diff options
Diffstat (limited to 'dyngen.c')
-rw-r--r-- | dyngen.c | 57 |
1 files changed, 51 insertions, 6 deletions
@@ -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); } |