removed sh4 user build (not usable yet)
[qemu] / dyngen.c
index ad0e834..c1f348a 100644 (file)
--- a/dyngen.c
+++ b/dyngen.c
@@ -54,7 +54,7 @@
 #define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
 #undef ELF_USES_RELOCA
 
-#elif defined(HOST_AMD64)
+#elif defined(HOST_X86_64)
 
 #define ELF_CLASS      ELFCLASS64
 #define ELF_ARCH       EM_X86_64
@@ -635,6 +635,8 @@ static char *get_rel_sym_name(EXE_RELOC *rel)
     name = get_sym_name(symtab + *(uint32_t *)(rel->r_reloc->r_symndx));
     if (!strcmp(name, ".data"))
         name = name_for_dotdata(rel);
+    if (name[0] == '.')
+        return NULL;
     return name;
 }
 
@@ -996,11 +998,11 @@ static const char * get_reloc_name(EXE_RELOC * rel, int * sslide)
 
        switch(rel->r_type)
        {
-               case PPC_RELOC_LO16: fetch_next_pair_value(rel+1, &other_half); sectoffset = (sectoffset & 0xffff);
+               case PPC_RELOC_LO16: fetch_next_pair_value(rel+1, &other_half); sectoffset |= (other_half << 16);
                        break;
-               case PPC_RELOC_HI16: fetch_next_pair_value(rel+1, &other_half); sectoffset = (other_half & 0xffff);
+               case PPC_RELOC_HI16: fetch_next_pair_value(rel+1, &other_half); sectoffset = (sectoffset << 16) | (uint16_t)(other_half & 0xffff);
                        break;
-               case PPC_RELOC_HA16: fetch_next_pair_value(rel+1, &other_half); sectoffset = (other_half & 0xffff);
+               case PPC_RELOC_HA16: fetch_next_pair_value(rel+1, &other_half); sectoffset = (sectoffset << 16) + (int16_t)(other_half & 0xffff);
                        break;
                case PPC_RELOC_BR24:
                        sectoffset = ( *(uint32_t *)(text + rel->r_address) & 0x03fffffc );
@@ -1146,13 +1148,11 @@ int load_object(const char *filename)
        
        /* Now transform the symtab, to an extended version, with the sym size, and the C name */
        for(i = 0, sym = symtab, syment = symtab_std; i < nb_syms; i++, sym++, syment++) {
-        const char *name;
         struct nlist *sym_follow, *sym_next = 0;
         unsigned int j;
-        name = find_str_by_index(sym->n_un.n_strx);
                memset(sym, 0, sizeof(*sym));
                
-               if ( sym->n_type & N_STAB ) /* Debug symbols are skipped */
+               if ( syment->n_type & N_STAB ) /* Debug symbols are skipped */
             continue;
                        
                memcpy(sym, syment, sizeof(*syment));
@@ -1185,6 +1185,68 @@ int load_object(const char *filename)
 
 #endif /* CONFIG_FORMAT_MACH */
 
+void 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);
+    } else {
+#ifdef HOST_SPARC
+        if (sym_name[0] == '.')
+            snprintf(name, sizeof(name),
+                     "(long)(&__dot_%s)",
+                     sym_name + 1);
+        else
+#endif
+            snprintf(name, name_size, "(long)(&%s)", sym_name);
+    }
+}
+
+#ifdef HOST_IA64
+
+#define PLT_ENTRY_SIZE 16      /* 1 bundle containing "brl" */
+
+struct plt_entry {
+    struct plt_entry *next;
+    const char *name;
+    unsigned long addend;
+} *plt_list;
+
+static int
+get_plt_index (const char *name, unsigned long addend)
+{
+    struct plt_entry *plt, *prev= NULL;
+    int index = 0;
+
+    /* see if we already have an entry for this target: */
+    for (plt = plt_list; plt; ++index, prev = plt, plt = plt->next)
+       if (strcmp(plt->name, name) == 0 && plt->addend == addend)
+           return index;
+
+    /* nope; create a new PLT entry: */
+
+    plt = malloc(sizeof(*plt));
+    if (!plt) {
+       perror("malloc");
+       exit(1);
+    }
+    memset(plt, 0, sizeof(*plt));
+    plt->name = strdup(name);
+    plt->addend = addend;
+
+    /* append to plt-list: */
+    if (prev)
+       prev->next = plt;
+    else
+       plt_list = plt;
+    return index;
+}
+
+#endif
+
 #ifdef HOST_ARM
 
 int arm_emit_ldr_info(const char *name, unsigned long start_offset,
@@ -1244,11 +1306,7 @@ int arm_emit_ldr_info(const char *name, unsigned long start_offset,
                         if (rel->r_offset == (pc_offset + start_offset)) {
                             sym_name = get_rel_sym_name(rel);
                             /* 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);
-                            }
+                            get_reloc_expr(relname, sizeof(relname), sym_name);
                             type = ELF32_R_TYPE(rel->r_info);
                             if (type != R_ARM_ABS32)
                                 error("%s: unsupported data relocation", name);
@@ -1307,7 +1365,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
     p_start = text + offset;
     p_end = p_start + size;
     start_offset = offset;
-#if defined(HOST_I386) || defined(HOST_AMD64)
+#if defined(HOST_I386) || defined(HOST_X86_64)
 #ifdef CONFIG_FORMAT_COFF
     {
         uint8_t *p;
@@ -1378,7 +1436,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
         /* 08 00 84 00 */
         if (get32((uint32_t *)p) != 0x00840008)
             error("br.ret.sptk.many b0;; expected at the end of %s", name);
-        copy_size = p - p_start;
+       copy_size = p_end - p_start;
     }
 #elif defined(HOST_SPARC)
     {
@@ -1482,7 +1540,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
             sym_name = get_rel_sym_name(rel);
             if(!sym_name)
                 continue;
-            if (strstart(sym_name, "__op_param", &p)) {
+            if (strstart(sym_name, "__op_param", &p) ||
+                strstart(sym_name, "__op_gen_label", &p)) {
                 n = strtoul(p, NULL, 10);
                 if (n > MAX_ARGS)
                     error("too many arguments in %s", name);
@@ -1514,7 +1573,11 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
             }
             fprintf(outfile, ";\n");
         }
+#if defined(HOST_IA64)
+        fprintf(outfile, "    extern char %s;\n", name);
+#else
         fprintf(outfile, "    extern void %s();\n", name);
+#endif
 
         for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
             host_ulong offset = get_rel_offset(rel);
@@ -1525,7 +1588,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                     continue;
                 if (*sym_name && 
                     !strstart(sym_name, "__op_param", NULL) &&
-                    !strstart(sym_name, "__op_jmp", NULL)) {
+                    !strstart(sym_name, "__op_jmp", NULL) &&
+                    !strstart(sym_name, "__op_gen_label", NULL)) {
 #if defined(HOST_SPARC)
                    if (sym_name[0] == '.') {
                        fprintf(outfile,
@@ -1534,9 +1598,18 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                        continue;
                    }
 #endif
-#ifdef __APPLE__
+#if defined(__APPLE__)
 /* set __attribute((unused)) on darwin because we wan't to avoid warning when we don't use the symbol */
                     fprintf(outfile, "extern char %s __attribute__((unused));\n", sym_name);
+#elif defined(HOST_IA64)
+                       if (ELF64_R_TYPE(rel->r_info) != R_IA64_PCREL21B)
+                               /*
+                                * PCREL21 br.call targets generally
+                                * are out of range and need to go
+                                * through an "import stub".
+                                */
+                               fprintf(outfile, "    extern char %s;\n",
+                                       sym_name);
 #else
                     fprintf(outfile, "extern char %s;\n", sym_name);
 #endif
@@ -1604,10 +1677,9 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                         }
                     }
 #endif                    
-
-                    if (val >= start_offset && val < start_offset + copy_size) {
+                    if (val >= start_offset && val <= start_offset + copy_size) {
                         n = strtol(p, NULL, 10);
-                        fprintf(outfile, "    label_offsets[%d] = %ld + (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, (long)(val - start_offset));
                     }
                 }
             }
@@ -1624,10 +1696,14 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                 char name[256];
                 int type;
                 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);
+                    if (!sym_name)
+                        continue;
+                    reloc_offset = rel->r_offset - start_offset;
                     if (strstart(sym_name, "__op_jmp", &p)) {
                         int n;
                         n = strtol(p, NULL, 10);
@@ -1636,26 +1712,22 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                            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);
+                                n, reloc_offset);
                         continue;
                     }
-                        
-                    if (strstart(sym_name, "__op_param", &p)) {
-                        snprintf(name, sizeof(name), "param%s", p);
-                    } else {
-                        snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
-                    }
+
+                    get_reloc_expr(name, sizeof(name), 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", 
-                                rel->r_offset - start_offset, name, addend);
+                                reloc_offset, name, addend);
                         break;
                     case R_386_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);
+                                reloc_offset, name, reloc_offset, addend);
                         break;
                     default:
                         error("unsupported i386 relocation (%d)", type);
@@ -1678,11 +1750,11 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                     switch(type) {
                     case DIR32:
                         fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", 
-                                rel->r_offset - start_offset, name, addend);
+                                reloc_offset, name, addend);
                         break;
                     case DISP32:
                         fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d -4;\n", 
-                                rel->r_offset - start_offset, name, rel->r_offset - start_offset, addend);
+                                reloc_offset, name, reloc_offset, addend);
                         break;
                     default:
                         error("unsupported i386 relocation (%d)", type);
@@ -1693,37 +1765,35 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                 }
                 }
             }
-#elif defined(HOST_AMD64)
+#elif defined(HOST_X86_64)
             {
                 char name[256];
                 int type;
                 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;
-                    if (strstart(sym_name, "__op_param", &p)) {
-                        snprintf(name, sizeof(name), "param%s", p);
-                    } else {
-                        snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
-                    }
+                    get_reloc_expr(name, sizeof(name), 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", 
-                                rel->r_offset - start_offset, name, addend);
+                                reloc_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);
+                                reloc_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);
+                                reloc_offset, name, reloc_offset, addend);
                         break;
                     default:
-                        error("unsupported AMD64 relocation (%d)", type);
+                        error("unsupported X86_64 relocation (%d)", type);
                     }
                 }
                 }
@@ -1734,10 +1804,12 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                 char name[256];
                 int type;
                 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;
+                        reloc_offset = rel->r_offset - start_offset;
                         if (strstart(sym_name, "__op_jmp", &p)) {
                             int n;
                             n = strtol(p, NULL, 10);
@@ -1746,38 +1818,34 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                                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);
+                                    n, reloc_offset);
                             continue;
                         }
                         
-                        if (strstart(sym_name, "__op_param", &p)) {
-                            snprintf(name, sizeof(name), "param%s", p);
-                        } else {
-                            snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
-                        }
+                        get_reloc_expr(name, sizeof(name), 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 + %d) = %s + %d;\n", 
-                                    rel->r_offset - start_offset, name, addend);
+                                    reloc_offset, name, addend);
                             break;
                         case R_PPC_ADDR16_LO:
                             fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d) = (%s + %d);\n", 
-                                    rel->r_offset - start_offset, name, addend);
+                                    reloc_offset, name, addend);
                             break;
                         case R_PPC_ADDR16_HI:
                             fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d) = (%s + %d) >> 16;\n", 
-                                    rel->r_offset - start_offset, name, addend);
+                                    reloc_offset, name, addend);
                             break;
                         case R_PPC_ADDR16_HA:
                             fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d) = (%s + %d + 0x8000) >> 16;\n", 
-                                    rel->r_offset - start_offset, name, addend);
+                                    reloc_offset, name, addend);
                             break;
                         case R_PPC_REL24:
                             /* warning: must be at 32 MB distancy */
                             fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | ((%s - (long)(gen_code_ptr + %d) + %d) & 0x03fffffc);\n", 
-                                    rel->r_offset - start_offset, rel->r_offset - start_offset, name, rel->r_offset - start_offset, addend);
+                                    reloc_offset, reloc_offset, name, reloc_offset, addend);
                             break;
                         default:
                             error("unsupported powerpc relocation (%d)", type);
@@ -1839,19 +1907,20 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                                                continue; /* dunno how to handle without final_sym_name */
                                        }
                                                                                                           
-                                       if (strstart(sym_name, "__op_param", &p)) {
-                                               snprintf(final_sym_name, sizeof(final_sym_name), "param%s", p);
-                                       } else {
-                                               snprintf(final_sym_name, sizeof(final_sym_name), "(long)(&%s)", sym_name);
-                                       }
-                       
+                                        get_reloc_expr(final_sym_name, sizeof(final_sym_name), 
+                                                       sym_name);
                                        switch(type) {
                                        case PPC_RELOC_BR24:
-                                               fprintf(outfile, "{\n");
-                                               fprintf(outfile, "    uint32_t imm = *(uint32_t *)(gen_code_ptr + %d) & 0x3fffffc;\n", slide);
-                                               fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | ((imm + ((long)%s - (long)gen_code_ptr) + %d) & 0x03fffffc);\n", 
+                                           if (!strstart(sym_name,"__op_gen_label",&p)) {
+                                               fprintf(outfile, "{\n");
+                                               fprintf(outfile, "    uint32_t imm = *(uint32_t *)(gen_code_ptr + %d) & 0x3fffffc;\n", slide);
+                                               fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | ((imm + ((long)%s - (long)gen_code_ptr) + %d) & 0x03fffffc);\n", 
                                                                                        slide, slide, name, sslide );
-                                               fprintf(outfile, "}\n");
+                                               fprintf(outfile, "}\n");
+                                       } else {
+                                                       fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | (((long)%s - (long)gen_code_ptr - %d) & 0x03fffffc);\n",
+                                                                                       slide, slide, final_sym_name, slide);
+                                       }
                                                break;
                                        case PPC_RELOC_HI16:
                                                fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d) >> 16;\n", 
@@ -1878,29 +1947,27 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                 char name[256];
                 int type;
                 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;
-                        if (strstart(sym_name, "__op_param", &p)) {
-                            snprintf(name, sizeof(name), "param%s", p);
-                        } else {
-                            snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
-                        }
+                        get_reloc_expr(name, sizeof(name), sym_name);
                         type = ELF32_R_TYPE(rel->r_info);
                         addend = rel->r_addend;
+                        reloc_offset = rel->r_offset - start_offset;
                         switch(type) {
                         case R_390_32:
                             fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", 
-                                    rel->r_offset - start_offset, name, addend);
+                                    reloc_offset, name, addend);
                             break;
                         case R_390_16:
                             fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d) = %s + %d;\n", 
-                                    rel->r_offset - start_offset, name, addend);
+                                    reloc_offset, name, addend);
                             break;
                         case R_390_8:
                             fprintf(outfile, "    *(uint8_t *)(gen_code_ptr + %d) = %s + %d;\n", 
-                                    rel->r_offset - start_offset, name, addend);
+                                    reloc_offset, name, addend);
                             break;
                         default:
                             error("unsupported s390 relocation (%d)", type);
@@ -1913,17 +1980,19 @@ 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) {
                        int type;
+                        long reloc_offset;
 
                        type = ELF64_R_TYPE(rel->r_info);
                        sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name;
+                        reloc_offset = rel->r_offset - start_offset;
                        switch (type) {
                        case R_ALPHA_GPDISP:
                            /* The gp is just 32 bit, and never changes, so it's easiest to emit it
                               as an immediate instead of constructing it from the pv or ra.  */
                            fprintf(outfile, "    immediate_ldah(gen_code_ptr + %ld, gp);\n",
-                                   rel->r_offset - start_offset);
+                                   reloc_offset);
                            fprintf(outfile, "    immediate_lda(gen_code_ptr + %ld, gp);\n",
-                                   rel->r_offset - start_offset + rel->r_addend);
+                                   reloc_offset + (int)rel->r_addend);
                            break;
                        case R_ALPHA_LITUSE:
                            /* jsr to literal hint. Could be used to optimize to bsr. Ignore for
@@ -1943,18 +2012,18 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                               special treatment.  */
                            if (strstart(sym_name, "__op_param", &p))
                                fprintf(outfile, "    immediate_ldah(gen_code_ptr + %ld, param%s);\n",
-                                       rel->r_offset - start_offset, p);
+                                       reloc_offset, p);
                            break;
                        case R_ALPHA_GPRELLOW:
                            if (strstart(sym_name, "__op_param", &p))
                                fprintf(outfile, "    immediate_lda(gen_code_ptr + %ld, param%s);\n",
-                                       rel->r_offset - start_offset, p);
+                                       reloc_offset, p);
                            break;
                        case R_ALPHA_BRSGP:
                            /* PC-relative jump. Tweak offset to skip the two instructions that try to
                               set up the gp from the pv.  */
                            fprintf(outfile, "    fix_bsr(gen_code_ptr + %ld, (uint8_t *) &%s - (gen_code_ptr + %ld + 4) + 8);\n",
-                                   rel->r_offset - start_offset, sym_name, rel->r_offset - start_offset);
+                                   reloc_offset, sym_name, reloc_offset);
                            break;
                        default:
                            error("unsupported Alpha relocation (%d)", type);
@@ -1964,56 +2033,97 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
             }
 #elif defined(HOST_IA64)
             {
+               unsigned long sym_idx;
+               long code_offset;
                 char name[256];
                 int type;
-                int addend;
+                long 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[ELF64_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 = ELF64_R_TYPE(rel->r_info);
-                        addend = rel->r_addend;
-                        switch(type) {
-                       case R_IA64_LTOFF22:
-                           error("must implemnt R_IA64_LTOFF22 relocation");
-                       case R_IA64_PCREL21B:
-                           error("must implemnt R_IA64_PCREL21B relocation");
-                        default:
-                            error("unsupported ia64 relocation (%d)", type);
-                        }
-                    }
+                   sym_idx = ELF64_R_SYM(rel->r_info);
+                    if (rel->r_offset < start_offset
+                       || rel->r_offset >= start_offset + copy_size)
+                       continue;
+                   sym_name = (strtab + symtab[sym_idx].st_name);
+                   code_offset = rel->r_offset - start_offset;
+                   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] ="
+                               "%ld + (gen_code_ptr - gen_code_buf);\n",
+                               n, code_offset);
+                       continue;
+                   }
+                   get_reloc_expr(name, sizeof(name), sym_name);
+                   type = ELF64_R_TYPE(rel->r_info);
+                   addend = rel->r_addend;
+                   switch(type) {
+                     case R_IA64_IMM64:
+                         fprintf(outfile,
+                                 "    ia64_imm64(gen_code_ptr + %ld, "
+                                 "%s + %ld);\n",
+                                 code_offset, name, addend);
+                         break;
+                     case R_IA64_LTOFF22X:
+                     case R_IA64_LTOFF22:
+                         fprintf(outfile, "    IA64_LTOFF(gen_code_ptr + %ld,"
+                                 " %s + %ld, %d);\n",
+                                 code_offset, name, addend,
+                                 (type == R_IA64_LTOFF22X));
+                         break;
+                     case R_IA64_LDXMOV:
+                         fprintf(outfile,
+                                 "    ia64_ldxmov(gen_code_ptr + %ld,"
+                                 " %s + %ld);\n", code_offset, name, addend);
+                         break;
+
+                     case R_IA64_PCREL21B:
+                         if (strstart(sym_name, "__op_gen_label", NULL)) {
+                             fprintf(outfile,
+                                     "    ia64_imm21b(gen_code_ptr + %ld,"
+                                     " (long) (%s + %ld -\n\t\t"
+                                     "((long) gen_code_ptr + %ld)) >> 4);\n",
+                                     code_offset, name, addend,
+                                     code_offset & ~0xfUL);
+                         } else {
+                             fprintf(outfile,
+                                     "    IA64_PLT(gen_code_ptr + %ld, "
+                                     "%d);\t/* %s + %ld */\n",
+                                     code_offset,
+                                     get_plt_index(sym_name, addend),
+                                     sym_name, addend);
+                         }
+                         break;
+                     default:
+                         error("unsupported ia64 relocation (0x%x)",
+                               type);
+                   }
                 }
+               fprintf(outfile, "    ia64_nop_b(gen_code_ptr + %d);\n",
+                       copy_size - 16 + 2);
             }
 #elif defined(HOST_SPARC)
             {
                 char name[256];
                 int type;
                 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[ELF32_R_SYM(rel->r_info)].st_name;
-                        if (strstart(sym_name, "__op_param", &p)) {
-                            snprintf(name, sizeof(name), "param%s", p);
-                        } else {
-                               if (sym_name[0] == '.')
-                                       snprintf(name, sizeof(name),
-                                                "(long)(&__dot_%s)",
-                                                sym_name + 1);
-                               else
-                                       snprintf(name, sizeof(name),
-                                                "(long)(&%s)", sym_name);
-                        }
+                        get_reloc_expr(name, sizeof(name), sym_name);
                         type = ELF32_R_TYPE(rel->r_info);
                         addend = rel->r_addend;
+                        reloc_offset = rel->r_offset - start_offset;
                         switch(type) {
                         case R_SPARC_32:
                             fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", 
-                                    rel->r_offset - start_offset, name, addend);
+                                    reloc_offset, name, addend);
                            break;
                        case R_SPARC_HI22:
                             fprintf(outfile,
@@ -2021,9 +2131,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                                    "((*(uint32_t *)(gen_code_ptr + %d)) "
                                    " & ~0x3fffff) "
                                    " | (((%s + %d) >> 10) & 0x3fffff);\n",
-                                    rel->r_offset - start_offset,
-                                   rel->r_offset - start_offset,
-                                   name, addend);
+                                    reloc_offset, reloc_offset, name, addend);
                            break;
                        case R_SPARC_LO10:
                             fprintf(outfile,
@@ -2031,9 +2139,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                                    "((*(uint32_t *)(gen_code_ptr + %d)) "
                                    " & ~0x3ff) "
                                    " | ((%s + %d) & 0x3ff);\n",
-                                    rel->r_offset - start_offset,
-                                   rel->r_offset - start_offset,
-                                   name, addend);
+                                    reloc_offset, reloc_offset, name, addend);
                            break;
                        case R_SPARC_WDISP30:
                            fprintf(outfile,
@@ -2042,10 +2148,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                                    " & ~0x3fffffff) "
                                    " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
                                    "    & 0x3fffffff);\n",
-                                   rel->r_offset - start_offset,
-                                   rel->r_offset - start_offset,
-                                   name, addend,
-                                   rel->r_offset - start_offset);
+                                   reloc_offset, reloc_offset, name, addend,
+                                   reloc_offset);
                            break;
                         default:
                             error("unsupported sparc relocation (%d)", type);
@@ -2058,21 +2162,19 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                 char name[256];
                 int type;
                 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[ELF64_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);
-                        }
+                        get_reloc_expr(name, sizeof(name), sym_name);
                         type = ELF64_R_TYPE(rel->r_info);
                         addend = rel->r_addend;
+                        reloc_offset = rel->r_offset - start_offset;
                         switch(type) {
                         case R_SPARC_32:
                             fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
-                                    rel->r_offset - start_offset, name, addend);
+                                    reloc_offset, name, addend);
                            break;
                        case R_SPARC_HI22:
                             fprintf(outfile,
@@ -2080,9 +2182,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                                    "((*(uint32_t *)(gen_code_ptr + %d)) "
                                    " & ~0x3fffff) "
                                    " | (((%s + %d) >> 10) & 0x3fffff);\n",
-                                    rel->r_offset - start_offset,
-                                   rel->r_offset - start_offset,
-                                   name, addend);
+                                    reloc_offset, reloc_offset, name, addend);
                            break;
                        case R_SPARC_LO10:
                             fprintf(outfile,
@@ -2090,9 +2190,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                                    "((*(uint32_t *)(gen_code_ptr + %d)) "
                                    " & ~0x3ff) "
                                    " | ((%s + %d) & 0x3ff);\n",
-                                    rel->r_offset - start_offset,
-                                   rel->r_offset - start_offset,
-                                   name, addend);
+                                    reloc_offset, reloc_offset, name, addend);
                            break;
                        case R_SPARC_WDISP30:
                            fprintf(outfile,
@@ -2101,10 +2199,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                                    " & ~0x3fffffff) "
                                    " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
                                    "    & 0x3fffffff);\n",
-                                   rel->r_offset - start_offset,
-                                   rel->r_offset - start_offset,
-                                   name, addend,
-                                   rel->r_offset - start_offset);
+                                   reloc_offset, reloc_offset, name, addend,
+                                   reloc_offset);
                            break;
                         default:
                            error("unsupported sparc64 relocation (%d)", type);
@@ -2117,6 +2213,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                 char name[256];
                 int type;
                 int addend;
+                int reloc_offset;
 
                 arm_emit_ldr_info(name, start_offset, outfile, p_start, p_end,
                                   relocs, nb_relocs);
@@ -2128,21 +2225,18 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                     /* 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);
-                    }
+                    get_reloc_expr(name, sizeof(name), sym_name);
                     type = ELF32_R_TYPE(rel->r_info);
                     addend = get32((uint32_t *)(text + rel->r_offset));
+                    reloc_offset = rel->r_offset - start_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);
+                                reloc_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);
+                                reloc_offset, addend, name);
                         break;
                     default:
                         error("unsupported arm relocation (%d)", type);
@@ -2155,29 +2249,27 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                 char name[256];
                 int type;
                 int addend;
+                int reloc_offset;
                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);
-                    }
+                    get_reloc_expr(name, sizeof(name), sym_name);
                     type = ELF32_R_TYPE(rel->r_info);
                     addend = get32((uint32_t *)(text + rel->r_offset)) + rel->r_addend;
+                    reloc_offset = rel->r_offset - start_offset;
                     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 );
+                                reloc_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);
+                                reloc_offset, name, reloc_offset, /*sym->st_value+*/ addend);
                         break;
                     default:
                         error("unsupported m68k relocation (%d)", type);
@@ -2232,7 +2324,7 @@ 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);
@@ -2250,7 +2342,7 @@ int gen_file(FILE *outfile, int out_type)
 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)\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"
@@ -2262,6 +2354,63 @@ fprintf(outfile,
 "    LDREntry *arm_ldr_ptr = arm_ldr_table;\n"
 "    uint32_t *arm_data_ptr = arm_data_table;\n");
 #endif
+#ifdef HOST_IA64
+    {
+       long addend, not_first = 0;
+       unsigned long sym_idx;
+       int index, max_index;
+       const char *sym_name;
+       EXE_RELOC *rel;
+
+       max_index = -1;
+       for (i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
+           sym_idx = ELF64_R_SYM(rel->r_info);
+           sym_name = (strtab + symtab[sym_idx].st_name);
+           if (strstart(sym_name, "__op_gen_label", NULL))
+               continue;
+           if (ELF64_R_TYPE(rel->r_info) != R_IA64_PCREL21B)
+               continue;
+
+           addend = rel->r_addend;
+           index = get_plt_index(sym_name, addend);
+           if (index <= max_index)
+               continue;
+           max_index = index;
+           fprintf(outfile, "    extern void %s(void);\n", sym_name);
+       }
+
+       fprintf(outfile,
+               "    struct ia64_fixup *plt_fixes = NULL, "
+               "*ltoff_fixes = NULL;\n"
+               "    static long plt_target[] = {\n\t");
+
+       max_index = -1;
+       for (i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
+           sym_idx = ELF64_R_SYM(rel->r_info);
+           sym_name = (strtab + symtab[sym_idx].st_name);
+           if (strstart(sym_name, "__op_gen_label", NULL))
+               continue;
+           if (ELF64_R_TYPE(rel->r_info) != R_IA64_PCREL21B)
+               continue;
+
+           addend = rel->r_addend;
+           index = get_plt_index(sym_name, addend);
+           if (index <= max_index)
+               continue;
+           max_index = index;
+
+           if (not_first)
+               fprintf(outfile, ",\n\t");
+           not_first = 1;
+           if (addend)
+               fprintf(outfile, "(long) &%s + %ld", sym_name, addend);
+           else
+               fprintf(outfile, "(long) &%s", sym_name);
+       }
+       fprintf(outfile, "\n    };\n"
+           "    unsigned int plt_offset[%u] = { 0 };\n", max_index + 1);
+    }
+#endif
 
 fprintf(outfile,
 "\n"
@@ -2324,6 +2473,15 @@ 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