mirror of https://gitee.com/openkylin/qemu.git
Alpha fixes (Falk Hueffner)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@157 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
366c1b8bfa
commit
74c95119f2
58
dyngen.c
58
dyngen.c
|
@ -429,7 +429,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||||
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
|
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
|
||||||
if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
|
if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
|
||||||
sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
|
sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
|
||||||
if (!strstart(sym_name, "__op_param", &p)) {
|
if (*sym_name && !strstart(sym_name, "__op_param", &p)) {
|
||||||
#if defined(HOST_SPARC)
|
#if defined(HOST_SPARC)
|
||||||
if (sym_name[0] == '.') {
|
if (sym_name[0] == '.') {
|
||||||
fprintf(outfile,
|
fprintf(outfile,
|
||||||
|
@ -561,15 +561,17 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||||
for (i = 0, rel = relocs; i < nb_relocs; i++, rel++) {
|
for (i = 0, rel = relocs; i < nb_relocs; i++, rel++) {
|
||||||
if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
|
if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
|
||||||
int type;
|
int type;
|
||||||
sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name;
|
|
||||||
|
|
||||||
type = ELF64_R_TYPE(rel->r_info);
|
type = ELF64_R_TYPE(rel->r_info);
|
||||||
|
sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case R_ALPHA_GPDISP:
|
case R_ALPHA_GPDISP:
|
||||||
/* Instructions to set up the gp can be nopped, since we keep it current
|
/* The gp is just 32 bit, and never changes, so it's easiest to emit it
|
||||||
all the time. FIXME assert that target is really gp */
|
as an immediate instead of constructing it from the pv or ra. */
|
||||||
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = 0x2ffe0000; /* unop */\n",
|
fprintf(outfile, " immediate_ldah(gen_code_ptr + %ld, gp);\n",
|
||||||
rel->r_offset - offset);
|
rel->r_offset - offset);
|
||||||
|
fprintf(outfile, " immediate_lda(gen_code_ptr + %ld, gp);\n",
|
||||||
|
rel->r_offset - offset + rel->r_addend);
|
||||||
break;
|
break;
|
||||||
case R_ALPHA_LITUSE:
|
case R_ALPHA_LITUSE:
|
||||||
/* jsr to literal hint. Could be used to optimize to bsr. Ignore for
|
/* jsr to literal hint. Could be used to optimize to bsr. Ignore for
|
||||||
|
@ -580,10 +582,27 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||||
correct for in-function jumps. */
|
correct for in-function jumps. */
|
||||||
break;
|
break;
|
||||||
case R_ALPHA_LITERAL:
|
case R_ALPHA_LITERAL:
|
||||||
/* Load a literal from the GOT relative to the gp. Need to patch the
|
/* Load a literal from the GOT relative to the gp. Since there's only a
|
||||||
16-bit immediate offset. */
|
single gp, nothing is to be done. */
|
||||||
fprintf(outfile, " *(int16_t *)(gen_code_ptr + %d) = gp - (long)(&%s);\n",
|
break;
|
||||||
rel->r_offset - offset, name);
|
case R_ALPHA_GPRELHIGH:
|
||||||
|
/* Handle fake relocations against __op_param symbol. Need to emit the
|
||||||
|
high part of the immediate value instead. Other symbols need no
|
||||||
|
special treatment. */
|
||||||
|
if (strstart(sym_name, "__op_param", &p))
|
||||||
|
fprintf(outfile, " immediate_ldah(gen_code_ptr + %ld, param%s);\n",
|
||||||
|
rel->r_offset - offset, p);
|
||||||
|
break;
|
||||||
|
case R_ALPHA_GPRELLOW:
|
||||||
|
if (strstart(sym_name, "__op_param", &p))
|
||||||
|
fprintf(outfile, " immediate_lda(gen_code_ptr + %ld, param%s);\n",
|
||||||
|
rel->r_offset - offset, p);
|
||||||
|
break;
|
||||||
|
case R_ALPHA_BRSGP:
|
||||||
|
/* PC-relative jump. Tweak offset to skip the two instructions that try to
|
||||||
|
set up the gp from the pv. */
|
||||||
|
fprintf(outfile, " fix_bsr(gen_code_ptr + %ld, (uint8_t *) &%s - (gen_code_ptr + %ld) + 4);\n",
|
||||||
|
rel->r_offset - offset, sym_name, rel->r_offset - offset);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
error("unsupported Alpha relocation (%d)", type);
|
error("unsupported Alpha relocation (%d)", type);
|
||||||
|
@ -886,7 +905,24 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum)
|
||||||
} else {
|
} else {
|
||||||
/* generate big code generation switch */
|
/* generate big code generation switch */
|
||||||
#ifdef HOST_ALPHA
|
#ifdef HOST_ALPHA
|
||||||
fprintf(outfile, "register long gp asm(\"%%$29\");\n");
|
fprintf(outfile,
|
||||||
|
"register int gp asm(\"$29\");\n"
|
||||||
|
"static inline void immediate_ldah(void *p, int val) {\n"
|
||||||
|
" uint32_t *dest = p;\n"
|
||||||
|
" long high = ((val >> 16) + ((val >> 15) & 1)) & 0xffff;\n"
|
||||||
|
"\n"
|
||||||
|
" *dest &= ~0xffff;\n"
|
||||||
|
" *dest |= high;\n"
|
||||||
|
" *dest |= 31 << 16;\n"
|
||||||
|
"}\n"
|
||||||
|
"static inline void immediate_lda(void *dest, int val) {\n"
|
||||||
|
" *(uint16_t *) dest = val;\n"
|
||||||
|
"}\n"
|
||||||
|
"void fix_bsr(void *p, int offset) {\n"
|
||||||
|
" uint32_t *dest = p;\n"
|
||||||
|
" *dest &= ~((1 << 21) - 1);\n"
|
||||||
|
" *dest |= (offset >> 2) & ((1 << 21) - 1);\n"
|
||||||
|
"}\n");
|
||||||
#endif
|
#endif
|
||||||
fprintf(outfile,
|
fprintf(outfile,
|
||||||
"int dyngen_code(uint8_t *gen_code_buf,\n"
|
"int dyngen_code(uint8_t *gen_code_buf,\n"
|
||||||
|
|
22
exec-i386.h
22
exec-i386.h
|
@ -105,7 +105,13 @@ register struct CPUX86State *env asm("r10");
|
||||||
register unsigned int T0 asm("$9");
|
register unsigned int T0 asm("$9");
|
||||||
register unsigned int T1 asm("$10");
|
register unsigned int T1 asm("$10");
|
||||||
register unsigned int A0 asm("$11");
|
register unsigned int A0 asm("$11");
|
||||||
register struct CPUX86State *env asm("$12");
|
register unsigned int EAX asm("$12");
|
||||||
|
register unsigned int ESP asm("$13");
|
||||||
|
register unsigned int EBP asm("$14");
|
||||||
|
register struct CPUX86State *env asm("$15");
|
||||||
|
#define reg_EAX
|
||||||
|
#define reg_ESP
|
||||||
|
#define reg_EBP
|
||||||
#endif
|
#endif
|
||||||
#ifdef __ia64__
|
#ifdef __ia64__
|
||||||
register unsigned int T0 asm("r24");
|
register unsigned int T0 asm("r24");
|
||||||
|
@ -165,10 +171,24 @@ register struct CPUX86State *env asm("r27");
|
||||||
#define FP_CONVERT (env->fp_convert)
|
#define FP_CONVERT (env->fp_convert)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __alpha__
|
||||||
|
/* Suggested by Richard Henderson. This will result in code like
|
||||||
|
ldah $0,__op_param1($29) !gprelhigh
|
||||||
|
lda $0,__op_param1($0) !gprellow
|
||||||
|
We can then conveniently change $29 to $31 and adapt the offsets to
|
||||||
|
emit the appropriate constant. */
|
||||||
|
extern int __op_param1 __attribute__((visibility("hidden")));
|
||||||
|
extern int __op_param2 __attribute__((visibility("hidden")));
|
||||||
|
extern int __op_param3 __attribute__((visibility("hidden")));
|
||||||
|
#define PARAM1 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param1)); _r; })
|
||||||
|
#define PARAM2 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param2)); _r; })
|
||||||
|
#define PARAM3 ({ int _r; asm("" : "=r"(_r) : "0" (&__op_param3)); _r; })
|
||||||
|
#else
|
||||||
extern int __op_param1, __op_param2, __op_param3;
|
extern int __op_param1, __op_param2, __op_param3;
|
||||||
#define PARAM1 ((long)(&__op_param1))
|
#define PARAM1 ((long)(&__op_param1))
|
||||||
#define PARAM2 ((long)(&__op_param2))
|
#define PARAM2 ((long)(&__op_param2))
|
||||||
#define PARAM3 ((long)(&__op_param3))
|
#define PARAM3 ((long)(&__op_param3))
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "cpu-i386.h"
|
#include "cpu-i386.h"
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue