aboutsummaryrefslogtreecommitdiff
path: root/dyngen.c
diff options
context:
space:
mode:
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2003-03-20 22:33:23 +0000
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2003-03-20 22:33:23 +0000
commit04369ff2f525ea510b6ddeaa2e3ed6aedde8bbb4 (patch)
tree05bb7aeca8770e3299d0817a466bfe80b28d3927 /dyngen.c
parent68decc7c7f438497fc8f8ef913054df6c1ab5ed6 (diff)
ppc port
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@36 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'dyngen.c')
-rw-r--r--dyngen.c57
1 files changed, 51 insertions, 6 deletions
diff --git a/dyngen.c b/dyngen.c
index 9b2889b67a..ed68610639 100644
--- a/dyngen.c
+++ b/dyngen.c
@@ -19,6 +19,7 @@
*/
#include <stdlib.h>
#include <stdio.h>
+#include <string.h>
#include <stdarg.h>
#include <inttypes.h>
#include <elf.h>
@@ -228,14 +229,10 @@ void gen_code(const char *name, unsigned long offset, unsigned long size,
{
uint8_t *p;
p = (void *)(p_end - 4);
- /* find ret */
- while (p > p_start && get32((uint32_t *)p) != 0x4e800020)
- p -= 4;
- /* skip double ret */
- if (p > p_start && get32((uint32_t *)(p - 4)) == 0x4e800020)
- p -= 4;
if (p == p_start)
error("empty code for %s", name);
+ if (get32((uint32_t *)p) != 0x4e800020)
+ error("blr expected at the end of %s", name);
copy_size = p - p_start;
}
break;
@@ -361,6 +358,51 @@ void gen_code(const char *name, unsigned long offset, unsigned long size,
}
}
break;
+ case EM_PPC:
+ {
+ Elf32_Rela *rel;
+ char name[256];
+ int type;
+ long addend;
+ for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
+ if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
+ sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
+ 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 = rel->r_addend;
+ switch(type) {
+ case R_PPC_ADDR32:
+ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %ld) = %s + %ld;\n",
+ rel->r_offset - offset, name, addend);
+ break;
+ case R_PPC_ADDR16_LO:
+ fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %ld) = (%s + %ld);\n",
+ rel->r_offset - offset, name, addend);
+ break;
+ case R_PPC_ADDR16_HI:
+ fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %ld) = (%s + %ld) >> 16;\n",
+ rel->r_offset - offset, name, addend);
+ break;
+ case R_PPC_ADDR16_HA:
+ fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %ld) = (%s + %ld + 0x8000) >> 16;\n",
+ rel->r_offset - offset, name, addend);
+ break;
+ case R_PPC_REL24:
+ /* warning: must be at 32 MB distancy */
+ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %ld) = (*(uint32_t *)(gen_code_ptr + %ld) & ~0x03fffffc) | ((%s - (long)(gen_code_ptr + %ld) + %ld) & 0x03fffffc);\n",
+ rel->r_offset - offset, rel->r_offset - offset, name, rel->r_offset - offset, addend);
+ break;
+ default:
+ error("unsupported powerpc relocation (%d)", type);
+ }
+ }
+ }
+ }
+ break;
default:
error("unsupported CPU for relocations (%d)", e_machine);
}
@@ -569,6 +611,9 @@ fprintf(outfile,
case EM_386:
fprintf(outfile, "*gen_code_ptr++ = 0xc3; /* ret */\n");
break;
+ case EM_PPC:
+ fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x4e800020; /* blr */\n");
+ break;
default:
error("no return generation for cpu '%s'", cpu_name);
}