fixed ljmp and iret to TSS
[qemu] / dyngen.c
index 3e84623..7c1c0e8 100644 (file)
--- a/dyngen.c
+++ b/dyngen.c
@@ -25,7 +25,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 
-#include "config.h"
+#include "config-host.h"
 
 /* elf format definitions. We use these macros to test the CPU to
    allow cross compilation (this tool must be ran on the build
 #define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
 #undef ELF_USES_RELOCA
 
+#elif defined(HOST_AMD64)
+
+#define ELF_CLASS      ELFCLASS64
+#define ELF_ARCH       EM_X86_64
+#define elf_check_arch(x) ((x) == EM_X86_64)
+#define ELF_USES_RELOCA
+
 #elif defined(HOST_PPC)
 
 #define ELF_CLASS      ELFCLASS32
 #define elf_check_arch(x) ((x) == EM_ARM)
 #define ELF_USES_RELOC
 
+#elif defined(HOST_M68K)
+
+#define ELF_CLASS      ELFCLASS32
+#define ELF_ARCH       EM_68K
+#define elf_check_arch(x) ((x) == EM_68K)
+#define ELF_USES_RELOCA
+
 #else
 #error unsupported CPU - please update the code
 #endif
@@ -108,8 +122,7 @@ typedef uint64_t host_ulong;
 #define SHT_RELOC SHT_REL
 #endif
 
-#define NO_THUNK_TYPE_SIZE
-#include "thunk.h"
+#include "bswap.h"
 
 enum {
     OUT_GEN_OP,
@@ -440,6 +453,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
     start_offset = offset;
     switch(ELF_ARCH) {
     case EM_386:
+    case EM_X86_64:
         {
             int len;
             len = p_end - p_start;
@@ -479,8 +493,11 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
         {
            uint8_t *p;
            p = p_end - 4;
+#if 0
+            /* XXX: check why it occurs */
            if (p == p_start)
                error("empty code for %s", name);
+#endif
             if (get32((uint32_t *)p) != 0x6bfa8001)
                error("ret expected at the end of %s", name);
            copy_size = p - p_start;        
@@ -576,6 +593,21 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                                       relocs, nb_relocs);
         break;
 #endif
+    case EM_68K:
+       {
+           uint8_t *p;
+           p = (void *)(p_end - 2);
+           if (p == p_start)
+               error("empty code for %s", name);
+           // remove NOP's, probably added for alignment
+           while ((get16((uint16_t *)p) == 0x4e71) &&
+                  (p>p_start)) 
+             p -= 2;
+           if (get16((uint16_t *)p) != 0x4e75)
+               error("rts expected at the end of %s", name);
+           copy_size = p - p_start;
+       }
+        break;
     default:
        error("unknown ELF architecture");
     }
@@ -648,7 +680,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
         {
             ElfW(Sym) *sym;
             const char *sym_name, *p;
-            target_ulong val;
+            unsigned long val;
             int n;
 
             for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
@@ -663,7 +695,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                     if (!ptr)
                         error("__op_labelN in invalid section");
                     offset = sym->st_value;
-                    val = *(target_ulong *)(ptr + offset);
+                    val = *(unsigned long *)(ptr + offset);
 #ifdef ELF_USES_RELOCA
                     {
                         int reloc_shndx, nb_relocs1, j;
@@ -687,7 +719,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
 
                     if (val >= start_offset && val < start_offset + copy_size) {
                         n = strtol(p, NULL, 10);
-                        fprintf(outfile, "    label_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n", n, val - start_offset);
+                        fprintf(outfile, "    label_offsets[%d] = %ld + (gen_code_ptr - gen_code_buf);\n", n, val - start_offset);
                     }
                 }
             }
@@ -708,6 +740,18 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                 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;
+                    if (strstart(sym_name, "__op_jmp", &p)) {
+                        int n;
+                        n = strtol(p, NULL, 10);
+                        /* __op_jmp relocations are done at
+                           runtime to do translated block
+                           chaining: the offset of the instruction
+                           needs to be stored */
+                        fprintf(outfile, "    jmp_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n",
+                                n, rel->r_offset - start_offset);
+                        continue;
+                    }
+                        
                     if (strstart(sym_name, "__op_param", &p)) {
                         snprintf(name, sizeof(name), "param%s", p);
                     } else {
@@ -730,6 +774,41 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                 }
                 }
             }
+#elif defined(HOST_AMD64)
+            {
+                char name[256];
+                int type;
+                int addend;
+                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;
+                    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_X86_64_32:
+                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = (uint32_t)%s + %d;\n", 
+                                rel->r_offset - start_offset, name, addend);
+                        break;
+                    case R_X86_64_32S:
+                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = (int32_t)%s + %d;\n", 
+                                rel->r_offset - start_offset, name, addend);
+                        break;
+                    case R_X86_64_PC32:
+                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n", 
+                                rel->r_offset - start_offset, name, rel->r_offset - start_offset, addend);
+                        break;
+                    default:
+                        error("unsupported AMD64 relocation (%d)", type);
+                    }
+                }
+                }
+            }
 #elif defined(HOST_PPC)
             {
                 char name[256];
@@ -1063,6 +1142,41 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                 }
                 }
             }
+#elif defined(HOST_M68K)
+            {
+                char name[256];
+                int type;
+                int addend;
+               Elf32_Sym *sym;
+                for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
+                if (rel->r_offset >= start_offset &&
+                   rel->r_offset < start_offset + copy_size) {
+                   sym = &(symtab[ELFW(R_SYM)(rel->r_info)]);
+                    sym_name = strtab + symtab[ELFW(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 = get32((uint32_t *)(text + rel->r_offset)) + rel->r_addend;
+                    switch(type) {
+                    case R_68K_32:
+                       fprintf(outfile, "    /* R_68K_32 RELOC, offset %x */\n", rel->r_offset) ;
+                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %#x;\n", 
+                                rel->r_offset - start_offset, name, addend );
+                        break;
+                    case R_68K_PC32:
+                       fprintf(outfile, "    /* R_68K_PC32 RELOC, offset %x */\n", rel->r_offset);
+                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %#x) + %#x;\n", 
+                                rel->r_offset - start_offset, name, rel->r_offset - start_offset, /*sym->st_value+*/ addend);
+                        break;
+                    default:
+                        error("unsupported m68k relocation (%d)", type);
+                    }
+                }
+                }
+            }
 #else
 #error unsupported CPU
 #endif
@@ -1200,11 +1314,11 @@ int load_elf(const char *filename, FILE *outfile, int out_type)
     }
 
     if (out_type == OUT_INDEX_OP) {
-        fprintf(outfile, "DEF(nop1, 0, 0)\n");
-        fprintf(outfile, "DEF(nop2, 0, 0)\n");
-        fprintf(outfile, "DEF(nop3, 0, 0)\n");
-        fprintf(outfile, "DEF(nop, 0, 0)\n");
         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, *p;
             name = strtab + sym->st_name;
@@ -1306,38 +1420,10 @@ fprintf(outfile,
 " the_end:\n"
 );
 
-/* generate epilogue */ 
-    switch(ELF_ARCH) {
-    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;
-    case EM_S390:
-        fprintf(outfile, "*((uint16_t *)gen_code_ptr)++ = 0x07fe; /* br %%r14 */\n");
-        break;
-    case EM_ALPHA:
-        fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x6bfa8001; /* ret */\n");
-        break;
-    case EM_IA_64:
-        fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x00840008; /* br.ret.sptk.many b0;; */\n");
-        break;
-    case EM_SPARC:
-    case EM_SPARC32PLUS:
-       fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x81c62008; /* jmpl %%i0 + 8, %%g0 */\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");
-    }
+/* generate some code patching */ 
+#ifdef HOST_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");
+#endif
     /* flush instruction cache */
     fprintf(outfile, "flush_icache_range((unsigned long)gen_code_buf, (unsigned long)gen_code_ptr);\n");