Hello,

Let us see "jal R_MIPS_26":
in current CVS version, op.o, -fno-PIC -mno-abicalls
004eb0d4 <op_divb_AL_T0>:
...
 4eb104: afa50010 sw a1,16(sp)
 4eb108: 14600003 bnez v1,4eb118 <op_divb_AL_T0+0x44>
 4eb10c: 00000000 nop
 4eb110: 0c140e12 jal 503848 <raise_exception>
 4eb114: 00000000 nop
 4eb118: 8fa30010 lw v1,16(sp)
 4eb11c: 00002021 move a0,zero

helper.o, PIC and abicalls
00503848 <raise_exception>:
 503848: 3c1c000c lui gp,0xc
 50384c: 279c0858 addiu gp,gp,2136
 503850: 0399e021 addu gp,gp,t9
 503854: 8f998db8 lw t9,-29256(gp)
 503858: 00002821 move a1,zero
 50385c: 00003021 move a2,zero
 503860: 03200008 jr t9
 503864: 00003821 move a3,zero


When calling PIC/abicalls functions, $25 must contain the address of
the called function. But, At 0x503850, I guess $25 is not
&raise_exception, but &gen_func.

Therefore, before call raise_exception, we must seved the address of
raise_exception into $25. In other words, we must use R_MIPS_HI16 /
R_MIPS_LO16 instead of R_MIPS_26. op_mips.c can take care of this. I
tested it with qemu-0.6.1 and qemu-0.9.0 on loongson + linux.
diff -Nurb qemu-cvs/Makefile qemu-loongson/Makefile
--- qemu-cvs/Makefile   2007-05-20 18:54:50.000000000 +0800
+++ qemu-loongson/Makefile      2007-06-12 22:24:06.000000000 +0800
@@ -25,8 +25,15 @@
 
 LIBS+=$(AIOLIBS)
 
+ifeq ($(ARCH),mips)
+subdir-%: dyngen$(EXESUF) op_mips$(EXESUF)
+       $(MAKE) -C $(subst subdir-,,$@) all
+
+else
 all: $(TOOLS) $(DOCS) recurse-all
 
+endif
+
 subdir-%: dyngen$(EXESUF)
        $(MAKE) -C $(subst subdir-,,$@) all
 
@@ -38,10 +45,16 @@
 dyngen$(EXESUF): dyngen.c
        $(HOST_CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -o $@ $^
 
+ifeq ($(ARCH),mips)
+op_mips$(EXESUF): op_mips.c
+       $(HOST_CC) $(CFLAGS) $(DEFINES) -o $@ $^
+
+endif
+
 clean:
 # avoid old build problems by removing potentially incorrect old files
        rm -f config.mak config.h op-i386.h opc-i386.h gen-op-i386.h op-arm.h 
opc-arm.h gen-op-arm.h 
-       rm -f *.o *.a $(TOOLS) dyngen$(EXESUF) TAGS *.pod *~ */*~
+       rm -f *.o *.a $(TOOLS) dyngen$(EXESUF) op_mips$(EXESUF) TAGS *.pod *~ 
*/*~
        $(MAKE) -C tests clean
        for d in $(TARGET_DIRS); do \
        $(MAKE) -C $$d $@ || exit 1 ; \
diff -Nurb qemu-cvs/Makefile.target qemu-loongson/Makefile.target
--- qemu-cvs/Makefile.target    2007-06-12 22:20:44.000000000 +0800
+++ qemu-loongson/Makefile.target       2007-06-12 22:27:54.000000000 +0800
@@ -33,6 +33,7 @@
 LIBS=
 HELPER_CFLAGS=$(CFLAGS)
 DYNGEN=../dyngen$(EXESUF)
+OP_MIPS=../op_mips$(EXESUF)
 # user emulator name
 TARGET_ARCH2=$(TARGET_ARCH)
 ifeq ($(TARGET_ARCH),arm)
@@ -571,9 +572,22 @@
 gen-op.h: op.o $(DYNGEN)
        $(DYNGEN) -g -o $@ $<
 
+ifeq ($(ARCH),mips)
+op.o: op2.s
+       $(CC) $(OP_CFLAGS) $(CPPFLAGS) -c -o $@ $<
+
+op2.s: op.s $(OP_MIPS)
+       $(OP_MIPS) < $< > $@
+
+op.s: op.c
+       $(CC) $(OP_CFLAGS) $(CPPFLAGS) -S -o $@ $<
+
+else
 op.o: op.c
        $(CC) $(OP_CFLAGS) $(CPPFLAGS) -c -o $@ $<
 
+endif
+
 # HELPER_CFLAGS is used for all the code compiled with static register
 # variables
 ifeq ($(TARGET_BASE_ARCH), i386)
diff -Nurb qemu-cvs/dyngen.c qemu-loongson/dyngen.c
--- qemu-cvs/dyngen.c   2007-05-09 06:51:41.000000000 +0800
+++ qemu-loongson/dyngen.c      2007-06-12 22:24:06.000000000 +0800
@@ -2537,16 +2537,6 @@
                         addend = get32((uint32_t *)(text + rel->r_offset));
                         reloc_offset = rel->r_offset - start_offset;
                        switch (type) {
-                       case R_MIPS_26:
-                            fprintf(outfile, "    /* R_MIPS_26 RELOC, offset 
0x%x, name %s */\n",
-                                   rel->r_offset, sym_name);
-                            fprintf(outfile,
-                                   "    *(uint32_t *)(gen_code_ptr + 0x%x) = "
-                                   "(0x%x & ~0x3fffff) "
-                                   "| ((0x%x + ((%s - (*(uint32_t 
*)(gen_code_ptr + 0x%x))) >> 2)) "
-                                   "   & 0x3fffff);\n",
-                                    reloc_offset, addend, addend, name, 
reloc_offset);
-                           break;
                        case R_MIPS_HI16:
                             fprintf(outfile, "    /* R_MIPS_HI16 RELOC, offset 
0x%x, name %s */\n",
                                    rel->r_offset, sym_name);
@@ -2554,7 +2544,7 @@
                                    "    *(uint32_t *)(gen_code_ptr + 0x%x) = "
                                    "((*(uint32_t *)(gen_code_ptr + 0x%x)) "
                                    " & ~0xffff) "
-                                   " | (((%s - 0x8000) >> 16) & 0xffff);\n",
+                                   " | (((%s + 0x8000) >> 16) & 0xffff);\n",
                                     reloc_offset, reloc_offset, name);
                            break;
                        case R_MIPS_LO16:
@@ -2567,27 +2557,6 @@
                                    " | (%s & 0xffff);\n",
                                     reloc_offset, reloc_offset, name);
                            break;
-                       case R_MIPS_PC16:
-                            fprintf(outfile, "    /* R_MIPS_PC16 RELOC, offset 
0x%x, name %s */\n",
-                                   rel->r_offset, sym_name);
-                            fprintf(outfile,
-                                   "    *(uint32_t *)(gen_code_ptr + 0x%x) = "
-                                   "(0x%x & ~0xffff) "
-                                   "| ((0x%x + ((%s - (*(uint32_t 
*)(gen_code_ptr + 0x%x))) >> 2)) "
-                                   "   & 0xffff);\n",
-                                    reloc_offset, addend, addend, name, 
reloc_offset);
-                           break;
-                       case R_MIPS_GOT16:
-                       case R_MIPS_CALL16:
-                            fprintf(outfile, "    /* R_MIPS_GOT16 RELOC, 
offset 0x%x, name %s */\n",
-                                   rel->r_offset, sym_name);
-                            fprintf(outfile,
-                                   "    *(uint32_t *)(gen_code_ptr + 0x%x) = "
-                                   "((*(uint32_t *)(gen_code_ptr + 0x%x)) "
-                                   " & ~0xffff) "
-                                   " | (((%s - 0x8000) >> 16) & 0xffff);\n",
-                                    reloc_offset, reloc_offset, name);
-                           break;
                        default:
                            error("unsupported MIPS relocation (%d)", type);
                        }
diff -Nurb qemu-cvs/op_mips.c qemu-loongson/op_mips.c
--- qemu-cvs/op_mips.c  1970-01-01 08:00:00.000000000 +0800
+++ qemu-loongson/op_mips.c     2007-06-12 22:24:06.000000000 +0800
@@ -0,0 +1,160 @@
+/*     qemu/op_mips.c
+ *
+ *                     Peng Jun <[EMAIL PROTECTED]>
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define        GCC_MNO_ABICALLS        // faster
+//#define      QEMU_VERSION_6
+
+#ifdef QEMU_VERSION_6
+int exit_tb_key = 0;
+char exit_tb_buf[1024];
+char exit_tb_sp[1024];
+
+int line2(char *buf, int num)
+{
+       if(strcmp(buf, "\tj\t$31\n") != 0) {
+               strcat(exit_tb_buf, buf);
+               if(strstr(buf, "$sp"))
+                       strcat(exit_tb_sp, buf);
+               strcpy(buf, "");
+               return 0;
+       }
+
+       sprintf(buf, "\
+#EXIT_TB\n\
+%s\
+       j       $31\n\
+       nop\n\
+%s\
+$end_%08X:\n\
+       j       $31\n\
+",
+               exit_tb_sp, exit_tb_buf, num);
+
+       exit_tb_key = 0;
+
+       return 0;
+}
+#endif /* QEMU_VERSION_6 */
+
+int line(char *buf, int num)
+{
+       char func[256];
+
+#ifdef QEMU_VERSION_6
+       // exit_tb
+       if(strcmp(buf, "#EXIT_TB\n") == 0) {
+               exit_tb_key = 1;
+               strcpy(buf, "");
+               strcpy(exit_tb_buf, "");
+               strcpy(exit_tb_sp, "");
+               return 0;
+       }
+#endif
+
+       // j $31  --> end_XXX: j $31
+       if(strcmp(buf, "\tj\t$31\n") == 0) {
+               sprintf(buf, "\
+$end_%08X:\n\
+       j       $31\n\
+", num);
+                       return 0;
+       }
+
+#ifdef GCC_MNO_ABICALLS
+
+#ifdef QEMU_VERSION_6
+       if(strcmp(buf, "\tjal\t$2\n") == 0) {
+               return 0;
+       }
+#else
+       // jal $2  -->  jal $t9  (0.9.0)
+       if(strcmp(buf, "\tjal\t$2\n") == 0) {
+               sprintf(buf, "\
+       move    $25,$2\n\
+       jal     $25\n\
+"
+               );
+               return 0;
+       }
+#endif /* QEMU_VERSION_6 */
+
+       // jal func  --> lui + addiu
+       if(strncmp(buf, "\tjal\t", 5) == 0) {
+               *(strchr(buf, '\n')) = 0;
+               strcpy(func, buf + 5);
+               sprintf(buf, "\
+       lui     $25,%%hi(%s)\n\
+       addiu   $25,$25,%%lo(%s)\n\
+       jal     $25\n\
+",
+                               func, func);
+               return 0;
+       }
+
+#else  /* GCC_MNO_ABICALLS */
+
+       { char *p, reg[4];
+       // lw $?,%got(var)($28)  -->  lui + addiu
+       if(strstr(buf, "%got")) {
+               if(strncmp(buf, "\tlw\t$", 5))
+                       exit(1);
+               p = buf + 4;
+               *strchr(p, ',') = 0;
+               strcpy(reg, p);
+               p = p + strlen(reg) + 1;
+               p = strchr(p, '(') + 1;
+               *strchr(p, ')') = 0;
+               strcpy(func, p);
+               sprintf(buf, "\
+       lui     %s,%%hi(%s)\n\
+       addiu   %s,%s,%%lo(%s)\n\
+",
+                               reg, func, reg, reg, func);
+               return 0;
+       }
+
+       // lw $25,%call16(func)($28)  -->  lui + addiu
+       if(strstr(buf, "%call16")) {
+               if(strncmp(buf, "\tlw\t$25,%call16", 15))
+                       exit(1);
+               p = strchr(buf, '(') + 1;
+               *strchr(p, ')') = 0;
+               strcpy(func, p);
+               sprintf(buf, "\
+       lui     $25,%%hi(%s)\n\
+       addiu   $25,$25,%%lo(%s)\n\
+",
+                               func, func);
+               return 0;
+       }
+       }
+
+#endif /* GCC_MNO_ABICALLS */
+
+       return 0;
+}
+
+int main(int argc, char *argv[])
+{
+       char buf[1024];
+       int n = 0;
+
+       while(fgets(buf, 1023, stdin)) {
+#ifdef QEMU_VERSION_6
+               if(exit_tb_key)
+                       line2(buf, n);
+               else
+#endif
+                       line(buf, n);
+               printf("%s", buf);
+               n++;
+       }
+       return 0;
+}

Reply via email to