HPPA (PA-RISC) host support
[qemu] / dyngen.c
index 562fd0d..e4ea3b1 100644 (file)
--- a/dyngen.c
+++ b/dyngen.c
 #define elf_check_arch(x) ((x) == EM_68K)
 #define ELF_USES_RELOCA
 
+#elif defined(HOST_HPPA)
+
+#define ELF_CLASS   ELFCLASS32
+#define ELF_ARCH    EM_PARISC
+#define elf_check_arch(x) ((x) == EM_PARISC)
+#define ELF_USES_RELOCA
+
 #elif defined(HOST_MIPS)
 
 #define ELF_CLASS      ELFCLASS32
@@ -232,7 +239,7 @@ enum {
 
 int do_swap;
 
-void __attribute__((noreturn)) __attribute__((format (printf, 1, 2))) error(const char *fmt, ...)
+static void __attribute__((noreturn)) __attribute__((format (printf, 1, 2))) error(const char *fmt, ...)
 {
     va_list ap;
     va_start(ap, fmt);
@@ -243,7 +250,7 @@ void __attribute__((noreturn)) __attribute__((format (printf, 1, 2))) error(cons
     exit(1);
 }
 
-void *load_data(int fd, long offset, unsigned int size)
+static void *load_data(int fd, long offset, unsigned int size)
 {
     char *data;
 
@@ -1212,16 +1219,18 @@ int load_object(const char *filename)
 
 #endif /* CONFIG_FORMAT_MACH */
 
-void get_reloc_expr(char *name, int name_size, const char *sym_name)
+/* return true if the expression is a label reference */
+int get_reloc_expr(char *name, int name_size, const char *sym_name)
 {
     const char *p;
 
     if (strstart(sym_name, "__op_param", &p)) {
         snprintf(name, name_size, "param%s", p);
     } else if (strstart(sym_name, "__op_gen_label", &p)) {
-        snprintf(name, name_size, "gen_labels[param%s]", p);
+        snprintf(name, name_size, "param%s", p);
+        return 1;
     } else {
-#ifdef HOST_SPARC
+#if defined(HOST_SPARC) || defined(HOST_HPPA)
         if (sym_name[0] == '.')
             snprintf(name, name_size,
                      "(long)(&__dot_%s)",
@@ -1230,6 +1239,7 @@ void get_reloc_expr(char *name, int name_size, const char *sym_name)
 #endif
             snprintf(name, name_size, "(long)(&%s)", sym_name);
     }
+    return 0;
 }
 
 #ifdef HOST_IA64
@@ -1495,8 +1505,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
         p = (void *)(p_end - 2);
         if (p == p_start)
             error("empty code for %s", name);
-        if (get16((uint16_t *)p) != 0x07fe && get16((uint16_t *)p) != 0x07f4)
-            error("br %%r14 expected at the end of %s", name);
+        if ((get16((uint16_t *)p) & 0xfff0) != 0x07f0)
+            error("br expected at the end of %s", name);
         copy_size = p - p_start;
     }
 #elif defined(HOST_ALPHA)
@@ -1612,12 +1622,14 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
             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;
     }
@@ -1656,6 +1668,43 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
             error("rts expected at the end of %s", name);
         copy_size = p - p_start;
     }
+#elif defined(HOST_HPPA)
+    {
+        uint8_t *p;
+        p = p_start;
+        while (p < p_end) {
+            uint32_t insn = get32((uint32_t *)p);
+            if (insn == 0x6bc23fd9 ||                /* stw rp,-14(sp) */
+                insn == 0x08030241 ||                /* copy r3,r1 */
+                insn == 0x081e0243 ||                /* copy sp,r3 */
+                (insn & 0xffffc000) == 0x37de0000 || /* ldo x(sp),sp */
+                (insn & 0xffffc000) == 0x6fc10000)   /* stwm r1,x(sp) */
+                p += 4;
+            else
+                break;
+        }
+        start_offset += p - p_start;
+        p_start = p;
+        p = p_end - 4;
+
+        while (p > p_start) {
+            uint32_t insn = get32((uint32_t *)p);
+            if ((insn & 0xffffc000) == 0x347e0000 || /* ldo x(r3),sp */
+                (insn & 0xffe0c000) == 0x4fc00000 || /* ldwm x(sp),rx */
+                (insn & 0xffffc000) == 0x37de0000 || /* ldo x(sp),sp */
+                insn == 0x48623fd9 ||                /* ldw -14(r3),rp */
+                insn == 0xe840c000 ||                /* bv r0(rp) */
+                insn == 0xe840c002)                  /* bv,n r0(rp) */
+                p -= 4;
+            else
+                break;
+        }
+        p += 4;
+        if (p <= p_start)
+            error("empty code for %s", name);
+
+        copy_size = p - p_start;
+    }
 #elif defined(HOST_MIPS) || defined(HOST_MIPS64)
     {
 #define INSN_RETURN     0x03e00008
@@ -1741,7 +1790,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                     !strstart(sym_name, "__op_param", NULL) &&
                     !strstart(sym_name, "__op_jmp", NULL) &&
                     !strstart(sym_name, "__op_gen_label", NULL)) {
-#if defined(HOST_SPARC)
+#if defined(HOST_SPARC) || defined(HOST_HPPA)
                    if (sym_name[0] == '.') {
                        fprintf(outfile,
                                "extern char __dot_%s __asm__(\"%s\");\n",
@@ -1769,8 +1818,13 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
             }
         }
 
+#ifdef __hppa__
+        fprintf(outfile, "    memcpy(gen_code_ptr, (void *)((char *)__canonicalize_funcptr_for_compare(%s)+%d), %d);\n",
+                                       name, (int)(start_offset - offset), copy_size);
+#else
         fprintf(outfile, "    memcpy(gen_code_ptr, (void *)((char *)&%s+%d), %d);\n",
                                        name, (int)(start_offset - offset), copy_size);
+#endif
 
         /* emit code offset information */
         {
@@ -1846,7 +1900,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
 #if defined(HOST_I386)
             {
                 char relname[256];
-                int type;
+                int type, is_label;
                 int addend;
                 int reloc_offset;
                 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
@@ -1868,21 +1922,33 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                         continue;
                     }
 
-                    get_reloc_expr(relname, sizeof(relname), sym_name);
+                    is_label = get_reloc_expr(relname, sizeof(relname), sym_name);
                     addend = get32((uint32_t *)(text + rel->r_offset));
 #ifdef CONFIG_FORMAT_ELF
                     type = ELF32_R_TYPE(rel->r_info);
-                    switch(type) {
-                    case R_386_32:
-                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
-                                reloc_offset, relname, addend);
-                        break;
-                    case R_386_PC32:
-                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n",
-                                reloc_offset, relname, reloc_offset, addend);
-                        break;
-                    default:
-                        error("unsupported i386 relocation (%d)", type);
+                    if (is_label) {
+                        switch(type) {
+                        case R_386_32:
+                        case R_386_PC32:
+                            fprintf(outfile, "    tcg_out_reloc(s, gen_code_ptr + %d, %d, %s, %d);\n",
+                                    reloc_offset, type, relname, addend);
+                            break;
+                        default:
+                            error("unsupported i386 relocation (%d)", type);
+                        }
+                    } else {
+                        switch(type) {
+                        case R_386_32:
+                            fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
+                                    reloc_offset, relname, addend);
+                            break;
+                        case R_386_PC32:
+                            fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n",
+                                    reloc_offset, relname, reloc_offset, addend);
+                            break;
+                        default:
+                            error("unsupported i386 relocation (%d)", type);
+                        }
                     }
 #elif defined(CONFIG_FORMAT_COFF)
                     {
@@ -1899,17 +1965,37 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                         }
                     }
                     type = rel->r_type;
-                    switch(type) {
-                    case DIR32:
-                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
-                                reloc_offset, relname, addend);
-                        break;
-                    case DISP32:
-                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d -4;\n",
-                                reloc_offset, relname, reloc_offset, addend);
-                        break;
-                    default:
-                        error("unsupported i386 relocation (%d)", type);
+                    if (is_label) {
+/* TCG uses elf relocation constants */
+#define R_386_32       1
+#define R_386_PC32     2
+                        switch(type) {
+                        case DIR32:
+                            type = R_386_32;
+                            goto do_reloc;
+                        case DISP32:
+                            type = R_386_PC32;
+                            addend -= 4;
+                        do_reloc:
+                            fprintf(outfile, "    tcg_out_reloc(s, gen_code_ptr + %d, %d, %s, %d);\n",
+                                    reloc_offset, type, relname, addend);
+                            break;
+                        default:
+                            error("unsupported i386 relocation (%d)", type);
+                        }
+                    } else {
+                        switch(type) {
+                        case DIR32:
+                            fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
+                                    reloc_offset, relname, addend);
+                            break;
+                        case DISP32:
+                            fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d -4;\n",
+                                    reloc_offset, relname, reloc_offset, addend);
+                            break;
+                        default:
+                            error("unsupported i386 relocation (%d)", type);
+                        }
                     }
 #else
 #error unsupport object format
@@ -1920,32 +2006,45 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
 #elif defined(HOST_X86_64)
             {
                 char relname[256];
-                int type;
+                int type, is_label;
                 int addend;
                 int reloc_offset;
                 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;
-                    get_reloc_expr(relname, sizeof(relname), sym_name);
+                    is_label = get_reloc_expr(relname, sizeof(relname), sym_name);
                     type = ELF32_R_TYPE(rel->r_info);
                     addend = rel->r_addend;
                     reloc_offset = rel->r_offset - start_offset;
-                    switch(type) {
-                    case R_X86_64_32:
-                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = (uint32_t)%s + %d;\n",
-                                reloc_offset, relname, addend);
-                        break;
-                    case R_X86_64_32S:
-                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = (int32_t)%s + %d;\n",
-                                reloc_offset, relname, addend);
-                        break;
-                    case R_X86_64_PC32:
-                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n",
-                                reloc_offset, relname, reloc_offset, addend);
-                        break;
-                    default:
-                        error("unsupported X86_64 relocation (%d)", type);
+                    if (is_label) {
+                        switch(type) {
+                        case R_X86_64_32:
+                        case R_X86_64_32S:
+                        case R_X86_64_PC32:
+                            fprintf(outfile, "    tcg_out_reloc(s, gen_code_ptr + %d, %d, %s, %d);\n",
+                                    reloc_offset, type, relname, addend);
+                            break;
+                        default:
+                            error("unsupported X86_64 relocation (%d)", type);
+                        }
+                    } else {
+                        switch(type) {
+                        case R_X86_64_32:
+                            fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = (uint32_t)%s + %d;\n",
+                                    reloc_offset, relname, addend);
+                            break;
+                        case R_X86_64_32S:
+                            fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = (int32_t)%s + %d;\n",
+                                    reloc_offset, relname, addend);
+                            break;
+                        case R_X86_64_PC32:
+                            fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n",
+                                    reloc_offset, relname, reloc_offset, addend);
+                            break;
+                        default:
+                            error("unsupported X86_64 relocation (%d)", type);
+                        }
                     }
                 }
                 }
@@ -2120,6 +2219,19 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                             fprintf(outfile, "    *(uint8_t *)(gen_code_ptr + %d) = %s + %d;\n",
                                     reloc_offset, relname, addend);
                             break;
+                        case R_390_PC32DBL:
+                            if (ELF32_ST_TYPE(symtab[ELFW(R_SYM)(rel->r_info)].st_info) == STT_SECTION) {
+                                fprintf(outfile,
+                                        "    *(uint32_t *)(gen_code_ptr + %d) += "
+                                        "((long)&%s - (long)gen_code_ptr) >> 1;\n",
+                                        reloc_offset, name);
+                            }
+                            else
+                                fprintf(outfile,
+                                        "    *(uint32_t *)(gen_code_ptr + %d) = "
+                                        "(%s + %d - ((uint32_t)gen_code_ptr + %d)) >> 1;\n",
+                                        reloc_offset, relname, addend, reloc_offset);
+                            break;
                         default:
                             error("unsupported s390 relocation (%d)", type);
                         }
@@ -2518,6 +2630,82 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                 }
                 }
             }
+#elif defined(HOST_HPPA)
+            {
+                char relname[256];
+                int type, is_label;
+                int addend;
+                int reloc_offset;
+                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 = get_rel_sym_name(rel);
+                    sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
+                    is_label = get_reloc_expr(relname, sizeof(relname), sym_name);
+                    type = ELF32_R_TYPE(rel->r_info);
+                    addend = rel->r_addend;
+                    reloc_offset = rel->r_offset - start_offset;
+
+                    if (is_label) {
+                        switch (type) {
+                        case R_PARISC_PCREL17F:
+                            fprintf(outfile,
+"    tcg_out_reloc(s, gen_code_ptr + %d, %d, %s, %d);\n",
+                                    reloc_offset, type, relname, addend);
+                            break;
+                        default:
+                            error("unsupported hppa label relocation (%d)", type);
+                        }
+                    } else {
+                        switch (type) {
+                        case R_PARISC_DIR21L:
+                            fprintf(outfile,
+"    hppa_patch21l((uint32_t *)(gen_code_ptr + %d), %s, %d);\n",
+                                    reloc_offset, relname, addend);
+                            break;
+                        case R_PARISC_DIR14R:
+                            fprintf(outfile,
+"    hppa_patch14r((uint32_t *)(gen_code_ptr + %d), %s, %d);\n",
+                                    reloc_offset, relname, addend);
+                            break;
+                        case R_PARISC_PCREL17F:
+                            if (strstart(sym_name, "__op_gen_label", NULL)) {
+                                fprintf(outfile,
+"    hppa_patch17f((uint32_t *)(gen_code_ptr + %d), %s, %d);\n",
+                                        reloc_offset, relname, addend);
+                            } else {
+                                fprintf(outfile,
+"    HPPA_RECORD_BRANCH(hppa_stubs, (uint32_t *)(gen_code_ptr + %d), %s);\n",
+                                        reloc_offset, relname);
+                            }
+                            break;
+                        case R_PARISC_DPREL21L:
+                            if (strstart(sym_name, "__op_param", &p))
+                                fprintf(outfile,
+"    hppa_load_imm21l((uint32_t *)(gen_code_ptr + %d), param%s, %d);\n",
+                                        reloc_offset, p, addend);
+                            else
+                                fprintf(outfile,
+"    hppa_patch21l_dprel((uint32_t *)(gen_code_ptr + %d), %s, %d);\n",
+                                        reloc_offset, relname, addend);
+                            break;
+                        case R_PARISC_DPREL14R:
+                            if (strstart(sym_name, "__op_param", &p))
+                                fprintf(outfile,
+"    hppa_load_imm14r((uint32_t *)(gen_code_ptr + %d), param%s, %d);\n",
+                                        reloc_offset, p, addend);
+                            else
+                                fprintf(outfile,
+"    hppa_patch14r_dprel((uint32_t *)(gen_code_ptr + %d), %s, %d);\n",
+                                        reloc_offset, relname, addend);
+                            break;
+                        default:
+                            error("unsupported hppa relocation (%d)", type);
+                        }
+                    }
+                }
+                }
+            }
 #elif defined(HOST_MIPS) || defined(HOST_MIPS64)
             {
                 for (i = 0, rel = relocs; i < nb_relocs; i++, rel++) {
@@ -2626,11 +2814,6 @@ int gen_file(FILE *outfile, int out_type)
     EXE_SYM *sym;
 
     if (out_type == OUT_INDEX_OP) {
-        fprintf(outfile, "DEF(end, 0, 0)\n");
-        fprintf(outfile, "DEF(nop, 0, 0)\n");
-        fprintf(outfile, "DEF(nop1, 1, 0)\n");
-        fprintf(outfile, "DEF(nop2, 2, 0)\n");
-        fprintf(outfile, "DEF(nop3, 3, 0)\n");
         for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
             const char *name;
             name = get_sym_name(sym);
@@ -2640,7 +2823,6 @@ int gen_file(FILE *outfile, int out_type)
         }
     } else if (out_type == OUT_GEN_OP) {
         /* generate gen_xxx functions */
-        fprintf(outfile, "#include \"dyngen-op.h\"\n");
         for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
             const char *name;
             name = get_sym_name(sym);
@@ -2657,6 +2839,7 @@ int gen_file(FILE *outfile, int out_type)
         /* generate big code generation switch */
 
 #ifdef HOST_ARM
+#error broken
         /* We need to know the size of all the ops so we can figure out when
            to emit constant pools.  This must be consistent with opc.h.  */
 fprintf(outfile,
@@ -2677,16 +2860,8 @@ fprintf(outfile,
 "};\n");
 #endif
 
-fprintf(outfile,
-"int dyngen_code(uint8_t *gen_code_buf,\n"
-"                uint16_t *label_offsets, uint16_t *jmp_offsets,\n"
-"                const uint16_t *opc_buf, const uint32_t *opparam_buf, const long *gen_labels)\n"
-"{\n"
-"    uint8_t *gen_code_ptr;\n"
-"    const uint16_t *opc_ptr;\n"
-"    const uint32_t *opparam_ptr;\n");
-
 #ifdef HOST_ARM
+#error broken
 /* Arm is tricky because it uses constant pools for loading immediate values.
    We assume (and require) each function is code followed by a constant pool.
    All the ops are small so this should be ok.  For each op we figure
@@ -2719,6 +2894,7 @@ fprintf(outfile,
 "    uint8_t *arm_pool_ptr = gen_code_buf + 0x1000000;\n");
 #endif
 #ifdef HOST_IA64
+#error broken
     {
        long addend, not_first = 0;
        unsigned long sym_idx;
@@ -2776,18 +2952,8 @@ fprintf(outfile,
     }
 #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. */
-
-fprintf(outfile,
-"    for(;;) {\n");
-
 #ifdef HOST_ARM
+#error broken
 /* Generate constant pool if needed */
 fprintf(outfile,
 "            if (gen_code_ptr + arm_opc_size[*opc_ptr] >= arm_pool_ptr) {\n"
@@ -2800,9 +2966,6 @@ fprintf(outfile,
 "            }\n");
 #endif
 
-fprintf(outfile,
-"        switch(*opc_ptr++) {\n");
-
         for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
             const char *name;
             name = get_sym_name(sym);
@@ -2818,51 +2981,6 @@ fprintf(outfile,
                 gen_code(name, sym->st_value, sym->st_size, outfile, 1);
             }
         }
-
-fprintf(outfile,
-"        case INDEX_op_nop:\n"
-"            break;\n"
-"        case INDEX_op_nop1:\n"
-"            opparam_ptr++;\n"
-"            break;\n"
-"        case INDEX_op_nop2:\n"
-"            opparam_ptr += 2;\n"
-"            break;\n"
-"        case INDEX_op_nop3:\n"
-"            opparam_ptr += 3;\n"
-"            break;\n"
-"        default:\n"
-"            goto the_end;\n"
-"        }\n");
-
-
-fprintf(outfile,
-"    }\n"
-" the_end:\n"
-);
-#ifdef HOST_IA64
-    fprintf(outfile,
-           "    {\n"
-           "      extern char code_gen_buffer[];\n"
-           "      ia64_apply_fixes(&gen_code_ptr, ltoff_fixes, "
-           "(uint64_t) code_gen_buffer + 2*(1<<20), plt_fixes,\n\t\t\t"
-           "sizeof(plt_target)/sizeof(plt_target[0]),\n\t\t\t"
-           "plt_target, plt_offset);\n    }\n");
-#endif
-
-/* generate some code patching */
-#ifdef HOST_ARM
-fprintf(outfile,
-"if (arm_data_ptr != arm_data_table + ARM_LDR_TABLE_SIZE)\n"
-"    gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, "
-"arm_ldr_ptr, arm_data_ptr, arm_data_table + ARM_LDR_TABLE_SIZE, 0);\n");
-#endif
-    /* flush instruction cache */
-    fprintf(outfile, "flush_icache_range((unsigned long)gen_code_buf, (unsigned long)gen_code_ptr);\n");
-
-    fprintf(outfile, "return gen_code_ptr -  gen_code_buf;\n");
-    fprintf(outfile, "}\n\n");
-
     }
 
     return 0;