root / tcg / tcg-dyngen.c @ c596defd
History | View | Annotate | Download (12.4 kB)
1 | c896fe29 | bellard | /*
|
---|---|---|---|
2 | c896fe29 | bellard | * Tiny Code Generator for QEMU
|
3 | c896fe29 | bellard | *
|
4 | c896fe29 | bellard | * Copyright (c) 2008 Fabrice Bellard
|
5 | c896fe29 | bellard | *
|
6 | c896fe29 | bellard | * Permission is hereby granted, free of charge, to any person obtaining a copy
|
7 | c896fe29 | bellard | * of this software and associated documentation files (the "Software"), to deal
|
8 | c896fe29 | bellard | * in the Software without restriction, including without limitation the rights
|
9 | c896fe29 | bellard | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10 | c896fe29 | bellard | * copies of the Software, and to permit persons to whom the Software is
|
11 | c896fe29 | bellard | * furnished to do so, subject to the following conditions:
|
12 | c896fe29 | bellard | *
|
13 | c896fe29 | bellard | * The above copyright notice and this permission notice shall be included in
|
14 | c896fe29 | bellard | * all copies or substantial portions of the Software.
|
15 | c896fe29 | bellard | *
|
16 | c896fe29 | bellard | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17 | c896fe29 | bellard | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18 | c896fe29 | bellard | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
19 | c896fe29 | bellard | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20 | c896fe29 | bellard | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21 | c896fe29 | bellard | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22 | c896fe29 | bellard | * THE SOFTWARE.
|
23 | c896fe29 | bellard | */
|
24 | c896fe29 | bellard | #include <assert.h> |
25 | c896fe29 | bellard | #include <stdarg.h> |
26 | c896fe29 | bellard | #include <stdlib.h> |
27 | c896fe29 | bellard | #include <stdio.h> |
28 | c896fe29 | bellard | #include <string.h> |
29 | c896fe29 | bellard | #include <inttypes.h> |
30 | c896fe29 | bellard | |
31 | c896fe29 | bellard | #include "config.h" |
32 | c896fe29 | bellard | #include "osdep.h" |
33 | c896fe29 | bellard | |
34 | c896fe29 | bellard | #include "tcg.h" |
35 | c896fe29 | bellard | |
36 | c896fe29 | bellard | int __op_param1, __op_param2, __op_param3;
|
37 | c896fe29 | bellard | #if defined(__sparc__) || defined(__arm__)
|
38 | c896fe29 | bellard | void __op_gen_label1(){}
|
39 | c896fe29 | bellard | void __op_gen_label2(){}
|
40 | c896fe29 | bellard | void __op_gen_label3(){}
|
41 | c896fe29 | bellard | #else
|
42 | c896fe29 | bellard | int __op_gen_label1, __op_gen_label2, __op_gen_label3;
|
43 | c896fe29 | bellard | #endif
|
44 | c896fe29 | bellard | int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3;
|
45 | c896fe29 | bellard | |
46 | c896fe29 | bellard | #if 0
|
47 | c896fe29 | bellard | #if defined(__s390__)
|
48 | c896fe29 | bellard | static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
49 | c896fe29 | bellard | {
|
50 | c896fe29 | bellard | }
|
51 | c896fe29 | bellard | #elif defined(__ia64__)
|
52 | c896fe29 | bellard | static inline void flush_icache_range(unsigned long start, unsigned long stop) |
53 | c896fe29 | bellard | { |
54 | c896fe29 | bellard | while (start < stop) {
|
55 | c896fe29 | bellard | asm volatile ("fc %0" :: "r"(start)); |
56 | c896fe29 | bellard | start += 32;
|
57 | c896fe29 | bellard | } |
58 | c896fe29 | bellard | asm volatile (";;sync.i;;srlz.i;;"); |
59 | c896fe29 | bellard | } |
60 | c896fe29 | bellard | #elif defined(__powerpc__)
|
61 | c896fe29 | bellard | |
62 | c896fe29 | bellard | #define MIN_CACHE_LINE_SIZE 8 /* conservative value */ |
63 | c896fe29 | bellard | |
64 | c896fe29 | bellard | static inline void flush_icache_range(unsigned long start, unsigned long stop) |
65 | c896fe29 | bellard | { |
66 | c896fe29 | bellard | unsigned long p; |
67 | c896fe29 | bellard | |
68 | c896fe29 | bellard | start &= ~(MIN_CACHE_LINE_SIZE - 1);
|
69 | c896fe29 | bellard | stop = (stop + MIN_CACHE_LINE_SIZE - 1) & ~(MIN_CACHE_LINE_SIZE - 1); |
70 | c896fe29 | bellard | |
71 | c896fe29 | bellard | for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
|
72 | c896fe29 | bellard | asm volatile ("dcbst 0,%0" : : "r"(p) : "memory"); |
73 | c896fe29 | bellard | } |
74 | c896fe29 | bellard | asm volatile ("sync" : : : "memory"); |
75 | c896fe29 | bellard | for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
|
76 | c896fe29 | bellard | asm volatile ("icbi 0,%0" : : "r"(p) : "memory"); |
77 | c896fe29 | bellard | } |
78 | c896fe29 | bellard | asm volatile ("sync" : : : "memory"); |
79 | c896fe29 | bellard | asm volatile ("isync" : : : "memory"); |
80 | c896fe29 | bellard | } |
81 | c896fe29 | bellard | #elif defined(__alpha__)
|
82 | c896fe29 | bellard | static inline void flush_icache_range(unsigned long start, unsigned long stop) |
83 | c896fe29 | bellard | { |
84 | c896fe29 | bellard | asm ("imb"); |
85 | c896fe29 | bellard | } |
86 | c896fe29 | bellard | #elif defined(__sparc__)
|
87 | c896fe29 | bellard | static inline void flush_icache_range(unsigned long start, unsigned long stop) |
88 | c896fe29 | bellard | { |
89 | c896fe29 | bellard | unsigned long p; |
90 | c896fe29 | bellard | |
91 | c896fe29 | bellard | p = start & ~(8UL - 1UL); |
92 | c896fe29 | bellard | stop = (stop + (8UL - 1UL)) & ~(8UL - 1UL); |
93 | c896fe29 | bellard | |
94 | c896fe29 | bellard | for (; p < stop; p += 8) |
95 | c896fe29 | bellard | __asm__ __volatile__("flush\t%0" : : "r" (p)); |
96 | c896fe29 | bellard | } |
97 | c896fe29 | bellard | #elif defined(__arm__)
|
98 | c896fe29 | bellard | static inline void flush_icache_range(unsigned long start, unsigned long stop) |
99 | c896fe29 | bellard | { |
100 | c896fe29 | bellard | register unsigned long _beg __asm ("a1") = start; |
101 | c896fe29 | bellard | register unsigned long _end __asm ("a2") = stop; |
102 | c896fe29 | bellard | register unsigned long _flg __asm ("a3") = 0; |
103 | c896fe29 | bellard | __asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg)); |
104 | c896fe29 | bellard | } |
105 | c896fe29 | bellard | #elif defined(__mc68000)
|
106 | c896fe29 | bellard | |
107 | c896fe29 | bellard | # include <asm/cachectl.h> |
108 | c896fe29 | bellard | static inline void flush_icache_range(unsigned long start, unsigned long stop) |
109 | c896fe29 | bellard | { |
110 | c896fe29 | bellard | cacheflush(start,FLUSH_SCOPE_LINE,FLUSH_CACHE_BOTH,stop-start+16);
|
111 | c896fe29 | bellard | } |
112 | c896fe29 | bellard | #elif defined(__mips__)
|
113 | c896fe29 | bellard | |
114 | c896fe29 | bellard | #include <sys/cachectl.h> |
115 | c896fe29 | bellard | static inline void flush_icache_range(unsigned long start, unsigned long stop) |
116 | c896fe29 | bellard | { |
117 | c896fe29 | bellard | _flush_cache ((void *)start, stop - start, BCACHE);
|
118 | c896fe29 | bellard | } |
119 | c896fe29 | bellard | #else
|
120 | c896fe29 | bellard | #error unsupported CPU
|
121 | c896fe29 | bellard | #endif
|
122 | c896fe29 | bellard | |
123 | c896fe29 | bellard | #ifdef __alpha__
|
124 | c896fe29 | bellard | |
125 | c896fe29 | bellard | register int gp asm("$29"); |
126 | c896fe29 | bellard | |
127 | c896fe29 | bellard | static inline void immediate_ldah(void *p, int val) { |
128 | c896fe29 | bellard | uint32_t *dest = p; |
129 | c896fe29 | bellard | long high = ((val >> 16) + ((val >> 15) & 1)) & 0xffff; |
130 | c896fe29 | bellard | |
131 | c896fe29 | bellard | *dest &= ~0xffff;
|
132 | c896fe29 | bellard | *dest |= high; |
133 | c896fe29 | bellard | *dest |= 31 << 16; |
134 | c896fe29 | bellard | } |
135 | c896fe29 | bellard | static inline void immediate_lda(void *dest, int val) { |
136 | c896fe29 | bellard | *(uint16_t *) dest = val; |
137 | c896fe29 | bellard | } |
138 | c896fe29 | bellard | void fix_bsr(void *p, int offset) { |
139 | c896fe29 | bellard | uint32_t *dest = p; |
140 | c896fe29 | bellard | *dest &= ~((1 << 21) - 1); |
141 | c896fe29 | bellard | *dest |= (offset >> 2) & ((1 << 21) - 1); |
142 | c896fe29 | bellard | } |
143 | c896fe29 | bellard | |
144 | c896fe29 | bellard | #endif /* __alpha__ */ |
145 | c896fe29 | bellard | |
146 | c896fe29 | bellard | #ifdef __ia64
|
147 | c896fe29 | bellard | |
148 | c896fe29 | bellard | /* Patch instruction with "val" where "mask" has 1 bits. */
|
149 | c896fe29 | bellard | static inline void ia64_patch (uint64_t insn_addr, uint64_t mask, uint64_t val) |
150 | c896fe29 | bellard | { |
151 | c896fe29 | bellard | uint64_t m0, m1, v0, v1, b0, b1, *b = (uint64_t *) (insn_addr & -16);
|
152 | c896fe29 | bellard | # define insn_mask ((1UL << 41) - 1) |
153 | c896fe29 | bellard | unsigned long shift; |
154 | c896fe29 | bellard | |
155 | c896fe29 | bellard | b0 = b[0]; b1 = b[1]; |
156 | c896fe29 | bellard | shift = 5 + 41 * (insn_addr % 16); /* 5 template, 3 x 41-bit insns */ |
157 | c896fe29 | bellard | if (shift >= 64) { |
158 | c896fe29 | bellard | m1 = mask << (shift - 64);
|
159 | c896fe29 | bellard | v1 = val << (shift - 64);
|
160 | c896fe29 | bellard | } else {
|
161 | c896fe29 | bellard | m0 = mask << shift; m1 = mask >> (64 - shift);
|
162 | c896fe29 | bellard | v0 = val << shift; v1 = val >> (64 - shift);
|
163 | c896fe29 | bellard | b[0] = (b0 & ~m0) | (v0 & m0);
|
164 | c896fe29 | bellard | } |
165 | c896fe29 | bellard | b[1] = (b1 & ~m1) | (v1 & m1);
|
166 | c896fe29 | bellard | } |
167 | c896fe29 | bellard | |
168 | c896fe29 | bellard | static inline void ia64_patch_imm60 (uint64_t insn_addr, uint64_t val) |
169 | c896fe29 | bellard | { |
170 | c896fe29 | bellard | ia64_patch(insn_addr, |
171 | c896fe29 | bellard | 0x011ffffe000UL,
|
172 | c896fe29 | bellard | ( ((val & 0x0800000000000000UL) >> 23) /* bit 59 -> 36 */ |
173 | c896fe29 | bellard | | ((val & 0x00000000000fffffUL) << 13) /* bit 0 -> 13 */)); |
174 | c896fe29 | bellard | ia64_patch(insn_addr - 1, 0x1fffffffffcUL, val >> 18); |
175 | c896fe29 | bellard | } |
176 | c896fe29 | bellard | |
177 | c896fe29 | bellard | static inline void ia64_imm64 (void *insn, uint64_t val) |
178 | c896fe29 | bellard | { |
179 | c896fe29 | bellard | /* Ignore the slot number of the relocation; GCC and Intel
|
180 | c896fe29 | bellard | toolchains differed for some time on whether IMM64 relocs are
|
181 | c896fe29 | bellard | against slot 1 (Intel) or slot 2 (GCC). */
|
182 | c896fe29 | bellard | uint64_t insn_addr = (uint64_t) insn & ~3UL;
|
183 | c896fe29 | bellard | |
184 | c896fe29 | bellard | ia64_patch(insn_addr + 2,
|
185 | c896fe29 | bellard | 0x01fffefe000UL,
|
186 | c896fe29 | bellard | ( ((val & 0x8000000000000000UL) >> 27) /* bit 63 -> 36 */ |
187 | c896fe29 | bellard | | ((val & 0x0000000000200000UL) << 0) /* bit 21 -> 21 */ |
188 | c896fe29 | bellard | | ((val & 0x00000000001f0000UL) << 6) /* bit 16 -> 22 */ |
189 | c896fe29 | bellard | | ((val & 0x000000000000ff80UL) << 20) /* bit 7 -> 27 */ |
190 | c896fe29 | bellard | | ((val & 0x000000000000007fUL) << 13) /* bit 0 -> 13 */) |
191 | c896fe29 | bellard | ); |
192 | c896fe29 | bellard | ia64_patch(insn_addr + 1, 0x1ffffffffffUL, val >> 22); |
193 | c896fe29 | bellard | } |
194 | c896fe29 | bellard | |
195 | c896fe29 | bellard | static inline void ia64_imm60b (void *insn, uint64_t val) |
196 | c896fe29 | bellard | { |
197 | c896fe29 | bellard | /* Ignore the slot number of the relocation; GCC and Intel
|
198 | c896fe29 | bellard | toolchains differed for some time on whether IMM64 relocs are
|
199 | c896fe29 | bellard | against slot 1 (Intel) or slot 2 (GCC). */
|
200 | c896fe29 | bellard | uint64_t insn_addr = (uint64_t) insn & ~3UL;
|
201 | c896fe29 | bellard | |
202 | c896fe29 | bellard | if (val + ((uint64_t) 1 << 59) >= (1UL << 60)) |
203 | c896fe29 | bellard | fprintf(stderr, "%s: value %ld out of IMM60 range\n",
|
204 | c896fe29 | bellard | __FUNCTION__, (int64_t) val); |
205 | c896fe29 | bellard | ia64_patch_imm60(insn_addr + 2, val);
|
206 | c896fe29 | bellard | } |
207 | c896fe29 | bellard | |
208 | c896fe29 | bellard | static inline void ia64_imm22 (void *insn, uint64_t val) |
209 | c896fe29 | bellard | { |
210 | c896fe29 | bellard | if (val + (1 << 21) >= (1 << 22)) |
211 | c896fe29 | bellard | fprintf(stderr, "%s: value %li out of IMM22 range\n",
|
212 | c896fe29 | bellard | __FUNCTION__, (int64_t)val); |
213 | c896fe29 | bellard | ia64_patch((uint64_t) insn, 0x01fffcfe000UL,
|
214 | c896fe29 | bellard | ( ((val & 0x200000UL) << 15) /* bit 21 -> 36 */ |
215 | c896fe29 | bellard | | ((val & 0x1f0000UL) << 6) /* bit 16 -> 22 */ |
216 | c896fe29 | bellard | | ((val & 0x00ff80UL) << 20) /* bit 7 -> 27 */ |
217 | c896fe29 | bellard | | ((val & 0x00007fUL) << 13) /* bit 0 -> 13 */)); |
218 | c896fe29 | bellard | } |
219 | c896fe29 | bellard | |
220 | c896fe29 | bellard | /* Like ia64_imm22(), but also clear bits 20-21. For addl, this has
|
221 | c896fe29 | bellard | the effect of turning "addl rX=imm22,rY" into "addl
|
222 | c896fe29 | bellard | rX=imm22,r0". */
|
223 | c896fe29 | bellard | static inline void ia64_imm22_r0 (void *insn, uint64_t val) |
224 | c896fe29 | bellard | { |
225 | c896fe29 | bellard | if (val + (1 << 21) >= (1 << 22)) |
226 | c896fe29 | bellard | fprintf(stderr, "%s: value %li out of IMM22 range\n",
|
227 | c896fe29 | bellard | __FUNCTION__, (int64_t)val); |
228 | c896fe29 | bellard | ia64_patch((uint64_t) insn, 0x01fffcfe000UL | (0x3UL << 20), |
229 | c896fe29 | bellard | ( ((val & 0x200000UL) << 15) /* bit 21 -> 36 */ |
230 | c896fe29 | bellard | | ((val & 0x1f0000UL) << 6) /* bit 16 -> 22 */ |
231 | c896fe29 | bellard | | ((val & 0x00ff80UL) << 20) /* bit 7 -> 27 */ |
232 | c896fe29 | bellard | | ((val & 0x00007fUL) << 13) /* bit 0 -> 13 */)); |
233 | c896fe29 | bellard | } |
234 | c896fe29 | bellard | |
235 | c896fe29 | bellard | static inline void ia64_imm21b (void *insn, uint64_t val) |
236 | c896fe29 | bellard | { |
237 | c896fe29 | bellard | if (val + (1 << 20) >= (1 << 21)) |
238 | c896fe29 | bellard | fprintf(stderr, "%s: value %li out of IMM21b range\n",
|
239 | c896fe29 | bellard | __FUNCTION__, (int64_t)val); |
240 | c896fe29 | bellard | ia64_patch((uint64_t) insn, 0x11ffffe000UL,
|
241 | c896fe29 | bellard | ( ((val & 0x100000UL) << 16) /* bit 20 -> 36 */ |
242 | c896fe29 | bellard | | ((val & 0x0fffffUL) << 13) /* bit 0 -> 13 */)); |
243 | c896fe29 | bellard | } |
244 | c896fe29 | bellard | |
245 | c896fe29 | bellard | static inline void ia64_nop_b (void *insn) |
246 | c896fe29 | bellard | { |
247 | c896fe29 | bellard | ia64_patch((uint64_t) insn, (1UL << 41) - 1, 2UL << 37); |
248 | c896fe29 | bellard | } |
249 | c896fe29 | bellard | |
250 | c896fe29 | bellard | static inline void ia64_ldxmov(void *insn, uint64_t val) |
251 | c896fe29 | bellard | { |
252 | c896fe29 | bellard | if (val + (1 << 21) < (1 << 22)) |
253 | c896fe29 | bellard | ia64_patch((uint64_t) insn, 0x1fff80fe000UL, 8UL << 37); |
254 | c896fe29 | bellard | } |
255 | c896fe29 | bellard | |
256 | c896fe29 | bellard | static inline int ia64_patch_ltoff(void *insn, uint64_t val, |
257 | c896fe29 | bellard | int relaxable)
|
258 | c896fe29 | bellard | { |
259 | c896fe29 | bellard | if (relaxable && (val + (1 << 21) < (1 << 22))) { |
260 | c896fe29 | bellard | ia64_imm22_r0(insn, val); |
261 | c896fe29 | bellard | return 0; |
262 | c896fe29 | bellard | } |
263 | c896fe29 | bellard | return 1; |
264 | c896fe29 | bellard | } |
265 | c896fe29 | bellard | |
266 | c896fe29 | bellard | struct ia64_fixup {
|
267 | c896fe29 | bellard | struct ia64_fixup *next;
|
268 | c896fe29 | bellard | void *addr; /* address that needs to be patched */ |
269 | c896fe29 | bellard | long value;
|
270 | c896fe29 | bellard | }; |
271 | c896fe29 | bellard | |
272 | c896fe29 | bellard | #define IA64_PLT(insn, plt_index) \
|
273 | c896fe29 | bellard | do { \
|
274 | c896fe29 | bellard | struct ia64_fixup *fixup = alloca(sizeof(*fixup)); \ |
275 | c896fe29 | bellard | fixup->next = plt_fixes; \ |
276 | c896fe29 | bellard | plt_fixes = fixup; \ |
277 | c896fe29 | bellard | fixup->addr = (insn); \ |
278 | c896fe29 | bellard | fixup->value = (plt_index); \ |
279 | c896fe29 | bellard | plt_offset[(plt_index)] = 1; \
|
280 | c896fe29 | bellard | } while (0) |
281 | c896fe29 | bellard | |
282 | c896fe29 | bellard | #define IA64_LTOFF(insn, val, relaxable) \
|
283 | c896fe29 | bellard | do { \
|
284 | c896fe29 | bellard | if (ia64_patch_ltoff(insn, val, relaxable)) { \
|
285 | c896fe29 | bellard | struct ia64_fixup *fixup = alloca(sizeof(*fixup)); \ |
286 | c896fe29 | bellard | fixup->next = ltoff_fixes; \ |
287 | c896fe29 | bellard | ltoff_fixes = fixup; \ |
288 | c896fe29 | bellard | fixup->addr = (insn); \ |
289 | c896fe29 | bellard | fixup->value = (val); \ |
290 | c896fe29 | bellard | } \ |
291 | c896fe29 | bellard | } while (0) |
292 | c896fe29 | bellard | |
293 | c896fe29 | bellard | static inline void ia64_apply_fixes (uint8_t **gen_code_pp, |
294 | c896fe29 | bellard | struct ia64_fixup *ltoff_fixes,
|
295 | c896fe29 | bellard | uint64_t gp, |
296 | c896fe29 | bellard | struct ia64_fixup *plt_fixes,
|
297 | c896fe29 | bellard | int num_plts,
|
298 | c896fe29 | bellard | unsigned long *plt_target, |
299 | c896fe29 | bellard | unsigned int *plt_offset) |
300 | c896fe29 | bellard | { |
301 | c896fe29 | bellard | static const uint8_t plt_bundle[] = { |
302 | c896fe29 | bellard | 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, /* nop 0; movl r1=GP */ |
303 | c896fe29 | bellard | 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x60, |
304 | c896fe29 | bellard | |
305 | c896fe29 | bellard | 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, /* nop 0; brl IP */ |
306 | c896fe29 | bellard | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0 |
307 | c896fe29 | bellard | }; |
308 | c896fe29 | bellard | uint8_t *gen_code_ptr = *gen_code_pp, *plt_start, *got_start; |
309 | c896fe29 | bellard | uint64_t *vp; |
310 | c896fe29 | bellard | struct ia64_fixup *fixup;
|
311 | c896fe29 | bellard | unsigned int offset = 0; |
312 | c896fe29 | bellard | struct fdesc {
|
313 | c896fe29 | bellard | long ip;
|
314 | c896fe29 | bellard | long gp;
|
315 | c896fe29 | bellard | } *fdesc; |
316 | c896fe29 | bellard | int i;
|
317 | c896fe29 | bellard | |
318 | c896fe29 | bellard | if (plt_fixes) {
|
319 | c896fe29 | bellard | plt_start = gen_code_ptr; |
320 | c896fe29 | bellard | |
321 | c896fe29 | bellard | for (i = 0; i < num_plts; ++i) { |
322 | c896fe29 | bellard | if (plt_offset[i]) {
|
323 | c896fe29 | bellard | plt_offset[i] = offset; |
324 | c896fe29 | bellard | offset += sizeof(plt_bundle);
|
325 | c896fe29 | bellard | |
326 | c896fe29 | bellard | fdesc = (struct fdesc *) plt_target[i];
|
327 | c896fe29 | bellard | memcpy(gen_code_ptr, plt_bundle, sizeof(plt_bundle));
|
328 | c896fe29 | bellard | ia64_imm64 (gen_code_ptr + 0x02, fdesc->gp);
|
329 | c896fe29 | bellard | ia64_imm60b(gen_code_ptr + 0x12,
|
330 | c896fe29 | bellard | (fdesc->ip - (long) (gen_code_ptr + 0x10)) >> 4); |
331 | c896fe29 | bellard | gen_code_ptr += sizeof(plt_bundle);
|
332 | c896fe29 | bellard | } |
333 | c896fe29 | bellard | } |
334 | c896fe29 | bellard | |
335 | c896fe29 | bellard | for (fixup = plt_fixes; fixup; fixup = fixup->next)
|
336 | c896fe29 | bellard | ia64_imm21b(fixup->addr, |
337 | c896fe29 | bellard | ((long) plt_start + plt_offset[fixup->value]
|
338 | c896fe29 | bellard | - ((long) fixup->addr & ~0xf)) >> 4); |
339 | c896fe29 | bellard | } |
340 | c896fe29 | bellard | |
341 | c896fe29 | bellard | got_start = gen_code_ptr; |
342 | c896fe29 | bellard | |
343 | c896fe29 | bellard | /* First, create the GOT: */
|
344 | c896fe29 | bellard | for (fixup = ltoff_fixes; fixup; fixup = fixup->next) {
|
345 | c896fe29 | bellard | /* first check if we already have this value in the GOT: */
|
346 | c896fe29 | bellard | for (vp = (uint64_t *) got_start; vp < (uint64_t *) gen_code_ptr; ++vp)
|
347 | c896fe29 | bellard | if (*vp == fixup->value)
|
348 | c896fe29 | bellard | break;
|
349 | c896fe29 | bellard | if (vp == (uint64_t *) gen_code_ptr) {
|
350 | c896fe29 | bellard | /* Nope, we need to put the value in the GOT: */
|
351 | c896fe29 | bellard | *vp = fixup->value; |
352 | c896fe29 | bellard | gen_code_ptr += 8;
|
353 | c896fe29 | bellard | } |
354 | c896fe29 | bellard | ia64_imm22(fixup->addr, (long) vp - gp);
|
355 | c896fe29 | bellard | } |
356 | c896fe29 | bellard | /* Keep code ptr aligned. */
|
357 | c896fe29 | bellard | if ((long) gen_code_ptr & 15) |
358 | c896fe29 | bellard | gen_code_ptr += 8;
|
359 | c896fe29 | bellard | *gen_code_pp = gen_code_ptr; |
360 | c896fe29 | bellard | } |
361 | c896fe29 | bellard | #endif
|
362 | c896fe29 | bellard | #endif
|
363 | c896fe29 | bellard | |
364 | bf6247fb | blueswir1 | #ifdef CONFIG_DYNGEN_OP
|
365 | f54b3f92 | aurel32 | |
366 | f54b3f92 | aurel32 | #if defined __hppa__
|
367 | f54b3f92 | aurel32 | struct hppa_branch_stub {
|
368 | f54b3f92 | aurel32 | uint32_t *location; |
369 | f54b3f92 | aurel32 | long target;
|
370 | f54b3f92 | aurel32 | struct hppa_branch_stub *next;
|
371 | f54b3f92 | aurel32 | }; |
372 | f54b3f92 | aurel32 | |
373 | f54b3f92 | aurel32 | #define HPPA_RECORD_BRANCH(LIST, LOC, TARGET) \
|
374 | f54b3f92 | aurel32 | do { \
|
375 | f54b3f92 | aurel32 | struct hppa_branch_stub *stub = alloca(sizeof(struct hppa_branch_stub)); \ |
376 | f54b3f92 | aurel32 | stub->location = LOC; \ |
377 | f54b3f92 | aurel32 | stub->target = TARGET; \ |
378 | f54b3f92 | aurel32 | stub->next = LIST; \ |
379 | f54b3f92 | aurel32 | LIST = stub; \ |
380 | f54b3f92 | aurel32 | } while (0) |
381 | f54b3f92 | aurel32 | |
382 | f54b3f92 | aurel32 | static inline void hppa_process_stubs(struct hppa_branch_stub *stub, |
383 | f54b3f92 | aurel32 | uint8_t **gen_code_pp) |
384 | f54b3f92 | aurel32 | { |
385 | f54b3f92 | aurel32 | uint32_t *s = (uint32_t *)*gen_code_pp; |
386 | f54b3f92 | aurel32 | uint32_t *p = s + 1;
|
387 | f54b3f92 | aurel32 | |
388 | f54b3f92 | aurel32 | if (!stub) return; |
389 | f54b3f92 | aurel32 | |
390 | f54b3f92 | aurel32 | for (; stub != NULL; stub = stub->next) { |
391 | f54b3f92 | aurel32 | unsigned long l = (unsigned long)p; |
392 | f54b3f92 | aurel32 | /* stub:
|
393 | f54b3f92 | aurel32 | * ldil L'target, %r1
|
394 | f54b3f92 | aurel32 | * be,n R'target(%sr4,%r1)
|
395 | f54b3f92 | aurel32 | */
|
396 | f54b3f92 | aurel32 | *p++ = 0x20200000 | reassemble_21(lrsel(stub->target, 0)); |
397 | f54b3f92 | aurel32 | *p++ = 0xe0202002 | (reassemble_17(rrsel(stub->target, 0) >> 2)); |
398 | f54b3f92 | aurel32 | hppa_patch17f(stub->location, l, 0);
|
399 | f54b3f92 | aurel32 | } |
400 | f54b3f92 | aurel32 | /* b,l,n stub,%r0 */
|
401 | f54b3f92 | aurel32 | *s = 0xe8000002 | reassemble_17((p - s) - 2); |
402 | f54b3f92 | aurel32 | *gen_code_pp = (uint8_t *)p; |
403 | f54b3f92 | aurel32 | } |
404 | f54b3f92 | aurel32 | #endif /* __hppa__ */ |
405 | f54b3f92 | aurel32 | |
406 | c896fe29 | bellard | const TCGArg *dyngen_op(TCGContext *s, int opc, const TCGArg *opparam_ptr) |
407 | c896fe29 | bellard | { |
408 | c896fe29 | bellard | uint8_t *gen_code_ptr; |
409 | c896fe29 | bellard | |
410 | f54b3f92 | aurel32 | #ifdef __hppa__
|
411 | f54b3f92 | aurel32 | struct hppa_branch_stub *hppa_stubs = NULL; |
412 | f54b3f92 | aurel32 | #endif
|
413 | f54b3f92 | aurel32 | |
414 | c896fe29 | bellard | gen_code_ptr = s->code_ptr; |
415 | c896fe29 | bellard | switch(opc) {
|
416 | c896fe29 | bellard | |
417 | c896fe29 | bellard | /* op.h is dynamically generated by dyngen.c from op.c */
|
418 | c896fe29 | bellard | #include "op.h" |
419 | c896fe29 | bellard | |
420 | c896fe29 | bellard | default:
|
421 | c896fe29 | bellard | tcg_abort(); |
422 | c896fe29 | bellard | } |
423 | f54b3f92 | aurel32 | |
424 | f54b3f92 | aurel32 | #ifdef __hppa__
|
425 | f54b3f92 | aurel32 | hppa_process_stubs(hppa_stubs, &gen_code_ptr); |
426 | f54b3f92 | aurel32 | #endif
|
427 | f54b3f92 | aurel32 | |
428 | c896fe29 | bellard | s->code_ptr = gen_code_ptr; |
429 | c896fe29 | bellard | return opparam_ptr;
|
430 | c896fe29 | bellard | } |
431 | cf2be984 | blueswir1 | #endif |