PCI SCSI HBA emulation.
[qemu] / dyngen.c
index 5823e07..c1f348a 100644 (file)
--- a/dyngen.c
+++ b/dyngen.c
@@ -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;
 }
 
@@ -1203,6 +1205,48 @@ void get_reloc_expr(char *name, int name_size, const char *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,
@@ -1392,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)
     {
@@ -1529,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);
@@ -1550,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
@@ -1622,7 +1679,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
 #endif                    
                     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));
                     }
                 }
             }
@@ -1639,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);
@@ -1651,10 +1712,10 @@ 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;
                     }
-                        
+
                     get_reloc_expr(name, sizeof(name), sym_name);
                     addend = get32((uint32_t *)(text + rel->r_offset));
 #ifdef CONFIG_FORMAT_ELF
@@ -1662,11 +1723,11 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                     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);
@@ -1689,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);
@@ -1709,6 +1770,7 @@ 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) {
@@ -1716,18 +1778,19 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                     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 X86_64 relocation (%d)", type);
@@ -1741,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);
@@ -1753,7 +1818,7 @@ 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;
                         }
                         
@@ -1763,24 +1828,24 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                         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);
@@ -1882,6 +1947,7 @@ 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) {
@@ -1889,18 +1955,19 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                         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,31 +2033,85 @@ 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;
-                        get_reloc_expr(name, sizeof(name), 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) {
@@ -1996,10 +2119,11 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                         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,
@@ -2007,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,
@@ -2017,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,
@@ -2028,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);
@@ -2044,6 +2162,7 @@ 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) {
@@ -2051,10 +2170,11 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                         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,
@@ -2062,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,
@@ -2072,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,
@@ -2083,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);
@@ -2099,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);
@@ -2113,14 +2228,15 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                     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);
@@ -2133,6 +2249,7 @@ 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 &&
@@ -2142,16 +2259,17 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                     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);
@@ -2236,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"
@@ -2298,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