]> git.proxmox.com Git - qemu.git/blobdiff - dyngen.c
added getrusage
[qemu.git] / dyngen.c
index 66f735bee3cc5ec8c5b75df7d5484f9af2a7151a..f037d87590d2b1e3fc1bd28cfb6de5323c791ca3 100644 (file)
--- a/dyngen.c
+++ b/dyngen.c
 #define elf_check_arch(x) ((x) == EM_IA_64)
 #define ELF_USES_RELOCA
 
+#elif defined(HOST_SPARC)
+
+#define ELF_CLASS      ELFCLASS32
+#define ELF_ARCH       EM_SPARC
+#define elf_check_arch(x) ((x) == EM_SPARC || (x) == EM_SPARC32PLUS)
+#define ELF_USES_RELOCA
+
+#elif defined(HOST_SPARC64)
+
+#define ELF_CLASS      ELFCLASS64
+#define ELF_ARCH       EM_SPARCV9
+#define elf_check_arch(x) ((x) == EM_SPARCV9)
+#define ELF_USES_RELOCA
+
 #else
 #error unsupported CPU - please update the code
 #endif
@@ -260,14 +274,20 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
 {
     int copy_size = 0;
     uint8_t *p_start, *p_end;
+    host_ulong start_offset;
     int nb_args, i, n;
     uint8_t args_present[MAX_ARGS];
     const char *sym_name, *p;
     ELF_RELOC *rel;
 
-    /* compute exact size excluding return instruction */
+    /* Compute exact size excluding prologue and epilogue instructions.
+     * Increment start_offset to skip epilogue instructions, then compute
+     * copy_size the indicate the size of the remaining instructions (in
+     * bytes).
+     */
     p_start = text + offset;
     p_end = p_start + size;
+    start_offset = offset;
     switch(ELF_ARCH) {
     case EM_386:
         {
@@ -326,6 +346,69 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
             copy_size = p - p_start;
        }
         break;
+    case EM_SPARC:
+    case EM_SPARC32PLUS:
+       {
+           uint32_t start_insn, end_insn1, end_insn2, skip_insn;
+            uint8_t *p;
+            p = (void *)(p_end - 8);
+            if (p <= p_start)
+                error("empty code for %s", name);
+           start_insn = get32((uint32_t *)(p_start + 0x0));
+           end_insn1 = get32((uint32_t *)(p + 0x0));
+           end_insn2 = get32((uint32_t *)(p + 0x4));
+           if ((start_insn & ~0x1fff) == 0x9de3a000) {
+               p_start += 0x4;
+               start_offset += 0x4;
+               if ((int)(start_insn | ~0x1fff) < -128)
+                   error("Found bogus save at the start of %s", name);
+               if (end_insn1 != 0x81c7e008 || end_insn2 != 0x81e80000)
+                   error("ret; restore; not found at end of %s", name);
+           } else {
+               error("No save at the beginning of %s", name);
+           }
+
+           /* Skip a preceeding nop, if present.  */
+           if (p > p_start) {
+               skip_insn = get32((uint32_t *)(p - 0x4));
+               if (skip_insn == 0x01000000)
+                   p -= 4;
+           }
+
+            copy_size = p - p_start;
+       }
+       break;
+    case EM_SPARCV9:
+       {
+           uint32_t start_insn, end_insn1, end_insn2, skip_insn;
+            uint8_t *p;
+            p = (void *)(p_end - 8);
+            if (p <= p_start)
+                error("empty code for %s", name);
+           start_insn = get32((uint32_t *)(p_start + 0x0));
+           end_insn1 = get32((uint32_t *)(p + 0x0));
+           end_insn2 = get32((uint32_t *)(p + 0x4));
+           if ((start_insn & ~0x1fff) == 0x9de3a000) {
+               p_start += 0x4;
+               start_offset += 0x4;
+               if ((int)(start_insn | ~0x1fff) < -256)
+                   error("Found bogus save at the start of %s", name);
+               if (end_insn1 != 0x81c7e008 || end_insn2 != 0x81e80000)
+                   error("ret; restore; not found at end of %s", name);
+           } else {
+               error("No save at the beginning of %s", name);
+           }
+
+           /* Skip a preceeding nop, if present.  */
+           if (p > p_start) {
+               skip_insn = get32((uint32_t *)(p - 0x4));
+               if (skip_insn == 0x01000000)
+                   p -= 4;
+           }
+
+            copy_size = p - p_start;
+       }
+       break;
     default:
        error("unknown ELF architecture");
     }
@@ -335,7 +418,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
         args_present[i] = 0;
 
     for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
-        if (rel->r_offset >= offset && rel->r_offset < offset + copy_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_param", &p)) {
                 n = strtoul(p, NULL, 10);
@@ -372,15 +456,24 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
         fprintf(outfile, "    extern void %s();\n", name);
 
         for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
-            if (rel->r_offset >= offset && rel->r_offset < offset + copy_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_param", &p)) {
+                if (*sym_name && !strstart(sym_name, "__op_param", &p)) {
+#if defined(HOST_SPARC)
+                   if (sym_name[0] == '.') {
+                       fprintf(outfile,
+                               "extern char __dot_%s __asm__(\"%s\");\n",
+                               sym_name+1, sym_name);
+                       continue;
+                   }
+#endif
                     fprintf(outfile, "extern char %s;\n", sym_name);
                 }
             }
         }
 
-        fprintf(outfile, "    memcpy(gen_code_ptr, &%s, %d);\n", name, copy_size);
+        fprintf(outfile, "    memcpy(gen_code_ptr, (void *)((char *)&%s+%d), %d);\n", name, start_offset - offset, copy_size);
         for(i = 0; i < nb_args; i++) {
             fprintf(outfile, "    param%d = *opparam_ptr++;\n", i + 1);
         }
@@ -392,7 +485,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                 int type;
                 int addend;
                 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
-                if (rel->r_offset >= offset && rel->r_offset < offset + copy_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_param", &p)) {
                         snprintf(name, sizeof(name), "param%s", p);
@@ -404,11 +498,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 - offset, name, addend);
+                                rel->r_offset - start_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 - offset, name, rel->r_offset - offset, addend);
+                                rel->r_offset - start_offset, name, rel->r_offset - start_offset, addend);
                         break;
                     default:
                         error("unsupported i386 relocation (%d)", type);
@@ -422,7 +516,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                 int type;
                 int addend;
                 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
-                    if (rel->r_offset >= offset && rel->r_offset < offset + copy_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_param", &p)) {
                             snprintf(name, sizeof(name), "param%s", p);
@@ -434,24 +529,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 - offset, name, addend);
+                                    rel->r_offset - start_offset, name, addend);
                             break;
                         case R_PPC_ADDR16_LO:
                             fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d) = (%s + %d);\n", 
-                                    rel->r_offset - offset, name, addend);
+                                    rel->r_offset - start_offset, name, addend);
                             break;
                         case R_PPC_ADDR16_HI:
                             fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d) = (%s + %d) >> 16;\n", 
-                                    rel->r_offset - offset, name, addend);
+                                    rel->r_offset - start_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 - offset, name, addend);
+                                    rel->r_offset - start_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 - offset, rel->r_offset - offset, name, rel->r_offset - offset, addend);
+                                    rel->r_offset - start_offset, rel->r_offset - start_offset, name, rel->r_offset - start_offset, addend);
                             break;
                         default:
                             error("unsupported powerpc relocation (%d)", type);
@@ -465,7 +560,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                 int type;
                 int addend;
                 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
-                    if (rel->r_offset >= offset && rel->r_offset < offset + copy_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_param", &p)) {
                             snprintf(name, sizeof(name), "param%s", p);
@@ -477,15 +573,15 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                         switch(type) {
                         case R_390_32:
                             fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", 
-                                    rel->r_offset - offset, name, addend);
+                                    rel->r_offset - start_offset, name, addend);
                             break;
                         case R_390_16:
                             fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d) = %s + %d;\n", 
-                                    rel->r_offset - offset, name, addend);
+                                    rel->r_offset - start_offset, name, addend);
                             break;
                         case R_390_8:
                             fprintf(outfile, "    *(uint8_t *)(gen_code_ptr + %d) = %s + %d;\n", 
-                                    rel->r_offset - offset, name, addend);
+                                    rel->r_offset - start_offset, name, addend);
                             break;
                         default:
                             error("unsupported s390 relocation (%d)", type);
@@ -496,17 +592,19 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
 #elif defined(HOST_ALPHA)
             {
                 for (i = 0, rel = relocs; i < nb_relocs; i++, rel++) {
-                   if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
+                   if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) {
                        int type;
-                       sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name;
-                       
+
                        type = ELF64_R_TYPE(rel->r_info);
+                       sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name;
                        switch (type) {
                        case R_ALPHA_GPDISP:
-                           /* Instructions to set up the gp can be nopped, since we keep it current
-                              all the time.  FIXME assert that target is really gp  */
-                           fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = 0x2ffe0000; /* unop */\n",
-                                   rel->r_offset - offset);
+                           /* 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);
+                           fprintf(outfile, "    immediate_lda(gen_code_ptr + %ld, gp);\n",
+                                   rel->r_offset - start_offset + rel->r_addend);
                            break;
                        case R_ALPHA_LITUSE:
                            /* jsr to literal hint. Could be used to optimize to bsr. Ignore for
@@ -517,10 +615,27 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                               correct for in-function jumps.  */
                            break;
                        case R_ALPHA_LITERAL:
-                           /* Load a literal from the GOT relative to the gp.  Need to patch the
-                              16-bit immediate offset.  */
-                           fprintf(outfile, "    *(int16_t *)(gen_code_ptr + %d) = gp - (long)(&%s);\n",
-                                   rel->r_offset - offset, name);
+                           /* Load a literal from the GOT relative to the gp.  Since there's only a
+                              single gp, nothing is to be done.  */
+                           break;
+                       case R_ALPHA_GPRELHIGH:
+                           /* Handle fake relocations against __op_param symbol.  Need to emit the
+                              high part of the immediate value instead.  Other symbols need no
+                              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);
+                           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);
+                           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);\n",
+                                   rel->r_offset - start_offset, sym_name, rel->r_offset - start_offset);
                            break;
                        default:
                            error("unsupported Alpha relocation (%d)", type);
@@ -534,7 +649,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                 int type;
                 int addend;
                 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
-                    if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
+                    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);
@@ -554,6 +669,130 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
                     }
                 }
             }
+#elif defined(HOST_SPARC)
+            {
+                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[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);
+                        }
+                        type = ELF32_R_TYPE(rel->r_info);
+                        addend = rel->r_addend;
+                        switch(type) {
+                        case R_SPARC_32:
+                            fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", 
+                                    rel->r_offset - start_offset, name, addend);
+                           break;
+                       case R_SPARC_HI22:
+                            fprintf(outfile,
+                                   "    *(uint32_t *)(gen_code_ptr + %d) = "
+                                   "((*(uint32_t *)(gen_code_ptr + %d)) "
+                                   " & ~0x3fffff) "
+                                   " | (((%s + %d) >> 10) & 0x3fffff);\n",
+                                    rel->r_offset - start_offset,
+                                   rel->r_offset - start_offset,
+                                   name, addend);
+                           break;
+                       case R_SPARC_LO10:
+                            fprintf(outfile,
+                                   "    *(uint32_t *)(gen_code_ptr + %d) = "
+                                   "((*(uint32_t *)(gen_code_ptr + %d)) "
+                                   " & ~0x3ff) "
+                                   " | ((%s + %d) & 0x3ff);\n",
+                                    rel->r_offset - start_offset,
+                                   rel->r_offset - start_offset,
+                                   name, addend);
+                           break;
+                       case R_SPARC_WDISP30:
+                           fprintf(outfile,
+                                   "    *(uint32_t *)(gen_code_ptr + %d) = "
+                                   "((*(uint32_t *)(gen_code_ptr + %d)) "
+                                   " & ~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);
+                           break;
+                        default:
+                            error("unsupported sparc relocation (%d)", type);
+                        }
+                    }
+                }
+            }
+#elif defined(HOST_SPARC64)
+            {
+                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[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_SPARC_32:
+                            fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
+                                    rel->r_offset - start_offset, name, addend);
+                           break;
+                       case R_SPARC_HI22:
+                            fprintf(outfile,
+                                   "    *(uint32_t *)(gen_code_ptr + %d) = "
+                                   "((*(uint32_t *)(gen_code_ptr + %d)) "
+                                   " & ~0x3fffff) "
+                                   " | (((%s + %d) >> 10) & 0x3fffff);\n",
+                                    rel->r_offset - start_offset,
+                                   rel->r_offset - start_offset,
+                                   name, addend);
+                           break;
+                       case R_SPARC_LO10:
+                            fprintf(outfile,
+                                   "    *(uint32_t *)(gen_code_ptr + %d) = "
+                                   "((*(uint32_t *)(gen_code_ptr + %d)) "
+                                   " & ~0x3ff) "
+                                   " | ((%s + %d) & 0x3ff);\n",
+                                    rel->r_offset - start_offset,
+                                   rel->r_offset - start_offset,
+                                   name, addend);
+                           break;
+                       case R_SPARC_WDISP30:
+                           fprintf(outfile,
+                                   "    *(uint32_t *)(gen_code_ptr + %d) = "
+                                   "((*(uint32_t *)(gen_code_ptr + %d)) "
+                                   " & ~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);
+                           break;
+                        default:
+                           error("unsupported sparc64 relocation (%d)", type);
+                        }
+                    }
+                }
+            }
 #else
 #error unsupported CPU
 #endif
@@ -703,7 +942,24 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum)
     } else {
         /* generate big code generation switch */
 #ifdef HOST_ALPHA
-       fprintf(outfile, "register long gp asm(\"%%$29\");\n");
+fprintf(outfile,
+"register int gp asm(\"$29\");\n"
+"static inline void immediate_ldah(void *p, int val) {\n"
+"    uint32_t *dest = p;\n"
+"    long high = ((val >> 16) + ((val >> 15) & 1)) & 0xffff;\n"
+"\n"
+"    *dest &= ~0xffff;\n"
+"    *dest |= high;\n"
+"    *dest |= 31 << 16;\n"
+"}\n"
+"static inline void immediate_lda(void *dest, int val) {\n"
+"    *(uint16_t *) dest = val;\n"
+"}\n"
+"void fix_bsr(void *p, int offset) {\n"
+"    uint32_t *dest = p;\n"
+"    *dest &= ~((1 << 21) - 1);\n"
+"    *dest |= (offset >> 2) & ((1 << 21) - 1);\n"
+"}\n");
 #endif
 fprintf(outfile,
 "int dyngen_code(uint8_t *gen_code_buf,\n"
@@ -714,7 +970,22 @@ fprintf(outfile,
 "    const uint32_t *opparam_ptr;\n"
 "    gen_code_ptr = gen_code_buf;\n"
 "    opc_ptr = opc_buf;\n"
-"    opparam_ptr = opparam_buf;\n"
+"    opparam_ptr = opparam_buf;\n");
+
+       /* Generate prologue, if needed. */ 
+       switch(ELF_ARCH) {
+       case EM_SPARC:
+               fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x9c23a080; /* sub %%sp, 128, %%sp */\n");
+               fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0xbc27a080; /* sub %%fp, 128, %%fp */\n");
+               break;
+
+       case EM_SPARCV9:
+               fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x9c23a100; /* sub %%sp, 256, %%sp */\n");
+               fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0xbc27a100; /* sub %%fp, 256, %%fp */\n");
+               break;
+       };
+
+fprintf(outfile,
 "    for(;;) {\n"
 "        switch(*opc_ptr++) {\n"
 );
@@ -742,7 +1013,7 @@ fprintf(outfile,
 " the_end:\n"
 );
 
-/* generate a return */ 
+/* generate epilogue */ 
     switch(ELF_ARCH) {
     case EM_386:
         fprintf(outfile, "*gen_code_ptr++ = 0xc3; /* ret */\n");
@@ -759,6 +1030,16 @@ fprintf(outfile,
     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)++ = 0xbc07a080; /* add %%fp, 256, %%fp */\n");
+       fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x81c62008; /* jmpl %%i0 + 8, %%g0 */\n");
+       fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x9c03a080; /* add %%sp, 256, %%sp */\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;
     default:
        error("unknown ELF architecture");
     }