mirror of https://github.com/xqemu/xqemu.git
arm support - suppressed possibly unsafe sparc nop deletion
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@225 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
9c5d1246c7
commit
ff1f20a3ee
214
dyngen.c
214
dyngen.c
|
@ -79,6 +79,13 @@
|
|||
#define elf_check_arch(x) ((x) == EM_SPARCV9)
|
||||
#define ELF_USES_RELOCA
|
||||
|
||||
#elif defined(HOST_ARM)
|
||||
|
||||
#define ELF_CLASS ELFCLASS32
|
||||
#define ELF_ARCH EM_ARM
|
||||
#define elf_check_arch(x) ((x) == EM_ARM)
|
||||
#define ELF_USES_RELOC
|
||||
|
||||
#else
|
||||
#error unsupported CPU - please update the code
|
||||
#endif
|
||||
|
@ -301,6 +308,106 @@ int strstart(const char *str, const char *val, const char **ptr)
|
|||
return 1;
|
||||
}
|
||||
|
||||
#ifdef HOST_ARM
|
||||
|
||||
int arm_emit_ldr_info(const char *name, unsigned long start_offset,
|
||||
FILE *outfile, uint8_t *p_start, uint8_t *p_end,
|
||||
ELF_RELOC *relocs, int nb_relocs)
|
||||
{
|
||||
uint8_t *p;
|
||||
uint32_t insn;
|
||||
int offset, min_offset, pc_offset, data_size;
|
||||
uint8_t data_allocated[1024];
|
||||
unsigned int data_index;
|
||||
|
||||
memset(data_allocated, 0, sizeof(data_allocated));
|
||||
|
||||
p = p_start;
|
||||
min_offset = p_end - p_start;
|
||||
while (p < p_start + min_offset) {
|
||||
insn = get32((uint32_t *)p);
|
||||
if ((insn & 0x0d5f0000) == 0x051f0000) {
|
||||
/* ldr reg, [pc, #im] */
|
||||
offset = insn & 0xfff;
|
||||
if (!(insn & 0x00800000))
|
||||
offset = -offset;
|
||||
if ((offset & 3) !=0)
|
||||
error("%s:%04x: ldr pc offset must be 32 bit aligned",
|
||||
name, start_offset + p - p_start);
|
||||
pc_offset = p - p_start + offset + 8;
|
||||
if (pc_offset <= (p - p_start) ||
|
||||
pc_offset >= (p_end - p_start))
|
||||
error("%s:%04x: ldr pc offset must point inside the function code",
|
||||
name, start_offset + p - p_start);
|
||||
if (pc_offset < min_offset)
|
||||
min_offset = pc_offset;
|
||||
if (outfile) {
|
||||
/* ldr position */
|
||||
fprintf(outfile, " arm_ldr_ptr->ptr = gen_code_ptr + %d;\n",
|
||||
p - p_start);
|
||||
/* ldr data index */
|
||||
data_index = ((p_end - p_start) - pc_offset - 4) >> 2;
|
||||
fprintf(outfile, " arm_ldr_ptr->data_ptr = arm_data_ptr + %d;\n",
|
||||
data_index);
|
||||
fprintf(outfile, " arm_ldr_ptr++;\n");
|
||||
if (data_index >= sizeof(data_allocated))
|
||||
error("%s: too many data", name);
|
||||
if (!data_allocated[data_index]) {
|
||||
ELF_RELOC *rel;
|
||||
int i, addend, type;
|
||||
const char *sym_name, *p;
|
||||
char relname[1024];
|
||||
|
||||
data_allocated[data_index] = 1;
|
||||
|
||||
/* data value */
|
||||
addend = get32((uint32_t *)(p_start + pc_offset));
|
||||
relname[0] = '\0';
|
||||
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
|
||||
if (rel->r_offset == (pc_offset + start_offset)) {
|
||||
sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
|
||||
/* the compiler leave some unnecessary references to the code */
|
||||
if (strstart(sym_name, "__op_param", &p)) {
|
||||
snprintf(relname, sizeof(relname), "param%s", p);
|
||||
} else {
|
||||
snprintf(relname, sizeof(relname), "(long)(&%s)", sym_name);
|
||||
}
|
||||
type = ELF32_R_TYPE(rel->r_info);
|
||||
if (type != R_ARM_ABS32)
|
||||
error("%s: unsupported data relocation", name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
fprintf(outfile, " arm_data_ptr[%d] = 0x%x",
|
||||
data_index, addend);
|
||||
if (relname[0] != '\0')
|
||||
fprintf(outfile, " + %s", relname);
|
||||
fprintf(outfile, ";\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
p += 4;
|
||||
}
|
||||
data_size = (p_end - p_start) - min_offset;
|
||||
if (data_size > 0 && outfile) {
|
||||
fprintf(outfile, " arm_data_ptr += %d;\n", data_size >> 2);
|
||||
}
|
||||
|
||||
/* the last instruction must be a mov pc, lr */
|
||||
if (p == p_start)
|
||||
goto arm_ret_error;
|
||||
p -= 4;
|
||||
insn = get32((uint32_t *)p);
|
||||
if ((insn & 0xffff0000) != 0xe91b0000) {
|
||||
arm_ret_error:
|
||||
if (!outfile)
|
||||
printf("%s: invalid epilog\n", name);
|
||||
}
|
||||
return p - p_start;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#define MAX_ARGS 3
|
||||
|
||||
/* generate op code */
|
||||
|
@ -388,7 +495,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
|||
case EM_SPARC:
|
||||
case EM_SPARC32PLUS:
|
||||
{
|
||||
uint32_t start_insn, end_insn1, end_insn2, skip_insn;
|
||||
uint32_t start_insn, end_insn1, end_insn2;
|
||||
uint8_t *p;
|
||||
p = (void *)(p_end - 8);
|
||||
if (p <= p_start)
|
||||
|
@ -406,14 +513,14 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
|||
} else {
|
||||
error("No save at the beginning of %s", name);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Skip a preceeding nop, if present. */
|
||||
if (p > p_start) {
|
||||
skip_insn = get32((uint32_t *)(p - 0x4));
|
||||
if (skip_insn == 0x01000000)
|
||||
p -= 4;
|
||||
}
|
||||
|
||||
#endif
|
||||
copy_size = p - p_start;
|
||||
}
|
||||
break;
|
||||
|
@ -448,6 +555,20 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
|||
copy_size = p - p_start;
|
||||
}
|
||||
break;
|
||||
#ifdef HOST_ARM
|
||||
case EM_ARM:
|
||||
if ((p_end - p_start) <= 16)
|
||||
error("%s: function too small", name);
|
||||
if (get32((uint32_t *)p_start) != 0xe1a0c00d ||
|
||||
(get32((uint32_t *)(p_start + 4)) & 0xffff0000) != 0xe92d0000 ||
|
||||
get32((uint32_t *)(p_start + 8)) != 0xe24cb004)
|
||||
error("%s: invalid prolog", name);
|
||||
p_start += 12;
|
||||
start_offset += 12;
|
||||
copy_size = arm_emit_ldr_info(name, start_offset, NULL, p_start, p_end,
|
||||
relocs, nb_relocs);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
error("unknown ELF architecture");
|
||||
}
|
||||
|
@ -458,7 +579,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
|||
|
||||
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
|
||||
if (rel->r_offset >= start_offset &&
|
||||
rel->r_offset < start_offset + copy_size) {
|
||||
rel->r_offset < start_offset + (p_end - p_start)) {
|
||||
sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
|
||||
if (strstart(sym_name, "__op_param", &p)) {
|
||||
n = strtoul(p, NULL, 10);
|
||||
|
@ -496,7 +617,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
|||
|
||||
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
|
||||
if (rel->r_offset >= start_offset &&
|
||||
rel->r_offset < start_offset + copy_size) {
|
||||
rel->r_offset < start_offset + (p_end - p_start)) {
|
||||
sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
|
||||
if (*sym_name &&
|
||||
!strstart(sym_name, "__op_param", NULL) &&
|
||||
|
@ -900,6 +1021,44 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
|||
}
|
||||
}
|
||||
}
|
||||
#elif defined(HOST_ARM)
|
||||
{
|
||||
char name[256];
|
||||
int type;
|
||||
int addend;
|
||||
|
||||
arm_emit_ldr_info(name, start_offset, outfile, p_start, p_end,
|
||||
relocs, nb_relocs);
|
||||
|
||||
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
|
||||
if (rel->r_offset >= start_offset &&
|
||||
rel->r_offset < start_offset + copy_size) {
|
||||
sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
|
||||
/* the compiler leave some unnecessary references to the code */
|
||||
if (sym_name[0] == '\0')
|
||||
continue;
|
||||
if (strstart(sym_name, "__op_param", &p)) {
|
||||
snprintf(name, sizeof(name), "param%s", p);
|
||||
} else {
|
||||
snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
|
||||
}
|
||||
type = ELF32_R_TYPE(rel->r_info);
|
||||
addend = get32((uint32_t *)(text + rel->r_offset));
|
||||
switch(type) {
|
||||
case R_ARM_ABS32:
|
||||
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
|
||||
rel->r_offset - start_offset, name, addend);
|
||||
break;
|
||||
case R_ARM_PC24:
|
||||
fprintf(outfile, " arm_reloc_pc24((uint32_t *)(gen_code_ptr + %d), 0x%x, %s);\n",
|
||||
rel->r_offset - start_offset, addend, name);
|
||||
break;
|
||||
default:
|
||||
error("unsupported arm relocation (%d)", type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
#error unsupported CPU
|
||||
#endif
|
||||
|
@ -1075,23 +1234,22 @@ fprintf(outfile,
|
|||
"{\n"
|
||||
" uint8_t *gen_code_ptr;\n"
|
||||
" const uint16_t *opc_ptr;\n"
|
||||
" const uint32_t *opparam_ptr;\n"
|
||||
" const uint32_t *opparam_ptr;\n");
|
||||
|
||||
#ifdef HOST_ARM
|
||||
fprintf(outfile,
|
||||
" uint8_t *last_gen_code_ptr = gen_code_buf;\n"
|
||||
" LDREntry *arm_ldr_ptr = arm_ldr_table;\n"
|
||||
" uint32_t *arm_data_ptr = arm_data_table;\n");
|
||||
#endif
|
||||
|
||||
fprintf(outfile,
|
||||
"\n"
|
||||
" gen_code_ptr = gen_code_buf;\n"
|
||||
" opc_ptr = opc_buf;\n"
|
||||
" opparam_ptr = opparam_buf;\n");
|
||||
|
||||
/* Generate prologue, if needed. */
|
||||
switch(ELF_ARCH) {
|
||||
case EM_SPARC:
|
||||
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x9c23a080; /* sub %%sp, 128, %%sp */\n");
|
||||
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0xbc27a080; /* sub %%fp, 128, %%fp */\n");
|
||||
break;
|
||||
|
||||
case EM_SPARCV9:
|
||||
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x9c23a100; /* sub %%sp, 256, %%sp */\n");
|
||||
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0xbc27a100; /* sub %%fp, 256, %%fp */\n");
|
||||
break;
|
||||
};
|
||||
|
||||
fprintf(outfile,
|
||||
" for(;;) {\n"
|
||||
|
@ -1116,7 +1274,21 @@ fprintf(outfile,
|
|||
fprintf(outfile,
|
||||
" default:\n"
|
||||
" goto the_end;\n"
|
||||
" }\n"
|
||||
" }\n");
|
||||
|
||||
#ifdef HOST_ARM
|
||||
/* generate constant table if needed */
|
||||
fprintf(outfile,
|
||||
" if ((gen_code_ptr - last_gen_code_ptr) >= (MAX_FRAG_SIZE - MAX_OP_SIZE)) {\n"
|
||||
" gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, arm_ldr_ptr, arm_data_table, arm_data_ptr, 1);\n"
|
||||
" last_gen_code_ptr = gen_code_ptr;\n"
|
||||
" arm_ldr_ptr = arm_ldr_table;\n"
|
||||
" arm_data_ptr = arm_data_table;\n"
|
||||
" }\n");
|
||||
#endif
|
||||
|
||||
|
||||
fprintf(outfile,
|
||||
" }\n"
|
||||
" the_end:\n"
|
||||
);
|
||||
|
@ -1140,14 +1312,16 @@ fprintf(outfile,
|
|||
break;
|
||||
case EM_SPARC:
|
||||
case EM_SPARC32PLUS:
|
||||
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0xbc07a080; /* add %%fp, 256, %%fp */\n");
|
||||
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x81c62008; /* jmpl %%i0 + 8, %%g0 */\n");
|
||||
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x9c03a080; /* add %%sp, 256, %%sp */\n");
|
||||
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x01000000; /* nop */\n");
|
||||
break;
|
||||
case EM_SPARCV9:
|
||||
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x81c7e008; /* ret */\n");
|
||||
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x81e80000; /* restore */\n");
|
||||
break;
|
||||
case EM_ARM:
|
||||
fprintf(outfile, "gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, arm_ldr_ptr, arm_data_table, arm_data_ptr, 0);\n");
|
||||
break;
|
||||
default:
|
||||
error("unknown ELF architecture");
|
||||
}
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* dyngen helpers
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifdef __alpha__
|
||||
|
||||
register int gp asm("$29");
|
||||
|
||||
static inline void immediate_ldah(void *p, int val) {
|
||||
uint32_t *dest = p;
|
||||
long high = ((val >> 16) + ((val >> 15) & 1)) & 0xffff;
|
||||
|
||||
*dest &= ~0xffff;
|
||||
*dest |= high;
|
||||
*dest |= 31 << 16;
|
||||
}
|
||||
static inline void immediate_lda(void *dest, int val) {
|
||||
*(uint16_t *) dest = val;
|
||||
}
|
||||
void fix_bsr(void *p, int offset) {
|
||||
uint32_t *dest = p;
|
||||
*dest &= ~((1 << 21) - 1);
|
||||
*dest |= (offset >> 2) & ((1 << 21) - 1);
|
||||
}
|
||||
|
||||
#endif /* __alpha__ */
|
||||
|
||||
#ifdef __arm__
|
||||
|
||||
#define MAX_OP_SIZE (128 * 4) /* in bytes */
|
||||
/* max size of the code that can be generated without calling arm_flush_ldr */
|
||||
#define MAX_FRAG_SIZE (1024 * 4)
|
||||
//#define MAX_FRAG_SIZE (135 * 4) /* for testing */
|
||||
|
||||
typedef struct LDREntry {
|
||||
uint8_t *ptr;
|
||||
uint32_t *data_ptr;
|
||||
} LDREntry;
|
||||
|
||||
static LDREntry arm_ldr_table[1024];
|
||||
static uint32_t arm_data_table[1024];
|
||||
|
||||
extern char exec_loop;
|
||||
|
||||
static inline void arm_reloc_pc24(uint32_t *ptr, uint32_t insn, int val)
|
||||
{
|
||||
*ptr = (insn & ~0xffffff) | ((insn + ((val - (int)ptr) >> 2)) & 0xffffff);
|
||||
}
|
||||
|
||||
static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr,
|
||||
LDREntry *ldr_start, LDREntry *ldr_end,
|
||||
uint32_t *data_start, uint32_t *data_end,
|
||||
int gen_jmp)
|
||||
{
|
||||
LDREntry *le;
|
||||
uint32_t *ptr;
|
||||
int offset, data_size, target;
|
||||
uint8_t *data_ptr;
|
||||
uint32_t insn;
|
||||
|
||||
data_size = (uint8_t *)data_end - (uint8_t *)data_start;
|
||||
|
||||
if (!gen_jmp) {
|
||||
/* b exec_loop */
|
||||
arm_reloc_pc24((uint32_t *)gen_code_ptr, 0xeafffffe, (long)(&exec_loop));
|
||||
gen_code_ptr += 4;
|
||||
} else {
|
||||
/* generate branch to skip the data */
|
||||
if (data_size == 0)
|
||||
return gen_code_ptr;
|
||||
target = (long)gen_code_ptr + data_size + 4;
|
||||
arm_reloc_pc24((uint32_t *)gen_code_ptr, 0xeafffffe, target);
|
||||
gen_code_ptr += 4;
|
||||
}
|
||||
|
||||
/* copy the data */
|
||||
data_ptr = gen_code_ptr;
|
||||
memcpy(gen_code_ptr, data_start, data_size);
|
||||
gen_code_ptr += data_size;
|
||||
|
||||
/* patch the ldr to point to the data */
|
||||
for(le = ldr_start; le < ldr_end; le++) {
|
||||
ptr = (uint32_t *)le->ptr;
|
||||
offset = ((unsigned long)(le->data_ptr) - (unsigned long)data_start) +
|
||||
(unsigned long)data_ptr -
|
||||
(unsigned long)ptr - 8;
|
||||
insn = *ptr & ~(0xfff | 0x00800000);
|
||||
if (offset < 0) {
|
||||
offset = - offset;
|
||||
} else {
|
||||
insn |= 0x00800000;
|
||||
}
|
||||
if (offset > 0xfff) {
|
||||
fprintf(stderr, "Error ldr offset\n");
|
||||
abort();
|
||||
}
|
||||
insn |= offset;
|
||||
*ptr = insn;
|
||||
}
|
||||
return gen_code_ptr;
|
||||
}
|
||||
|
||||
#endif /* __arm__ */
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue