Revision b8076a74 dyngen.h

b/dyngen.h
43 43
#ifdef __ia64__
44 44
static inline void flush_icache_range(unsigned long start, unsigned long stop)
45 45
{
46
    while (start < stop) {
47
	asm volatile ("fc %0" :: "r"(start));
48
	start += 32;
49
    }
50
    asm volatile (";;sync.i;;srlz.i;;");
46 51
}
47 52
#endif
48 53

  
......
204 209
}
205 210

  
206 211
#endif /* __arm__ */
212

  
213
#ifdef __ia64
214

  
215

  
216
/* Patch instruction with "val" where "mask" has 1 bits. */
217
static inline void ia64_patch (uint64_t insn_addr, uint64_t mask, uint64_t val)
218
{
219
    uint64_t m0, m1, v0, v1, b0, b1, *b = (uint64_t *) (insn_addr & -16);
220
#   define insn_mask ((1UL << 41) - 1)
221
    unsigned long shift;
222

  
223
    b0 = b[0]; b1 = b[1];
224
    shift = 5 + 41 * (insn_addr % 16); /* 5 template, 3 x 41-bit insns */
225
    if (shift >= 64) {
226
	m1 = mask << (shift - 64);
227
	v1 = val << (shift - 64);
228
    } else {
229
	m0 = mask << shift; m1 = mask >> (64 - shift);
230
	v0 = val  << shift; v1 = val >> (64 - shift);
231
	b[0] = (b0 & ~m0) | (v0 & m0);
232
    }
233
    b[1] = (b1 & ~m1) | (v1 & m1);
234
}
235

  
236
static inline void ia64_patch_imm60 (uint64_t insn_addr, uint64_t val)
237
{
238
	ia64_patch(insn_addr,
239
		   0x011ffffe000UL,
240
		   (  ((val & 0x0800000000000000UL) >> 23) /* bit 59 -> 36 */
241
		    | ((val & 0x00000000000fffffUL) << 13) /* bit 0 -> 13 */));
242
	ia64_patch(insn_addr - 1, 0x1fffffffffcUL, val >> 18);
243
}
244

  
245
static inline void ia64_imm64 (void *insn, uint64_t val)
246
{
247
    /* Ignore the slot number of the relocation; GCC and Intel
248
       toolchains differed for some time on whether IMM64 relocs are
249
       against slot 1 (Intel) or slot 2 (GCC).  */
250
    uint64_t insn_addr = (uint64_t) insn & ~3UL;
251

  
252
    ia64_patch(insn_addr + 2,
253
	       0x01fffefe000UL,
254
	       (  ((val & 0x8000000000000000UL) >> 27) /* bit 63 -> 36 */
255
		| ((val & 0x0000000000200000UL) <<  0) /* bit 21 -> 21 */
256
		| ((val & 0x00000000001f0000UL) <<  6) /* bit 16 -> 22 */
257
		| ((val & 0x000000000000ff80UL) << 20) /* bit  7 -> 27 */
258
		| ((val & 0x000000000000007fUL) << 13) /* bit  0 -> 13 */)
259
	    );
260
    ia64_patch(insn_addr + 1, 0x1ffffffffffUL, val >> 22);
261
}
262

  
263
static inline void ia64_imm60b (void *insn, uint64_t val)
264
{
265
    /* Ignore the slot number of the relocation; GCC and Intel
266
       toolchains differed for some time on whether IMM64 relocs are
267
       against slot 1 (Intel) or slot 2 (GCC).  */
268
    uint64_t insn_addr = (uint64_t) insn & ~3UL;
269

  
270
    if (val + ((uint64_t) 1 << 59) >= (1UL << 60))
271
	fprintf(stderr, "%s: value %ld out of IMM60 range\n",
272
		__FUNCTION__, (int64_t) val);
273
    ia64_patch_imm60(insn_addr + 2, val);
274
}
275

  
276
static inline void ia64_imm22 (void *insn, uint64_t val)
277
{
278
    if (val + (1 << 21) >= (1 << 22))
279
	fprintf(stderr, "%s: value %li out of IMM22 range\n",
280
		__FUNCTION__, (int64_t)val);
281
    ia64_patch((uint64_t) insn, 0x01fffcfe000UL,
282
	       (  ((val & 0x200000UL) << 15) /* bit 21 -> 36 */
283
		| ((val & 0x1f0000UL) <<  6) /* bit 16 -> 22 */
284
		| ((val & 0x00ff80UL) << 20) /* bit  7 -> 27 */
285
		| ((val & 0x00007fUL) << 13) /* bit  0 -> 13 */));
286
}
287

  
288
/* Like ia64_imm22(), but also clear bits 20-21.  For addl, this has
289
   the effect of turning "addl rX=imm22,rY" into "addl
290
   rX=imm22,r0".  */
291
static inline void ia64_imm22_r0 (void *insn, uint64_t val)
292
{
293
    if (val + (1 << 21) >= (1 << 22))
294
	fprintf(stderr, "%s: value %li out of IMM22 range\n",
295
		__FUNCTION__, (int64_t)val);
296
    ia64_patch((uint64_t) insn, 0x01fffcfe000UL | (0x3UL << 20),
297
	       (  ((val & 0x200000UL) << 15) /* bit 21 -> 36 */
298
		| ((val & 0x1f0000UL) <<  6) /* bit 16 -> 22 */
299
		| ((val & 0x00ff80UL) << 20) /* bit  7 -> 27 */
300
		| ((val & 0x00007fUL) << 13) /* bit  0 -> 13 */));
301
}
302

  
303
static inline void ia64_imm21b (void *insn, uint64_t val)
304
{
305
    if (val + (1 << 20) >= (1 << 21))
306
	fprintf(stderr, "%s: value %li out of IMM21b range\n",
307
		__FUNCTION__, (int64_t)val);
308
    ia64_patch((uint64_t) insn, 0x11ffffe000UL,
309
	       (  ((val & 0x100000UL) << 16) /* bit 20 -> 36 */
310
		| ((val & 0x0fffffUL) << 13) /* bit  0 -> 13 */));
311
}
312

  
313
static inline void ia64_nop_b (void *insn)
314
{
315
    ia64_patch((uint64_t) insn, (1UL << 41) - 1, 2UL << 37);
316
}
317

  
318
static inline void ia64_ldxmov(void *insn, uint64_t val)
319
{
320
    if (val + (1 << 21) < (1 << 22))
321
	ia64_patch((uint64_t) insn, 0x1fff80fe000UL, 8UL << 37);
322
}
323

  
324
static inline int ia64_patch_ltoff(void *insn, uint64_t val,
325
				   int relaxable)
326
{
327
    if (relaxable && (val + (1 << 21) < (1 << 22))) {
328
	ia64_imm22_r0(insn, val);
329
	return 0;
330
    }
331
    return 1;
332
}
333

  
334
struct ia64_fixup {
335
    struct ia64_fixup *next;
336
    void *addr;			/* address that needs to be patched */
337
    long value;
338
};
339

  
340
#define IA64_PLT(insn, plt_index)			\
341
do {							\
342
    struct ia64_fixup *fixup = alloca(sizeof(*fixup));	\
343
    fixup->next = plt_fixes;				\
344
    plt_fixes = fixup;					\
345
    fixup->addr = (insn);				\
346
    fixup->value = (plt_index);				\
347
    plt_offset[(plt_index)] = 1;			\
348
} while (0)
349

  
350
#define IA64_LTOFF(insn, val, relaxable)			\
351
do {								\
352
    if (ia64_patch_ltoff(insn, val, relaxable)) {		\
353
	struct ia64_fixup *fixup = alloca(sizeof(*fixup));	\
354
	fixup->next = ltoff_fixes;				\
355
	ltoff_fixes = fixup;					\
356
	fixup->addr = (insn);					\
357
	fixup->value = (val);					\
358
    }								\
359
} while (0)
360

  
361
static inline void ia64_apply_fixes (uint8_t **gen_code_pp,
362
				     struct ia64_fixup *ltoff_fixes,
363
				     uint64_t gp,
364
				     struct ia64_fixup *plt_fixes,
365
				     int num_plts,
366
				     unsigned long *plt_target,
367
				     unsigned int *plt_offset)
368
{
369
    static const uint8_t plt_bundle[] = {
370
	0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,	/* nop 0; movl r1=GP */
371
	0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x60,
372

  
373
	0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,	/* nop 0; brl IP */
374
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0
375
    };
376
    uint8_t *gen_code_ptr = *gen_code_pp, *plt_start, *got_start, *vp;
377
    struct ia64_fixup *fixup;
378
    unsigned int offset = 0;
379
    struct fdesc {
380
	long ip;
381
	long gp;
382
    } *fdesc;
383
    int i;
384

  
385
    if (plt_fixes) {
386
	plt_start = gen_code_ptr;
387

  
388
	for (i = 0; i < num_plts; ++i) {
389
	    if (plt_offset[i]) {
390
		plt_offset[i] = offset;
391
		offset += sizeof(plt_bundle);
392

  
393
		fdesc = (struct fdesc *) plt_target[i];
394
		memcpy(gen_code_ptr, plt_bundle, sizeof(plt_bundle));
395
		ia64_imm64 (gen_code_ptr + 0x02, fdesc->gp);
396
		ia64_imm60b(gen_code_ptr + 0x12,
397
			    (fdesc->ip - (long) (gen_code_ptr + 0x10)) >> 4);
398
		gen_code_ptr += sizeof(plt_bundle);
399
	    }
400
	}
401

  
402
	for (fixup = plt_fixes; fixup; fixup = fixup->next)
403
	    ia64_imm21b(fixup->addr,
404
			((long) plt_start + plt_offset[fixup->value]
405
			 - ((long) fixup->addr & ~0xf)) >> 4);
406
    }
407

  
408
    got_start = gen_code_ptr;
409

  
410
    /* First, create the GOT: */
411
    for (fixup = ltoff_fixes; fixup; fixup = fixup->next) {
412
	/* first check if we already have this value in the GOT: */
413
	for (vp = got_start; vp < gen_code_ptr; ++vp)
414
	    if (*(uint64_t *) vp == fixup->value)
415
		break;
416
	if (vp == gen_code_ptr) {
417
	    /* Nope, we need to put the value in the GOT: */
418
	    *(uint64_t *) vp = fixup->value;
419
	    gen_code_ptr += 8;
420
	}
421
	ia64_imm22(fixup->addr, (long) vp - gp);
422
    }
423
    *gen_code_pp = gen_code_ptr;
424
}
425

  
426
#endif

Also available in: Unified diff