Support new risc-v calling convention
authorAndrew Waterman <waterman@cs.berkeley.edu>
Mon, 22 Apr 2013 22:05:08 +0000 (15:05 -0700)
committerAndrew Waterman <waterman@cs.berkeley.edu>
Mon, 22 Apr 2013 22:14:26 +0000 (15:14 -0700)
12 files changed:
kern/arch/riscv/boot.S
kern/arch/riscv/entry.S
kern/arch/riscv/process.c
kern/arch/riscv/riscv.h
kern/arch/riscv/ros/trapframe.h
kern/arch/riscv/trap.c
tools/compilers/gcc-glibc/binutils-2.21.1-riscv.patch
tools/compilers/gcc-glibc/gcc-4.6.1-riscv.patch
tools/compilers/gcc-glibc/gcc-4.6.1-ros.patch [new file with mode: 0644]
tools/compilers/gcc-glibc/glibc-2.14.1-riscv.patch
user/parlib/include/riscv/vcore.h
user/parlib/riscv/vcore.S

index c182f7b..2a8ccb4 100644 (file)
@@ -25,23 +25,23 @@ _start:
 
   // set up trap entry point.  this is not a relocated address, as we
   // do not support trapping before the MMU is set up.
-  la     t0, trap_entry
-  mtpcr  t0, ASM_CR(PCR_EVEC)
+  la     a6, trap_entry
+  mtpcr  a6, ASM_CR(PCR_EVEC)
 
   // clear IPIs and enable traps
   mtpcr  zero, ASM_CR(PCR_CLR_IPI)
-  li     t0, PCR0
-  mtpcr  t0, ASM_CR(PCR_SR)
+  li     a6, PCR0
+  mtpcr  a6, ASM_CR(PCR_SR)
 
   // core 0?
-  mfpcr  t0, ASM_CR(PCR_COREID)
-  bnez   t0, notcore0
+  mfpcr  a6, ASM_CR(PCR_COREID)
+  bnez   a6, notcore0
 
   // terminate frame pointer for backtracing and set up stack
   li     s9, 0
   la     sp, percore_stacks + KSTKSIZE
-  li     t1, KERN_LOAD_ADDR
-  sub    sp, sp, t1
+  li     a7, KERN_LOAD_ADDR
+  sub    sp, sp, a7
 
   // get memory size and core count from first two words of memory
   lw     s0, 0(zero)
@@ -50,12 +50,12 @@ _start:
   // set up initial page mappings
   move   a0, s0
   la     a1, l1pt
-  sub    a1, a1, t1
+  sub    a1, a1, a7
   la     a2, l1pt_boot
-  sub    a2, a2, t1
+  sub    a2, a2, a7
 #ifdef __riscv64
   la     a3, l2pt
-  sub    a3, a3, t1
+  sub    a3, a3, a7
 #endif
   jal    pagetable_init
   jal    enable_mmu
@@ -64,43 +64,43 @@ _start:
   move   a0, s0
   move   a1, s1
   la     sp, percore_stacks + KSTKSIZE
-  la     t0, cmain
-  jr     t0
+  la     a6, cmain
+  jr     a6
 
 notcore0:
   // wait for core 0 to boot
-  la     t2, num_cpus_booted - KERN_LOAD_ADDR
-1:lw     t3, 0(t2)
-  beqz   t3, 1b
+  la     a8, num_cpus_booted - KERN_LOAD_ADDR
+1:lw     a9, 0(a8)
+  beqz   a9, 1b
 
   // if for some reason coreid >= num_cpus, don't boot this core
-  la     t2, num_cpus - KERN_LOAD_ADDR
-  lw     t2, 0(t2)
-1:bgeu   t0, t2, 1b
+  la     a8, num_cpus - KERN_LOAD_ADDR
+  lw     a8, 0(a8)
+1:bgeu   a6, a8, 1b
 
   // set up stack: sp = percoore_stacks+(core_id()+1)*KSTKSIZE
   la     sp, percore_stacks
-  add    t0, t0, 1
-  sll    t0, t0, KSTKSHIFT
-  add    sp, sp, t0
-  li     t1, KERN_LOAD_ADDR
-  sub    sp, sp, t1
+  add    a6, a6, 1
+  sll    a6, a6, KSTKSHIFT
+  add    sp, sp, a6
+  li     a7, KERN_LOAD_ADDR
+  sub    sp, sp, a7
   
   jal    enable_mmu
 
   // relocate stack and call into C code
-  li     t1, KERN_LOAD_ADDR
-  add    sp, sp, t1
-  la     t0, smp_init
-  jr     t0
+  li     a7, KERN_LOAD_ADDR
+  add    sp, sp, a7
+  la     a6, smp_init
+  jr     a6
 
 enable_mmu:
-  la     t0, l1pt_boot
-  li     t1, KERN_LOAD_ADDR
-  sub    t0, t0, t1
-  mtpcr  t0, ASM_CR(PCR_PTBR)
-  li     t0, PCR0 | SR_VM
-  mtpcr  t0, ASM_CR(PCR_SR)
+  la     a6, l1pt_boot
+  li     a7, KERN_LOAD_ADDR
+  sub    a6, a6, a7
+  mtpcr  a6, ASM_CR(PCR_PTBR)
+  li     a6, PCR0 | SR_VM
+  mtpcr  a6, ASM_CR(PCR_SR)
   ret
 
 ///////////////////////////////////////////////////////////////////
index 46f1421..6e610c5 100644 (file)
@@ -16,6 +16,8 @@
   .text
   .global save_kernel_tf_asm
 save_kernel_tf_asm:
+  mfpcr  a1,ASM_CR(PCR_SR)
+
   STORE  s0,20*REGBYTES(a0)
   STORE  s1,21*REGBYTES(a0)
   STORE  s2,22*REGBYTES(a0)
@@ -28,8 +30,7 @@ save_kernel_tf_asm:
   STORE  s9,29*REGBYTES(a0)
   STORE  sp,30*REGBYTES(a0)
 
-  mfpcr  t0,ASM_CR(PCR_SR)
-  STORE  t0,32*REGBYTES(a0)
+  STORE  a1,32*REGBYTES(a0)
 
   # set EPC to this function's return address
   STORE  ra,33*REGBYTES(a0)
@@ -38,7 +39,7 @@ save_kernel_tf_asm:
   .text
   .global pop_kernel_ctx
 pop_kernel_ctx:
-  LOAD  t0,32*REGBYTES(a0)
+  LOAD  a1,32*REGBYTES(a0)
   LOAD  ra,33*REGBYTES(a0)
 
   LOAD  s0,20*REGBYTES(a0)
@@ -53,7 +54,7 @@ pop_kernel_ctx:
   LOAD  s9,29*REGBYTES(a0)
   LOAD  sp,30*REGBYTES(a0)
 
-  mtpcr  t0,ASM_CR(PCR_SR)
+  mtpcr  a1,ASM_CR(PCR_SR)
   ret
 
 
@@ -64,12 +65,12 @@ save_tf:  # write the trap frame onto the stack
   .globl  env_pop_tf
 env_pop_tf:  # write the trap frame onto the stack
   # restore gprs
-  LOAD  t0,32*REGBYTES(a0)  # restore sr (should disable interrupts)
-  mfpcr t1, ASM_CR(PCR_SR)
-  andi  t1, t1, ~(SR_PS | SR_EF | SR_U64)
-  andi  t0, t0, SR_PS | SR_EF | SR_U64
-  or    t0, t0, t1
-  mtpcr t0, ASM_CR(PCR_SR)
+  LOAD  v0,32*REGBYTES(a0)  # restore sr (should disable interrupts)
+  mfpcr v1, ASM_CR(PCR_SR)
+  andi  v1, v1, ~(SR_PS | SR_EF | SR_U64)
+  andi  v0, v0, SR_PS | SR_EF | SR_U64
+  or    v0, v0, v1
+  mtpcr v0, ASM_CR(PCR_SR)
 
   LOAD  x1,1*REGBYTES(a0)
   mtpcr  x1,ASM_CR(PCR_K0)
@@ -115,32 +116,34 @@ env_pop_tf:  # write the trap frame onto the stack
 
   .global  trap_entry
 trap_entry:
-  # save x1 and x2 so we can use them as temporaries
-  mtpcr x1, ASM_CR(PCR_K0)
-  mtpcr x2, ASM_CR(PCR_K1)
-
-  # when coming from kernel, continue below its stack
+  mtpcr x1, ASM_CR(PCR_K0)  # stash x1 in k0
   mfpcr x1, ASM_CR(PCR_SR)
-  and   x1, x1, SR_PS
+  mtpcr x2, ASM_CR(PCR_K1)  # stash x2 in k1
+  # when coming from kernel, continue below its stack
   add   x2, sp, -SIZEOF_HW_TRAPFRAME
+  and   x1, x1, SR_PS
   bnez  x1, 1f
 
   # otherwise, start at the top of the per-core stack
-  la    x2, core_stacktops
   mfpcr x1, ASM_CR(PCR_COREID)
+  lui  x2, %hi(core_stacktops)
   sll   x1, x1, LOG_REGBYTES
   add   x2, x2, x1
-  LOAD  x2, 0(x2)
+  LOAD  x2, %lo(core_stacktops)(x2)
   add   x2, x2, -SIZEOF_HW_TRAPFRAME
 
 1:# save gprs
   STORE  x3,3*REGBYTES(x2)
   STORE  x4,4*REGBYTES(x2)
+  mfpcr  x3,ASM_CR(PCR_K0)    # retrieve x1
+  mfpcr  x4,ASM_CR(PCR_K1)    # retrieve x2
   STORE  x5,5*REGBYTES(x2)
   STORE  x6,6*REGBYTES(x2)
   STORE  x7,7*REGBYTES(x2)
   STORE  x8,8*REGBYTES(x2)
   STORE  x9,9*REGBYTES(x2)
+  STORE  x3,1*REGBYTES(x2)    # save x1
+  STORE  x4,2*REGBYTES(x2)    # save x2
   STORE  x10,10*REGBYTES(x2)
   STORE  x11,11*REGBYTES(x2)
   STORE  x12,12*REGBYTES(x2)
@@ -164,22 +167,16 @@ trap_entry:
   STORE  x30,30*REGBYTES(x2)
   STORE  x31,31*REGBYTES(x2)
 
-  mfpcr  x3,ASM_CR(PCR_K0)
-  STORE  x3,1*REGBYTES(x2)          # x1 is in PCR_K0
-  mfpcr  x3,ASM_CR(PCR_K1)
-  STORE  x3,2*REGBYTES(x2)          # x2 is in PCR_K1
-
   # get sr, epc, badvaddr, cause
-  mfpcr  x3,ASM_CR(PCR_SR)          # sr
+  mfpcr  x3,ASM_CR(PCR_SR)
+  mfpcr  x4,ASM_CR(PCR_EPC)
+  mfpcr  x5,ASM_CR(PCR_BADVADDR)
+  mfpcr  x6,ASM_CR(PCR_CAUSE)
   STORE  x3,32*REGBYTES(x2)
-  mfpcr  x4,ASM_CR(PCR_EPC)          # epc
   STORE  x4,33*REGBYTES(x2)
-  mfpcr  x3,ASM_CR(PCR_BADVADDR)      # badvaddr
-  STORE  x3,34*REGBYTES(x2)
-  mfpcr  x3,ASM_CR(PCR_CAUSE)        # cause
-  STORE  x3,35*REGBYTES(x2)
+  STORE  x5,34*REGBYTES(x2)
+  STORE  x6,35*REGBYTES(x2)
 
-  li    s9, 0
   move  sp, x2
   move  a0, x2
   j     handle_trap
index 0f09b36..b9f7534 100644 (file)
@@ -26,14 +26,14 @@ void proc_init_ctx(struct user_context *ctx, uint32_t vcoreid, uintptr_t entryp,
 
        memset(tf, 0, sizeof(*tf));
 
-       tf->gpr[30] = stack_top-64;
+       tf->gpr[GPR_SP] = stack_top-64;
        tf->sr = SR_U64;
 
        tf->epc = entryp;
 
        /* Coupled closely with user's entry.S.  id is the vcoreid, which entry.S
         * uses to determine what to do.  vcoreid == 0 is the main core/context. */
-       tf->gpr[4] = vcoreid;
+       tf->gpr[GPR_A0] = vcoreid;
 }
 
 /* TODO: handle both HW and SW contexts */
index 29e5cc3..c23c962 100644 (file)
@@ -19,7 +19,7 @@ static __inline uintptr_t
 read_pc(void)
 {
        uintptr_t pc;
-       asm ("rdnpc %0" : "=r"(pc));
+       asm ("rdpc %0" : "=r"(pc));
        return pc;
 }
 
index 3422ce3..d9a302e 100644 (file)
@@ -21,6 +21,11 @@ struct sw_trapframe {
        /* TODO */
 };
 
+#define GPR_RA 1
+#define GPR_SP 14
+#define GPR_A0 18
+#define GPR_A1 19
+
 typedef struct ancillary_state
 {
        uint64_t fpr[32];
index a50c2af..9d0bf6f 100644 (file)
@@ -67,7 +67,7 @@ static void set_current_ctx_hw(struct per_cpu_info *pcpui,
                warn("Turn off IRQs until cur_ctx is set!");
        assert(!pcpui->cur_ctx);
        pcpui->actual_ctx.type = ROS_HW_CTX;
-       pcpui->actual_ctx.hw_tf = *hw_tf;
+       pcpui->actual_ctx.tf.hw_tf = *hw_tf;
        pcpui->cur_ctx = &pcpui->actual_ctx;
 }
 
@@ -78,7 +78,7 @@ static void set_current_ctx_sw(struct per_cpu_info *pcpui,
                warn("Turn off IRQs until cur_ctx is set!");
        assert(!pcpui->cur_ctx);
        pcpui->actual_ctx.type = ROS_SW_CTX;
-       pcpui->actual_ctx.sw_tf = *sw_tf;
+       pcpui->actual_ctx.tf.sw_tf = *sw_tf;
        pcpui->cur_ctx = &pcpui->actual_ctx;
 }
 
@@ -94,10 +94,10 @@ format_trapframe(struct hw_trapframe *hw_tf, char* buf, int bufsz)
        int len = snprintf(buf,bufsz,"TRAP frame at %p on core %d\n",
                           hw_tf, core_id());
        static const char* regnames[] = {
-         "z ", "ra", "v0", "v1", "a0", "a1", "a2", "a3",
-         "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3",
-         "t4", "t5", "t6", "t7", "s0", "s1", "s2", "s3",
-         "s4", "s5", "s6", "s7", "s8", "fp", "sp", "tp"
+         "z ", "ra", "s0", "s1", "s2", "s3", "s4", "s5",
+         "s6", "s7", "s8", "s9", "sA", "sB", "sp", "tp",
+         "v0", "v1", "a0", "a1", "a2", "a3", "a4", "a5",
+         "a6", "a7", "a8", "a9", "aA", "aB", "aC", "aD"
        };
        
        hw_tf->gpr[0] = 0;
@@ -130,7 +130,7 @@ static void exit_halt_loop(struct hw_trapframe *hw_tf)
        extern char after_cpu_halt;
        if ((char*)hw_tf->epc >= (char*)&cpu_halt &&
            (char*)hw_tf->epc < &after_cpu_halt)
-               hw_tf->epc = hw_tf->gpr[1];
+               hw_tf->epc = hw_tf->gpr[GPR_RA];
 }
 
 static void handle_keypress(char c)
@@ -262,7 +262,7 @@ handle_illegal_instruction(struct hw_trapframe *state)
        set_current_ctx_hw(pcpui, state);
        if (emulate_fpu(state) == 0)
        {
-               advance_pc(&pcpui->cur_ctx->hw_tf);
+               advance_pc(&pcpui->cur_ctx->tf.hw_tf);
                return;
        }
 
@@ -283,8 +283,8 @@ handle_fp_disabled(struct hw_trapframe *hw_tf)
 static void
 handle_syscall(struct hw_trapframe *state)
 {
-       uintptr_t a0 = state->gpr[4];
-       uintptr_t a1 = state->gpr[5];
+       uintptr_t a0 = state->gpr[GPR_A0];
+       uintptr_t a1 = state->gpr[GPR_A1];
 
        advance_pc(state);
        set_current_ctx_hw(&per_cpu_info[core_id()], state);
index 722a472..f60ccc7 100644 (file)
@@ -200,10 +200,10 @@ index 0000000..22edee7
 +N (64, 64, 0, "riscv", TRUE, &arch_info_struct[0]);
 diff --git a/binutils-2.21.1/bfd/elf32-riscv.c b/binutils-2.21.1/bfd/elf32-riscv.c
 new file mode 100644
-index 0000000..c6b515a
+index 0000000..76c2f26
 --- /dev/null
 +++ binutils-2.21.1/bfd/elf32-riscv.c
-@@ -0,0 +1,2468 @@
+@@ -0,0 +1,2200 @@
 +/* MIPS-specific support for 32-bit ELF
 +   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
 +   2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
@@ -270,8 +270,6 @@ index 0000000..c6b515a
 +  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
 +static bfd_reloc_status_type gprel32_with_gp
 +  (bfd *, asymbol *, arelent *, asection *, bfd_boolean, void *, bfd_vma);
-+static bfd_reloc_status_type mips16_gprel_reloc
-+  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
 +static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup
 +  (bfd *, bfd_reloc_code_real_type);
 +static reloc_howto_type *mips_elf_n32_rtype_to_howto
@@ -537,7 +535,7 @@ index 0000000..c6b515a
 +       0,                     /* rightshift */
 +       2,                     /* size (0 = byte, 1 = short, 2 = long) */
 +       RISCV_BIGIMM_BITS,     /* bitsize */
-+       FALSE,                 /* pc_relative */
++       TRUE,                  /* pc_relative */
 +       OP_SH_BIGIMMEDIATE,    /* bitpos */
 +       complain_overflow_dont, /* complain_on_overflow */
 +       _bfd_riscv_elf_generic_reloc,  /* special_function */
@@ -552,7 +550,7 @@ index 0000000..c6b515a
 +       0,                     /* rightshift */
 +       2,                     /* size (0 = byte, 1 = short, 2 = long) */
 +       RISCV_IMM_BITS,                        /* bitsize */
-+       FALSE,                 /* pc_relative */
++       TRUE,                  /* pc_relative */
 +       OP_SH_IMMEDIATE,       /* bitpos */
 +       complain_overflow_dont, /* complain_on_overflow */
 +       _bfd_riscv_elf_generic_reloc,  /* special_function */
@@ -883,7 +881,7 @@ index 0000000..c6b515a
 +       0,                     /* rightshift */
 +       2,                     /* size (0 = byte, 1 = short, 2 = long) */
 +       RISCV_BIGIMM_BITS,     /* bitsize */
-+       FALSE,                 /* pc_relative */
++       TRUE,                  /* pc_relative */
 +       OP_SH_BIGIMMEDIATE,    /* bitpos */
 +       complain_overflow_dont, /* complain_on_overflow */
 +       _bfd_riscv_elf_generic_reloc,  /* special_function */
@@ -898,7 +896,7 @@ index 0000000..c6b515a
 +       0,                     /* rightshift */
 +       2,                     /* size (0 = byte, 1 = short, 2 = long) */
 +       RISCV_IMM_BITS,                        /* bitsize */
-+       FALSE,                 /* pc_relative */
++       TRUE,                  /* pc_relative */
 +       OP_SH_IMMEDIATE,       /* bitpos */
 +       complain_overflow_dont, /* complain_on_overflow */
 +       _bfd_riscv_elf_generic_reloc, /* special_function */
@@ -1048,7 +1046,7 @@ index 0000000..c6b515a
 +                                 bits must match the PC + 4.  */
 +       _bfd_riscv_elf_generic_reloc,  /* special_function */
 +       "R_RISCV_26",          /* name */
-+       TRUE,                  /* partial_inplace */
++       FALSE,                 /* partial_inplace */
 +       0,                     /* src_mask */
 +       ((1<<RISCV_JUMP_BITS)-1) << OP_SH_TARGET,              /* dst_mask */
 +       TRUE),         /* pcrel_offset */
@@ -1219,7 +1217,7 @@ index 0000000..c6b515a
 +       0,                     /* rightshift */
 +       2,                     /* size (0 = byte, 1 = short, 2 = long) */
 +       RISCV_BIGIMM_BITS,                     /* bitsize */
-+       FALSE,                 /* pc_relative */
++       TRUE,                  /* pc_relative */
 +       OP_SH_BIGIMMEDIATE,    /* bitpos */
 +       complain_overflow_dont, /* complain_on_overflow */
 +       _bfd_riscv_elf_generic_reloc,  /* special_function */
@@ -1234,7 +1232,7 @@ index 0000000..c6b515a
 +       0,                     /* rightshift */
 +       2,                     /* size (0 = byte, 1 = short, 2 = long) */
 +       RISCV_IMM_BITS,                        /* bitsize */
-+       FALSE,                 /* pc_relative */
++       TRUE,                  /* pc_relative */
 +       OP_SH_IMMEDIATE,       /* bitpos */
 +       complain_overflow_dont, /* complain_on_overflow */
 +       _bfd_riscv_elf_generic_reloc,  /* special_function */
@@ -1564,7 +1562,7 @@ index 0000000..c6b515a
 +       0,                     /* rightshift */
 +       2,                     /* size (0 = byte, 1 = short, 2 = long) */
 +       RISCV_BIGIMM_BITS,                     /* bitsize */
-+       FALSE,                 /* pc_relative */
++       TRUE,                  /* pc_relative */
 +       OP_SH_BIGIMMEDIATE,    /* bitpos */
 +       complain_overflow_dont, /* complain_on_overflow */
 +       _bfd_riscv_elf_generic_reloc,  /* special_function */
@@ -1579,7 +1577,7 @@ index 0000000..c6b515a
 +       0,                     /* rightshift */
 +       2,                     /* size (0 = byte, 1 = short, 2 = long) */
 +       RISCV_IMM_BITS,                        /* bitsize */
-+       FALSE,                 /* pc_relative */
++       TRUE,                  /* pc_relative */
 +       OP_SH_IMMEDIATE,       /* bitpos */
 +       complain_overflow_dont, /* complain_on_overflow */
 +       _bfd_riscv_elf_generic_reloc,  /* special_function */
@@ -1665,198 +1663,6 @@ index 0000000..c6b515a
 +       FALSE),                /* pcrel_offset */
 +};
 +
-+static reloc_howto_type elf_mips16_howto_table_rel[] =
-+{
-+  /* The reloc used for the mips16 jump instruction.  */
-+  HOWTO (R_MIPS16_26,         /* type */
-+       2,                     /* rightshift */
-+       2,                     /* size (0 = byte, 1 = short, 2 = long) */
-+       26,                    /* bitsize */
-+       FALSE,                 /* pc_relative */
-+       0,                     /* bitpos */
-+       complain_overflow_dont, /* complain_on_overflow */
-+                              /* This needs complex overflow
-+                                 detection, because the upper four
-+                                 bits must match the PC.  */
-+       _bfd_riscv_elf_generic_reloc, /* special_function */
-+       "R_MIPS16_26",         /* name */
-+       TRUE,                  /* partial_inplace */
-+       0x3ffffff,             /* src_mask */
-+       0x3ffffff,             /* dst_mask */
-+       FALSE),                /* pcrel_offset */
-+
-+  /* The reloc used for the mips16 gprel instruction.  */
-+  HOWTO (R_MIPS16_GPREL,      /* type */
-+       0,                     /* rightshift */
-+       2,                     /* size (0 = byte, 1 = short, 2 = long) */
-+       16,                    /* bitsize */
-+       FALSE,                 /* pc_relative */
-+       0,                     /* bitpos */
-+       complain_overflow_signed, /* complain_on_overflow */
-+       mips16_gprel_reloc,    /* special_function */
-+       "R_MIPS16_GPREL",      /* name */
-+       TRUE,                  /* partial_inplace */
-+       0x0000ffff,            /* src_mask */
-+       0x0000ffff,            /* dst_mask */
-+       FALSE),                /* pcrel_offset */
-+
-+  /* A MIPS16 reference to the global offset table.  */
-+  HOWTO (R_MIPS16_GOT16,      /* type */
-+       0,                     /* rightshift */
-+       2,                     /* size (0 = byte, 1 = short, 2 = long) */
-+       16,                    /* bitsize */
-+       FALSE,                 /* pc_relative */
-+       0,                     /* bitpos */
-+       complain_overflow_dont, /* complain_on_overflow */
-+       _bfd_riscv_elf_got16_reloc, /* special_function */
-+       "R_MIPS16_GOT16",      /* name */
-+       TRUE,                  /* partial_inplace */
-+       0x0000ffff,            /* src_mask */
-+       0x0000ffff,            /* dst_mask */
-+       FALSE),                /* pcrel_offset */
-+
-+  /* A MIPS16 call through the global offset table.  */
-+  HOWTO (R_MIPS16_CALL16,     /* type */
-+       0,                     /* rightshift */
-+       2,                     /* size (0 = byte, 1 = short, 2 = long) */
-+       16,                    /* bitsize */
-+       FALSE,                 /* pc_relative */
-+       0,                     /* bitpos */
-+       complain_overflow_dont, /* complain_on_overflow */
-+       _bfd_riscv_elf_generic_reloc, /* special_function */
-+       "R_MIPS16_CALL16",     /* name */
-+       TRUE,                  /* partial_inplace */
-+       0x0000ffff,            /* src_mask */
-+       0x0000ffff,            /* dst_mask */
-+       FALSE),                /* pcrel_offset */
-+
-+  /* MIPS16 high 16 bits of symbol value.  */
-+  HOWTO (R_MIPS16_HI16,               /* type */
-+       16,                    /* rightshift */
-+       2,                     /* size (0 = byte, 1 = short, 2 = long) */
-+       16,                    /* bitsize */
-+       FALSE,                 /* pc_relative */
-+       0,                     /* bitpos */
-+       complain_overflow_dont, /* complain_on_overflow */
-+       _bfd_riscv_elf_hi16_reloc, /* special_function */
-+       "R_MIPS16_HI16",       /* name */
-+       TRUE,                  /* partial_inplace */
-+       0x0000ffff,            /* src_mask */
-+       0x0000ffff,            /* dst_mask */
-+       FALSE),                /* pcrel_offset */
-+
-+  /* MIPS16 low 16 bits of symbol value.  */
-+  HOWTO (R_MIPS16_LO16,               /* type */
-+       0,                     /* rightshift */
-+       2,                     /* size (0 = byte, 1 = short, 2 = long) */
-+       16,                    /* bitsize */
-+       FALSE,                 /* pc_relative */
-+       0,                     /* bitpos */
-+       complain_overflow_dont, /* complain_on_overflow */
-+       _bfd_riscv_elf_lo16_reloc, /* special_function */
-+       "R_MIPS16_LO16",       /* name */
-+       TRUE,                  /* partial_inplace */
-+       0x0000ffff,            /* src_mask */
-+       0x0000ffff,            /* dst_mask */
-+       FALSE),                /* pcrel_offset */
-+};
-+
-+static reloc_howto_type elf_mips16_howto_table_rela[] =
-+{
-+  /* The reloc used for the mips16 jump instruction.  */
-+  HOWTO (R_MIPS16_26,         /* type */
-+       2,                     /* rightshift */
-+       2,                     /* size (0 = byte, 1 = short, 2 = long) */
-+       26,                    /* bitsize */
-+       FALSE,                 /* pc_relative */
-+       0,                     /* bitpos */
-+       complain_overflow_dont, /* complain_on_overflow */
-+                              /* This needs complex overflow
-+                                 detection, because the upper four
-+                                 bits must match the PC.  */
-+       _bfd_riscv_elf_generic_reloc, /* special_function */
-+       "R_MIPS16_26",         /* name */
-+       FALSE,                 /* partial_inplace */
-+       0x3ffffff,             /* src_mask */
-+       0x3ffffff,             /* dst_mask */
-+       FALSE),                /* pcrel_offset */
-+
-+  /* The reloc used for the mips16 gprel instruction.  */
-+  HOWTO (R_MIPS16_GPREL,      /* type */
-+       0,                     /* rightshift */
-+       2,                     /* size (0 = byte, 1 = short, 2 = long) */
-+       16,                    /* bitsize */
-+       FALSE,                 /* pc_relative */
-+       0,                     /* bitpos */
-+       complain_overflow_signed, /* complain_on_overflow */
-+       mips16_gprel_reloc,    /* special_function */
-+       "R_MIPS16_GPREL",      /* name */
-+       FALSE,                 /* partial_inplace */
-+       0x0000ffff,            /* src_mask */
-+       0x0000ffff,            /* dst_mask */
-+       FALSE),                /* pcrel_offset */
-+
-+  /* A MIPS16 reference to the global offset table.  */
-+  HOWTO (R_MIPS16_GOT16,      /* type */
-+       0,                     /* rightshift */
-+       2,                     /* size (0 = byte, 1 = short, 2 = long) */
-+       16,                    /* bitsize */
-+       FALSE,                 /* pc_relative */
-+       0,                     /* bitpos */
-+       complain_overflow_dont, /* complain_on_overflow */
-+       _bfd_riscv_elf_got16_reloc, /* special_function */
-+       "R_MIPS16_GOT16",      /* name */
-+       FALSE,                 /* partial_inplace */
-+       0x0000ffff,            /* src_mask */
-+       0x0000ffff,            /* dst_mask */
-+       FALSE),                /* pcrel_offset */
-+
-+  /* A MIPS16 call through the global offset table.  */
-+  HOWTO (R_MIPS16_CALL16,     /* type */
-+       0,                     /* rightshift */
-+       2,                     /* size (0 = byte, 1 = short, 2 = long) */
-+       16,                    /* bitsize */
-+       FALSE,                 /* pc_relative */
-+       0,                     /* bitpos */
-+       complain_overflow_dont, /* complain_on_overflow */
-+       _bfd_riscv_elf_generic_reloc, /* special_function */
-+       "R_MIPS16_CALL16",     /* name */
-+       FALSE,                 /* partial_inplace */
-+       0x0000ffff,            /* src_mask */
-+       0x0000ffff,            /* dst_mask */
-+       FALSE),                /* pcrel_offset */
-+
-+  /* MIPS16 high 16 bits of symbol value.  */
-+  HOWTO (R_MIPS16_HI16,               /* type */
-+       16,                    /* rightshift */
-+       2,                     /* size (0 = byte, 1 = short, 2 = long) */
-+       16,                    /* bitsize */
-+       FALSE,                 /* pc_relative */
-+       0,                     /* bitpos */
-+       complain_overflow_dont, /* complain_on_overflow */
-+       _bfd_riscv_elf_hi16_reloc, /* special_function */
-+       "R_MIPS16_HI16",       /* name */
-+       FALSE,                 /* partial_inplace */
-+       0x0000ffff,            /* src_mask */
-+       0x0000ffff,            /* dst_mask */
-+       FALSE),                /* pcrel_offset */
-+
-+  /* MIPS16 low 16 bits of symbol value.  */
-+  HOWTO (R_MIPS16_LO16,               /* type */
-+       0,                     /* rightshift */
-+       2,                     /* size (0 = byte, 1 = short, 2 = long) */
-+       16,                    /* bitsize */
-+       FALSE,                 /* pc_relative */
-+       0,                     /* bitpos */
-+       complain_overflow_dont, /* complain_on_overflow */
-+       _bfd_riscv_elf_lo16_reloc, /* special_function */
-+       "R_MIPS16_LO16",       /* name */
-+       FALSE,                 /* partial_inplace */
-+       0x0000ffff,            /* src_mask */
-+       0x0000ffff,            /* dst_mask */
-+       FALSE),                /* pcrel_offset */
-+};
-+
 +/* GNU extension to record C++ vtable hierarchy */
 +static reloc_howto_type elf_mips_gnu_vtinherit_howto =
 +  HOWTO (R_RISCV_GNU_VTINHERIT,       /* type */
@@ -2196,47 +2002,6 @@ index 0000000..c6b515a
 +  return bfd_reloc_ok;
 +}
 +
-+/* Handle a mips16 GP relative reloc.  */
-+
-+static bfd_reloc_status_type
-+mips16_gprel_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
-+                  void *data, asection *input_section, bfd *output_bfd,
-+                  char **error_message)
-+{
-+  bfd_boolean relocatable;
-+  bfd_reloc_status_type ret;
-+  bfd_vma gp;
-+
-+  /* If we're relocating, and this is an external symbol, we don't want
-+     to change anything.  */
-+  if (output_bfd != NULL
-+      && (symbol->flags & BSF_SECTION_SYM) == 0
-+      && (symbol->flags & BSF_LOCAL) != 0)
-+    {
-+      reloc_entry->address += input_section->output_offset;
-+      return bfd_reloc_ok;
-+    }
-+
-+  if (output_bfd != NULL)
-+    relocatable = TRUE;
-+  else
-+    {
-+      relocatable = FALSE;
-+      output_bfd = symbol->section->output_section->owner;
-+    }
-+
-+  ret = mips_elf_final_gp (output_bfd, symbol, relocatable, error_message,
-+                         &gp);
-+  if (ret != bfd_reloc_ok)
-+    return ret;
-+
-+  ret = _bfd_riscv_elf_gprel16_with_gp (abfd, symbol, reloc_entry,
-+                                     input_section, relocatable,
-+                                     data, gp);
-+
-+  return ret;
-+}
-+\f
 +/* A mapping from BFD reloc types to MIPS ELF reloc types.  */
 +
 +struct elf_reloc_map {
@@ -2289,16 +2054,6 @@ index 0000000..c6b515a
 +  { BFD_RELOC_MIPS_TLS_TPREL_LO16, R_RISCV_TLS_TPREL_LO16 }
 +};
 +
-+static const struct elf_reloc_map mips16_reloc_map[] =
-+{
-+  { BFD_RELOC_MIPS16_JMP, R_MIPS16_26 - R_MIPS16_min },
-+  { BFD_RELOC_MIPS16_GPREL, R_MIPS16_GPREL - R_MIPS16_min },
-+  { BFD_RELOC_MIPS16_GOT16, R_MIPS16_GOT16 - R_MIPS16_min },
-+  { BFD_RELOC_MIPS16_CALL16, R_MIPS16_CALL16 - R_MIPS16_min },
-+  { BFD_RELOC_MIPS16_HI16_S, R_MIPS16_HI16 - R_MIPS16_min },
-+  { BFD_RELOC_MIPS16_LO16, R_MIPS16_LO16 - R_MIPS16_min },
-+};
-+
 +/* Given a BFD reloc type, return a howto structure.  */
 +
 +static reloc_howto_type *
@@ -2309,7 +2064,6 @@ index 0000000..c6b515a
 +  /* FIXME: We default to RELA here instead of choosing the right
 +     relocation variant.  */
 +  reloc_howto_type *howto_table = elf_mips_howto_table_rela;
-+  reloc_howto_type *howto16_table = elf_mips16_howto_table_rela;
 +
 +  for (i = 0; i < sizeof (mips_reloc_map) / sizeof (struct elf_reloc_map);
 +       i++)
@@ -2318,13 +2072,6 @@ index 0000000..c6b515a
 +      return &howto_table[(int) mips_reloc_map[i].elf_val];
 +    }
 +
-+  for (i = 0; i < sizeof (mips16_reloc_map) / sizeof (struct elf_reloc_map);
-+       i++)
-+    {
-+      if (mips16_reloc_map[i].bfd_val == code)
-+      return &howto16_table[(int) mips16_reloc_map[i].elf_val];
-+    }
-+
 +  switch (code)
 +    {
 +    case BFD_RELOC_VTABLE_INHERIT:
@@ -2355,14 +2102,6 @@ index 0000000..c6b515a
 +      && strcasecmp (elf_mips_howto_table_rela[i].name, r_name) == 0)
 +      return &elf_mips_howto_table_rela[i];
 +
-+  for (i = 0;
-+       i < (sizeof (elf_mips16_howto_table_rela)
-+          / sizeof (elf_mips16_howto_table_rela[0]));
-+       i++)
-+    if (elf_mips16_howto_table_rela[i].name != NULL
-+      && strcasecmp (elf_mips16_howto_table_rela[i].name, r_name) == 0)
-+      return &elf_mips16_howto_table_rela[i];
-+
 +  if (strcasecmp (elf_mips_gnu_vtinherit_howto.name, r_name) == 0)
 +    return &elf_mips_gnu_vtinherit_howto;
 +  if (strcasecmp (elf_mips_gnu_vtentry_howto.name, r_name) == 0)
@@ -2400,13 +2139,6 @@ index 0000000..c6b515a
 +    case R_RISCV_JUMP_SLOT:
 +      return &elf_mips_jump_slot_howto;
 +    default:
-+      if (r_type >= R_MIPS16_min && r_type < R_MIPS16_max)
-+      {
-+        if (rela_p)
-+          return &elf_mips16_howto_table_rela[r_type - R_MIPS16_min];
-+        else
-+          return &elf_mips16_howto_table_rel[r_type - R_MIPS16_min];
-+      }
 +      BFD_ASSERT (r_type < (unsigned int) R_RISCV_max);
 +      if (rela_p)
 +      return &elf_mips_howto_table_rela[r_type];
@@ -2674,10 +2406,10 @@ index 0000000..c6b515a
 +#include "elf32-target.h"
 diff --git a/binutils-2.21.1/bfd/elf64-riscv.c b/binutils-2.21.1/bfd/elf64-riscv.c
 new file mode 100644
-index 0000000..aa3dca1
+index 0000000..973edc0
 --- /dev/null
 +++ binutils-2.21.1/bfd/elf64-riscv.c
-@@ -0,0 +1,3296 @@
+@@ -0,0 +1,3028 @@
 +/* MIPS-specific support for 64-bit ELF
 +   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
 +   2006, 2007, 2008, 2009, 2010
@@ -2796,8 +2528,6 @@ index 0000000..aa3dca1
 +  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
 +static bfd_reloc_status_type mips_elf64_gprel32_reloc
 +  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
-+static bfd_reloc_status_type mips16_gprel_reloc
-+  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
 +static bfd_boolean mips_elf64_assign_gp
 +  (bfd *, bfd_vma *);
 +static bfd_reloc_status_type mips_elf64_final_gp
@@ -3054,7 +2784,7 @@ index 0000000..aa3dca1
 +       0,                     /* rightshift */
 +       2,                     /* size (0 = byte, 1 = short, 2 = long) */
 +       RISCV_BIGIMM_BITS,     /* bitsize */
-+       FALSE,                 /* pc_relative */
++       TRUE,                  /* pc_relative */
 +       OP_SH_BIGIMMEDIATE,    /* bitpos */
 +       complain_overflow_dont, /* complain_on_overflow */
 +       _bfd_riscv_elf_generic_reloc,  /* special_function */
@@ -3069,7 +2799,7 @@ index 0000000..aa3dca1
 +       0,                     /* rightshift */
 +       2,                     /* size (0 = byte, 1 = short, 2 = long) */
 +       RISCV_IMM_BITS,                        /* bitsize */
-+       FALSE,                 /* pc_relative */
++       TRUE,                  /* pc_relative */
 +       OP_SH_IMMEDIATE,       /* bitpos */
 +       complain_overflow_dont, /* complain_on_overflow */
 +       _bfd_riscv_elf_generic_reloc,  /* special_function */
@@ -3400,7 +3130,7 @@ index 0000000..aa3dca1
 +       0,                     /* rightshift */
 +       2,                     /* size (0 = byte, 1 = short, 2 = long) */
 +       RISCV_BIGIMM_BITS,     /* bitsize */
-+       FALSE,                 /* pc_relative */
++       TRUE,                  /* pc_relative */
 +       OP_SH_BIGIMMEDIATE,    /* bitpos */
 +       complain_overflow_dont, /* complain_on_overflow */
 +       _bfd_riscv_elf_generic_reloc,  /* special_function */
@@ -3415,7 +3145,7 @@ index 0000000..aa3dca1
 +       0,                     /* rightshift */
 +       2,                     /* size (0 = byte, 1 = short, 2 = long) */
 +       RISCV_IMM_BITS,                        /* bitsize */
-+       FALSE,                 /* pc_relative */
++       TRUE,                  /* pc_relative */
 +       OP_SH_IMMEDIATE,       /* bitpos */
 +       complain_overflow_dont, /* complain_on_overflow */
 +       _bfd_riscv_elf_generic_reloc, /* special_function */
@@ -3565,7 +3295,7 @@ index 0000000..aa3dca1
 +                                 bits must match the PC + 4.  */
 +       _bfd_riscv_elf_generic_reloc,  /* special_function */
 +       "R_RISCV_26",          /* name */
-+       TRUE,                  /* partial_inplace */
++       FALSE,                 /* partial_inplace */
 +       0,                     /* src_mask */
 +       ((1<<RISCV_JUMP_BITS)-1) << OP_SH_TARGET,              /* dst_mask */
 +       TRUE),         /* pcrel_offset */
@@ -3736,7 +3466,7 @@ index 0000000..aa3dca1
 +       0,                     /* rightshift */
 +       2,                     /* size (0 = byte, 1 = short, 2 = long) */
 +       RISCV_BIGIMM_BITS,                     /* bitsize */
-+       FALSE,                 /* pc_relative */
++       TRUE,                  /* pc_relative */
 +       OP_SH_BIGIMMEDIATE,    /* bitpos */
 +       complain_overflow_dont, /* complain_on_overflow */
 +       _bfd_riscv_elf_generic_reloc,  /* special_function */
@@ -3751,7 +3481,7 @@ index 0000000..aa3dca1
 +       0,                     /* rightshift */
 +       2,                     /* size (0 = byte, 1 = short, 2 = long) */
 +       RISCV_IMM_BITS,                        /* bitsize */
-+       FALSE,                 /* pc_relative */
++       TRUE,                  /* pc_relative */
 +       OP_SH_IMMEDIATE,       /* bitpos */
 +       complain_overflow_dont, /* complain_on_overflow */
 +       _bfd_riscv_elf_generic_reloc,  /* special_function */
@@ -4081,7 +3811,7 @@ index 0000000..aa3dca1
 +       0,                     /* rightshift */
 +       2,                     /* size (0 = byte, 1 = short, 2 = long) */
 +       RISCV_BIGIMM_BITS,                     /* bitsize */
-+       FALSE,                 /* pc_relative */
++       TRUE,                  /* pc_relative */
 +       OP_SH_BIGIMMEDIATE,    /* bitpos */
 +       complain_overflow_dont, /* complain_on_overflow */
 +       _bfd_riscv_elf_generic_reloc,  /* special_function */
@@ -4096,7 +3826,7 @@ index 0000000..aa3dca1
 +       0,                     /* rightshift */
 +       2,                     /* size (0 = byte, 1 = short, 2 = long) */
 +       RISCV_IMM_BITS,                        /* bitsize */
-+       FALSE,                 /* pc_relative */
++       TRUE,                  /* pc_relative */
 +       OP_SH_IMMEDIATE,       /* bitpos */
 +       complain_overflow_dont, /* complain_on_overflow */
 +       _bfd_riscv_elf_generic_reloc,  /* special_function */
@@ -4182,241 +3912,49 @@ index 0000000..aa3dca1
 +       FALSE),                /* pcrel_offset */
 +};
 +
-+static reloc_howto_type mips16_elf64_howto_table_rel[] =
-+{
-+  /* The reloc used for the mips16 jump instruction.  */
-+  HOWTO (R_MIPS16_26,         /* type */
-+       2,                     /* rightshift */
++/* GNU extension to record C++ vtable hierarchy */
++static reloc_howto_type elf_mips_gnu_vtinherit_howto =
++  HOWTO (R_RISCV_GNU_VTINHERIT,       /* type */
++       0,                     /* rightshift */
 +       2,                     /* size (0 = byte, 1 = short, 2 = long) */
-+       26,                    /* bitsize */
++       0,                     /* bitsize */
 +       FALSE,                 /* pc_relative */
 +       0,                     /* bitpos */
 +       complain_overflow_dont, /* complain_on_overflow */
-+                              /* This needs complex overflow
-+                                 detection, because the upper four
-+                                 bits must match the PC.  */
-+       _bfd_riscv_elf_generic_reloc, /* special_function */
-+       "R_MIPS16_26",         /* name */
-+       TRUE,                  /* partial_inplace */
-+       0x3ffffff,             /* src_mask */
-+       0x3ffffff,             /* dst_mask */
-+       FALSE),                /* pcrel_offset */
++       NULL,                  /* special_function */
++       "R_RISCV_GNU_VTINHERIT", /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0,                     /* dst_mask */
++       FALSE);                /* pcrel_offset */
 +
-+  /* The reloc used for the mips16 gprel instruction.  */
-+  HOWTO (R_MIPS16_GPREL,      /* type */
++/* GNU extension to record C++ vtable member usage */
++static reloc_howto_type elf_mips_gnu_vtentry_howto =
++  HOWTO (R_RISCV_GNU_VTENTRY, /* type */
 +       0,                     /* rightshift */
 +       2,                     /* size (0 = byte, 1 = short, 2 = long) */
-+       16,                    /* bitsize */
++       0,                     /* bitsize */
 +       FALSE,                 /* pc_relative */
 +       0,                     /* bitpos */
++       complain_overflow_dont, /* complain_on_overflow */
++       _bfd_elf_rel_vtable_reloc_fn, /* special_function */
++       "R_RISCV_GNU_VTENTRY", /* name */
++       FALSE,                 /* partial_inplace */
++       0,                     /* src_mask */
++       0,                     /* dst_mask */
++       FALSE);                /* pcrel_offset */
++\f
++/* 16 bit offset for pc-relative branches.  */
++static reloc_howto_type elf_mips_gnu_rel16_s2 =
++  HOWTO (R_RISCV_GNU_REL16_S2,        /* type */
++       RISCV_BRANCH_ALIGN_BITS,                       /* rightshift */
++       2,                     /* size (0 = byte, 1 = short, 2 = long) */
++       RISCV_BRANCH_BITS,                     /* bitsize */
++       TRUE,                  /* pc_relative */
++       0,                     /* bitpos */
 +       complain_overflow_signed, /* complain_on_overflow */
-+       mips16_gprel_reloc,    /* special_function */
-+       "R_MIPS16_GPREL",      /* name */
-+       TRUE,                  /* partial_inplace */
-+       0x0000ffff,            /* src_mask */
-+       0x0000ffff,            /* dst_mask */
-+       FALSE),                /* pcrel_offset */
-+
-+  /* A MIPS16 reference to the global offset table.  */
-+  HOWTO (R_MIPS16_GOT16,      /* type */
-+       0,                     /* rightshift */
-+       2,                     /* size (0 = byte, 1 = short, 2 = long) */
-+       16,                    /* bitsize */
-+       FALSE,                 /* pc_relative */
-+       0,                     /* bitpos */
-+       complain_overflow_dont, /* complain_on_overflow */
-+       _bfd_riscv_elf_got16_reloc, /* special_function */
-+       "R_MIPS16_GOT16",      /* name */
-+       TRUE,                  /* partial_inplace */
-+       0x0000ffff,            /* src_mask */
-+       0x0000ffff,            /* dst_mask */
-+       FALSE),                /* pcrel_offset */
-+
-+  /* A MIPS16 call through the global offset table.  */
-+  HOWTO (R_MIPS16_CALL16,     /* type */
-+       0,                     /* rightshift */
-+       2,                     /* size (0 = byte, 1 = short, 2 = long) */
-+       16,                    /* bitsize */
-+       FALSE,                 /* pc_relative */
-+       0,                     /* bitpos */
-+       complain_overflow_dont, /* complain_on_overflow */
-+       _bfd_riscv_elf_generic_reloc, /* special_function */
-+       "R_MIPS16_CALL16",     /* name */
-+       TRUE,                  /* partial_inplace */
-+       0x0000ffff,            /* src_mask */
-+       0x0000ffff,            /* dst_mask */
-+       FALSE),                /* pcrel_offset */
-+
-+  /* MIPS16 high 16 bits of symbol value.  */
-+  HOWTO (R_MIPS16_HI16,               /* type */
-+       16,                    /* rightshift */
-+       2,                     /* size (0 = byte, 1 = short, 2 = long) */
-+       16,                    /* bitsize */
-+       FALSE,                 /* pc_relative */
-+       0,                     /* bitpos */
-+       complain_overflow_dont, /* complain_on_overflow */
-+       _bfd_riscv_elf_hi16_reloc, /* special_function */
-+       "R_MIPS16_HI16",       /* name */
-+       TRUE,                  /* partial_inplace */
-+       0x0000ffff,            /* src_mask */
-+       0x0000ffff,            /* dst_mask */
-+       FALSE),                /* pcrel_offset */
-+
-+  /* MIPS16 low 16 bits of symbol value.  */
-+  HOWTO (R_MIPS16_LO16,               /* type */
-+       0,                     /* rightshift */
-+       2,                     /* size (0 = byte, 1 = short, 2 = long) */
-+       16,                    /* bitsize */
-+       FALSE,                 /* pc_relative */
-+       0,                     /* bitpos */
-+       complain_overflow_dont, /* complain_on_overflow */
-+       _bfd_riscv_elf_lo16_reloc, /* special_function */
-+       "R_MIPS16_LO16",       /* name */
-+       TRUE,                  /* partial_inplace */
-+       0x0000ffff,            /* src_mask */
-+       0x0000ffff,            /* dst_mask */
-+       FALSE),                /* pcrel_offset */
-+};
-+
-+static reloc_howto_type mips16_elf64_howto_table_rela[] =
-+{
-+  /* The reloc used for the mips16 jump instruction.  */
-+  HOWTO (R_MIPS16_26,         /* type */
-+       2,                     /* rightshift */
-+       2,                     /* size (0 = byte, 1 = short, 2 = long) */
-+       26,                    /* bitsize */
-+       FALSE,                 /* pc_relative */
-+       0,                     /* bitpos */
-+       complain_overflow_dont, /* complain_on_overflow */
-+                              /* This needs complex overflow
-+                                 detection, because the upper four
-+                                 bits must match the PC.  */
-+       _bfd_riscv_elf_generic_reloc, /* special_function */
-+       "R_MIPS16_26",         /* name */
-+       FALSE,                 /* partial_inplace */
-+       0x3ffffff,             /* src_mask */
-+       0x3ffffff,             /* dst_mask */
-+       FALSE),                /* pcrel_offset */
-+
-+  /* The reloc used for the mips16 gprel instruction.  */
-+  HOWTO (R_MIPS16_GPREL,      /* type */
-+       0,                     /* rightshift */
-+       2,                     /* size (0 = byte, 1 = short, 2 = long) */
-+       16,                    /* bitsize */
-+       FALSE,                 /* pc_relative */
-+       0,                     /* bitpos */
-+       complain_overflow_signed, /* complain_on_overflow */
-+       mips16_gprel_reloc,    /* special_function */
-+       "R_MIPS16_GPREL",      /* name */
-+       FALSE,                 /* partial_inplace */
-+       0x0000ffff,            /* src_mask */
-+       0x0000ffff,            /* dst_mask */
-+       FALSE),                /* pcrel_offset */
-+
-+  /* A MIPS16 reference to the global offset table.  */
-+  HOWTO (R_MIPS16_GOT16,      /* type */
-+       0,                     /* rightshift */
-+       2,                     /* size (0 = byte, 1 = short, 2 = long) */
-+       16,                    /* bitsize */
-+       FALSE,                 /* pc_relative */
-+       0,                     /* bitpos */
-+       complain_overflow_dont, /* complain_on_overflow */
-+       _bfd_riscv_elf_got16_reloc, /* special_function */
-+       "R_MIPS16_GOT16",      /* name */
-+       FALSE,                 /* partial_inplace */
-+       0x0000ffff,            /* src_mask */
-+       0x0000ffff,            /* dst_mask */
-+       FALSE),                /* pcrel_offset */
-+
-+  /* A MIPS16 call through the global offset table.  */
-+  HOWTO (R_MIPS16_CALL16,     /* type */
-+       0,                     /* rightshift */
-+       2,                     /* size (0 = byte, 1 = short, 2 = long) */
-+       16,                    /* bitsize */
-+       FALSE,                 /* pc_relative */
-+       0,                     /* bitpos */
-+       complain_overflow_dont, /* complain_on_overflow */
-+       _bfd_riscv_elf_generic_reloc, /* special_function */
-+       "R_MIPS16_CALL16",     /* name */
-+       FALSE,                 /* partial_inplace */
-+       0x0000ffff,            /* src_mask */
-+       0x0000ffff,            /* dst_mask */
-+       FALSE),                /* pcrel_offset */
-+
-+  /* MIPS16 high 16 bits of symbol value.  */
-+  HOWTO (R_MIPS16_HI16,               /* type */
-+       16,                    /* rightshift */
-+       2,                     /* size (0 = byte, 1 = short, 2 = long) */
-+       16,                    /* bitsize */
-+       FALSE,                 /* pc_relative */
-+       0,                     /* bitpos */
-+       complain_overflow_dont, /* complain_on_overflow */
-+       _bfd_riscv_elf_hi16_reloc, /* special_function */
-+       "R_MIPS16_HI16",       /* name */
-+       FALSE,                 /* partial_inplace */
-+       0x0000ffff,            /* src_mask */
-+       0x0000ffff,            /* dst_mask */
-+       FALSE),                /* pcrel_offset */
-+
-+  /* MIPS16 low 16 bits of symbol value.  */
-+  HOWTO (R_MIPS16_LO16,               /* type */
-+       0,                     /* rightshift */
-+       2,                     /* size (0 = byte, 1 = short, 2 = long) */
-+       16,                    /* bitsize */
-+       FALSE,                 /* pc_relative */
-+       0,                     /* bitpos */
-+       complain_overflow_dont, /* complain_on_overflow */
-+       _bfd_riscv_elf_lo16_reloc, /* special_function */
-+       "R_MIPS16_LO16",       /* name */
-+       FALSE,                 /* partial_inplace */
-+       0x0000ffff,            /* src_mask */
-+       0x0000ffff,            /* dst_mask */
-+       FALSE),                /* pcrel_offset */
-+};
-+
-+/* GNU extension to record C++ vtable hierarchy */
-+static reloc_howto_type elf_mips_gnu_vtinherit_howto =
-+  HOWTO (R_RISCV_GNU_VTINHERIT,       /* type */
-+       0,                     /* rightshift */
-+       2,                     /* size (0 = byte, 1 = short, 2 = long) */
-+       0,                     /* bitsize */
-+       FALSE,                 /* pc_relative */
-+       0,                     /* bitpos */
-+       complain_overflow_dont, /* complain_on_overflow */
-+       NULL,                  /* special_function */
-+       "R_RISCV_GNU_VTINHERIT", /* name */
-+       FALSE,                 /* partial_inplace */
-+       0,                     /* src_mask */
-+       0,                     /* dst_mask */
-+       FALSE);                /* pcrel_offset */
-+
-+/* GNU extension to record C++ vtable member usage */
-+static reloc_howto_type elf_mips_gnu_vtentry_howto =
-+  HOWTO (R_RISCV_GNU_VTENTRY, /* type */
-+       0,                     /* rightshift */
-+       2,                     /* size (0 = byte, 1 = short, 2 = long) */
-+       0,                     /* bitsize */
-+       FALSE,                 /* pc_relative */
-+       0,                     /* bitpos */
-+       complain_overflow_dont, /* complain_on_overflow */
-+       _bfd_elf_rel_vtable_reloc_fn, /* special_function */
-+       "R_RISCV_GNU_VTENTRY", /* name */
-+       FALSE,                 /* partial_inplace */
-+       0,                     /* src_mask */
-+       0,                     /* dst_mask */
-+       FALSE);                /* pcrel_offset */
-+\f
-+/* 16 bit offset for pc-relative branches.  */
-+static reloc_howto_type elf_mips_gnu_rel16_s2 =
-+  HOWTO (R_RISCV_GNU_REL16_S2,        /* type */
-+       RISCV_BRANCH_ALIGN_BITS,                       /* rightshift */
-+       2,                     /* size (0 = byte, 1 = short, 2 = long) */
-+       RISCV_BRANCH_BITS,                     /* bitsize */
-+       TRUE,                  /* pc_relative */
-+       0,                     /* bitpos */
-+       complain_overflow_signed, /* complain_on_overflow */
-+       _bfd_riscv_elf_generic_reloc, /* special_function */
-+       "R_RISCV_GNU_REL16_S2",        /* name */
++       _bfd_riscv_elf_generic_reloc, /* special_function */
++       "R_RISCV_GNU_REL16_S2",        /* name */
 +       TRUE,                  /* partial_inplace */
 +       RISCV_BRANCH_REACH-1,          /* src_mask */
 +       RISCV_BRANCH_REACH-1,          /* dst_mask */
@@ -4862,47 +4400,6 @@ index 0000000..aa3dca1
 +  return bfd_reloc_ok;
 +}
 +
-+/* Handle a mips16 GP relative reloc.  */
-+
-+static bfd_reloc_status_type
-+mips16_gprel_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
-+                  void *data, asection *input_section, bfd *output_bfd,
-+                  char **error_message)
-+{
-+  bfd_boolean relocatable;
-+  bfd_reloc_status_type ret;
-+  bfd_vma gp;
-+
-+  /* If we're relocating, and this is an external symbol, we don't want
-+     to change anything.  */
-+  if (output_bfd != NULL
-+      && (symbol->flags & BSF_SECTION_SYM) == 0
-+      && (symbol->flags & BSF_LOCAL) != 0)
-+    {
-+      reloc_entry->address += input_section->output_offset;
-+      return bfd_reloc_ok;
-+    }
-+
-+  if (output_bfd != NULL)
-+    relocatable = TRUE;
-+  else
-+    {
-+      relocatable = FALSE;
-+      output_bfd = symbol->section->output_section->owner;
-+    }
-+
-+  ret = mips_elf64_final_gp (output_bfd, symbol, relocatable, error_message,
-+                           &gp);
-+  if (ret != bfd_reloc_ok)
-+    return ret;
-+
-+  ret = _bfd_riscv_elf_gprel16_with_gp (abfd, symbol, reloc_entry,
-+                                     input_section, relocatable,
-+                                     data, gp);
-+
-+  return ret;
-+}
-+\f
 +/* A mapping from BFD reloc types to MIPS ELF reloc types.  */
 +
 +struct elf_reloc_map {
@@ -4961,16 +4458,6 @@ index 0000000..aa3dca1
 +  { BFD_RELOC_RISCV_TLS_LDM_LO16, R_RISCV_TLS_LDM_LO16 }
 +};
 +
-+static const struct elf_reloc_map mips16_reloc_map[] =
-+{
-+  { BFD_RELOC_MIPS16_JMP, R_MIPS16_26 - R_MIPS16_min },
-+  { BFD_RELOC_MIPS16_GPREL, R_MIPS16_GPREL - R_MIPS16_min },
-+  { BFD_RELOC_MIPS16_GOT16, R_MIPS16_GOT16 - R_MIPS16_min },
-+  { BFD_RELOC_MIPS16_CALL16, R_MIPS16_CALL16 - R_MIPS16_min },
-+  { BFD_RELOC_MIPS16_HI16_S, R_MIPS16_HI16 - R_MIPS16_min },
-+  { BFD_RELOC_MIPS16_LO16, R_MIPS16_LO16 - R_MIPS16_min },
-+};
-+
 +/* Given a BFD reloc type, return a howto structure.  */
 +
 +static reloc_howto_type *
@@ -4981,7 +4468,6 @@ index 0000000..aa3dca1
 +  /* FIXME: We default to RELA here instead of choosing the right
 +     relocation variant.  */
 +  reloc_howto_type *howto_table = mips_elf64_howto_table_rela;
-+  reloc_howto_type *howto16_table = mips16_elf64_howto_table_rela;
 +
 +  for (i = 0; i < sizeof (mips_reloc_map) / sizeof (struct elf_reloc_map);
 +       i++)
@@ -4990,13 +4476,6 @@ index 0000000..aa3dca1
 +      return &howto_table[(int) mips_reloc_map[i].elf_val];
 +    }
 +
-+  for (i = 0; i < sizeof (mips16_reloc_map) / sizeof (struct elf_reloc_map);
-+       i++)
-+    {
-+      if (mips16_reloc_map[i].bfd_val == code)
-+      return &howto16_table[(int) mips16_reloc_map[i].elf_val];
-+    }
-+
 +  switch (code)
 +    {
 +    case BFD_RELOC_VTABLE_INHERIT:
@@ -5026,14 +4505,6 @@ index 0000000..aa3dca1
 +      && strcasecmp (mips_elf64_howto_table_rela[i].name, r_name) == 0)
 +      return &mips_elf64_howto_table_rela[i];
 +
-+  for (i = 0;
-+       i < (sizeof (mips16_elf64_howto_table_rela)
-+          / sizeof (mips16_elf64_howto_table_rela[0]));
-+       i++)
-+    if (mips16_elf64_howto_table_rela[i].name != NULL
-+      && strcasecmp (mips16_elf64_howto_table_rela[i].name, r_name) == 0)
-+      return &mips16_elf64_howto_table_rela[i];
-+
 +  if (strcasecmp (elf_mips_gnu_vtinherit_howto.name, r_name) == 0)
 +    return &elf_mips_gnu_vtinherit_howto;
 +  if (strcasecmp (elf_mips_gnu_vtentry_howto.name, r_name) == 0)
@@ -5071,13 +4542,6 @@ index 0000000..aa3dca1
 +    case R_RISCV_JUMP_SLOT:
 +      return &elf_mips_jump_slot_howto;
 +    default:
-+      if (r_type >= R_MIPS16_min && r_type < R_MIPS16_max)
-+      {
-+        if (rela_p)
-+          return &mips16_elf64_howto_table_rela[r_type - R_MIPS16_min];
-+        else
-+          return &mips16_elf64_howto_table_rel[r_type - R_MIPS16_min];
-+      }
 +      BFD_ASSERT (r_type < (unsigned int) R_RISCV_max);
 +      if (rela_p)
 +      return &mips_elf64_howto_table_rela[r_type];
@@ -5976,10 +5440,10 @@ index 0000000..aa3dca1
 +#include "elf64-target.h"
 diff --git a/binutils-2.21.1/bfd/elfxx-riscv.c b/binutils-2.21.1/bfd/elfxx-riscv.c
 new file mode 100644
-index 0000000..f6b350e
+index 0000000..529ee79
 --- /dev/null
 +++ binutils-2.21.1/bfd/elfxx-riscv.c
-@@ -0,0 +1,8324 @@
+@@ -0,0 +1,7401 @@
 +/* MIPS-specific support for ELF
 +   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
 +   2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
@@ -6209,35 +5673,6 @@ index 0000000..f6b350e
 +#define GGA_RELOC_ONLY 1
 +#define GGA_NONE 2
 +
-+/* Information about a non-PIC interface to a PIC function.  There are
-+   two ways of creating these interfaces.  The first is to add:
-+
-+      lui     t7,%hi(func)
-+      addi    t7,t7,%lo(func)
-+
-+   immediately before a PIC function "func".  The second is to add:
-+
-+      lui     t7,%hi(func)
-+      addi    t7,t7,%lo(func)
-+      j       func
-+
-+   to a separate trampoline section.
-+
-+   Stubs of the first kind go in a new section immediately before the
-+   target function.  Stubs of the second kind go in a single section
-+   pointed to by the hash table's "strampoline" field.  */
-+struct mips_elf_la25_stub {
-+  /* The generated section that contains this stub.  */
-+  asection *stub_section;
-+
-+  /* The offset of the stub from the start of STUB_SECTION.  */
-+  bfd_vma offset;
-+
-+  /* One symbol for the original function.  Its location is available
-+     in H->root.root.u.def.  */
-+  struct mips_elf_link_hash_entry *h;
-+};
-+
 +/* This structure is passed to mips_elf_sort_hash_table_f when sorting
 +   the dynamic symbols.  */
 +
@@ -6268,9 +5703,6 @@ index 0000000..f6b350e
 +  /* External symbol information.  */
 +  EXTR esym;
 +
-+  /* The la25 stub we have created for ths symbol, if any.  */
-+  struct mips_elf_la25_stub *la25_stub;
-+
 +  /* Number of R_RISCV_32, R_RISCV_REL32, or R_RISCV_64 relocs against
 +     this symbol.  */
 +  unsigned int possibly_dynamic_relocs;
@@ -6294,11 +5726,6 @@ index 0000000..f6b350e
 +  /* The highest GGA_* value that satisfies all references to this symbol.  */
 +  unsigned int global_got_area : 2;
 +
-+  /* True if all GOT relocations against this symbol are for calls.  This is
-+     a looser condition than no_fn_stub below, because there may be other
-+     non-call non-GOT relocations against the symbol.  */
-+  unsigned int got_only_for_calls : 1;
-+
 +  /* True if one of the relocations described by possibly_dynamic_relocs
 +     is against a readonly section.  */
 +  unsigned int readonly_reloc : 1;
@@ -6307,21 +5734,6 @@ index 0000000..f6b350e
 +     resolved by the static linker (in other words, if the relocation
 +     cannot possibly be made dynamic).  */
 +  unsigned int has_static_relocs : 1;
-+
-+  /* True if we must not create a .MIPS.stubs entry for this symbol.
-+     This is set, for example, if there are relocations related to
-+     taking the function's address, i.e. any but R_RISCV_CALL*16 ones.
-+     See "MIPS ABI Supplement, 3rd Edition", p. 4-20.  */
-+  unsigned int no_fn_stub : 1;
-+
-+  /* True if this symbol is referenced by branch relocations from
-+     any non-PIC input file.  This is used to determine whether an
-+     la25 stub is required.  */
-+  unsigned int has_nonpic_branches : 1;
-+
-+  /* Does this symbol need a traditional MIPS lazy-binding stub
-+     (as opposed to a PLT entry)?  */
-+  unsigned int needs_lazy_stub : 1;
 +};
 +
 +/* MIPS ELF linker hash table.  */
@@ -6335,19 +5747,6 @@ index 0000000..f6b350e
 +  bfd_size_type dynsym_sec_strindex[SIZEOF_MIPS_DYNSYM_SECNAMES];
 +#endif
 +
-+  /* The number of .rtproc entries.  */
-+  bfd_size_type procedure_count;
-+
-+  /* This flag indicates that the value of DT_MIPS_RLD_MAP dynamic
-+     entry is set to the address of __rld_obj_head as in IRIX5.  */
-+  bfd_boolean use_rld_obj_head;
-+
-+  /* This is the value of the __rld_map or __rld_obj_head symbol.  */
-+  bfd_vma rld_value;
-+
-+  /* True if we can generate copy relocs and PLTs.  */
-+  bfd_boolean use_plts_and_copy_relocs;
-+
 +  /* Shortcuts to some dynamic sections, or NULL if they are not
 +     being used.  */
 +  asection *srelbss;
@@ -6356,7 +5755,6 @@ index 0000000..f6b350e
 +  asection *srelplt2;
 +  asection *sgotplt;
 +  asection *splt;
-+  asection *sstubs;
 +  asection *sgot;
 +
 +  /* The master GOT information.  */
@@ -6368,31 +5766,8 @@ index 0000000..f6b350e
 +  /* The size of a PLT entry in bytes.  */
 +  bfd_vma plt_entry_size;
 +
-+  /* The number of functions that need a lazy-binding stub.  */
-+  bfd_vma lazy_stub_count;
-+
-+  /* The size of a function stub entry in bytes.  */
-+  bfd_vma function_stub_size;
-+
 +  /* The number of reserved entries at the beginning of the GOT.  */
 +  unsigned int reserved_gotno;
-+
-+  /* The section used for mips_elf_la25_stub trampolines.
-+     See the comment above that structure for details.  */
-+  asection *strampoline;
-+
-+  /* A table of mips_elf_la25_stubs, indexed by (input_section, offset)
-+     pairs.  */
-+  htab_t la25_stubs;
-+
-+  /* A function FN (NAME, IS, OS) that creates a new input section
-+     called NAME and links it to output section OS.  If IS is nonnull,
-+     the new section should go immediately before it, otherwise it
-+     should go at the (current) beginning of OS.
-+
-+     The function returns the new section on success, otherwise it
-+     returns null.  */
-+  asection *(*add_stub_section) (const char *, asection *, asection *);
 +};
 +
 +/* Get the MIPS ELF linker hash table from a link_info structure.  */
@@ -6512,9 +5887,6 @@ index 0000000..f6b350e
 +  ((sec->flags & (SEC_ALLOC | SEC_LOAD | SEC_READONLY))               \
 +   == (SEC_ALLOC | SEC_LOAD | SEC_READONLY))
 +
-+/* The name of the stub section.  */
-+#define MIPS_ELF_STUB_SECTION_NAME(abfd) ".MIPS.stubs"
-+
 +/* The size of an external REL relocation.  */
 +#define MIPS_ELF_REL_SIZE(abfd) \
 +  (get_elf_backend_data (abfd)->s->sizeof_rel)
@@ -6602,6 +5974,7 @@ index 0000000..f6b350e
 +   && OPCODE_IS_STORE(opcode))
 +
 +#define MATCH_LREG(abfd) (ABI_64_P(abfd) ? MATCH_LD : MATCH_LW)
++#define MATCH_SREG(abfd) (ABI_64_P(abfd) ? MATCH_SD : MATCH_SW)
 +
 +#define OPCODE_MATCHES(OPCODE, OP) \
 +  (((OPCODE) & MASK_##OP) == MATCH_##OP)
@@ -6613,48 +5986,67 @@ index 0000000..f6b350e
 +
 +/* The format of the first PLT entry.  */
 +
-+#define RISCV_PLT0_ENTRY_INSNS 8
++#define RISCV_PLT0_ENTRY_INSNS 44
 +static void
-+riscv_make_plt0_entry(bfd* abfd, bfd_vma gotplt_value,
++riscv_make_plt0_entry(bfd* abfd, bfd_vma gotplt_value, bfd_vma addr,
 +                      bfd_vma entry[RISCV_PLT0_ENTRY_INSNS])
 +{
-+  /* lui    t2, %hi(GOTPLT)
-+     l[w|d] t7, %lo(GOTPLT)(t2)
-+     addi   t2, t2, %lo(GOTPLT)
-+     sub    t6, t6, t2
-+     move   t5, ra
-+     srli   t6, t6, (RV32 ? 2 : 3)
-+     addi   t6, t6, -2
-+     jalr   t7
++  /* save ra and arg registers to stack
++     auipc  v0, %hi(GOTPLT)
++     addi   v0, v0, %lo(GOTPLT)
++     sub    a1, v1, v0
++     ld     a0, PTRSIZE(v0)
++     ld     v0, 0(v0)
++     slli   a1, a1, 1
++     addi   a1, a1, -4*PTRSIZE
++     jalr   v0
++     restore ra and arg registers from stack
++     jr     v0
 +  */
 +
-+  entry[0] = RISCV_LTYPE(LUI, 14, RISCV_LUI_HIGH_PART(gotplt_value));
-+  entry[1] = RISCV_ITYPE(LREG(abfd),  19, 14, RISCV_CONST_LOW_PART(gotplt_value));
-+  entry[2] = RISCV_ITYPE(ADDI, 14, 14, RISCV_CONST_LOW_PART(gotplt_value));
-+  entry[3] = RISCV_RTYPE(SUB, 18, 18, 14);
-+  entry[4] = RISCV_ITYPE(ADDI, 17, LINK_REG, 0);
-+  entry[5] = RISCV_ITYPE(SRLI, 18, 18, ABI_64_P(abfd) ? 3 : 2);
-+  entry[6] = RISCV_ITYPE(ADDI, 18, 18, -2);
-+  entry[7] = RISCV_ITYPE(JALR_C, LINK_REG, 19, 0);
++  int i = 0, j, regbytes = ABI_64_P(abfd) ? 8 : 4;
++  entry[i++] = RISCV_ITYPE(ADDI, 14, 14, -16*regbytes);
++  entry[i++] = RISCV_BTYPE(SREG(abfd), 14, LINK_REG, 0);
++  for (j = 0; j < 14; j++)
++    entry[i++] = RISCV_BTYPE(SREG(abfd), 14, 18+j, (j+1)*regbytes);
++  gotplt_value -= addr + i*4;
++  entry[i++] = RISCV_LTYPE(AUIPC, 16, RISCV_LUI_HIGH_PART(gotplt_value));
++  entry[i++] = RISCV_ITYPE(ADDI, 16, 16, RISCV_CONST_LOW_PART(gotplt_value));
++  entry[i++] = RISCV_RTYPE(SUB, 19, 17, 16);
++  entry[i++] = RISCV_ITYPE(LREG(abfd), 18, 16, regbytes);
++  entry[i++] = RISCV_ITYPE(LREG(abfd), 16, 16, 0);
++  entry[i++] = RISCV_ITYPE(SLLI, 19, 19, 1);
++  entry[i++] = RISCV_ITYPE(ADDI, 19, 19, -4*regbytes);
++  entry[i++] = RISCV_ITYPE(JALR_C, LINK_REG, 16, 0);
++  entry[i++] = RISCV_ITYPE(LREG(abfd), LINK_REG, 14, 0);
++  for (j = 0; j < 14; j++)
++    entry[i++] = RISCV_ITYPE(LREG(abfd), 18+j, 14, (j+1)*regbytes);
++  entry[i++] = RISCV_ITYPE(ADDI, 14, 14, 16*regbytes);
++  entry[i++] = RISCV_ITYPE(JALR_J, 0, 16, 0);
++
++  BFD_ASSERT(i <= RISCV_PLT0_ENTRY_INSNS);
++  while (i < RISCV_PLT0_ENTRY_INSNS)
++    entry[i++] = RISCV_ITYPE(ADDI, 0, 0, 0);
 +}
 +
 +/* The format of subsequent PLT entries.  */
 +
 +#define RISCV_PLT_ENTRY_INSNS 4
 +static void
-+riscv_make_plt_entry(bfd* abfd, bfd_vma got_address,
++riscv_make_plt_entry(bfd* abfd, bfd_vma got_address, bfd_vma addr,
 +                     bfd_vma entry[RISCV_PLT_ENTRY_INSNS])
 +{
-+  /* lui    t6, %hi(.got.plt entry)
-+     l[w|d] t7, %lo(.got.plt entry)(t6)
-+     addi   t6, t6, %lo(.got.plt entry)
-+     jr     t7
++  /* auipc  v1, %hi(.got.plt entry)
++     l[w|d] v0, %lo(.got.plt entry)(t6)
++     addi   v1, v1, %lo(.got.plt entry)
++     jr     v0
 +  */
 +
-+  entry[0] = RISCV_LTYPE(LUI, 18, RISCV_LUI_HIGH_PART(got_address));
-+  entry[1] = RISCV_ITYPE(LREG(abfd),  19, 18, RISCV_CONST_LOW_PART(got_address));
-+  entry[2] = RISCV_ITYPE(ADDI, 18, 18, RISCV_CONST_LOW_PART(got_address));
-+  entry[3] = RISCV_ITYPE(JALR_J, 0, 19, 0);
++  got_address -= addr;
++  entry[0] = RISCV_LTYPE(AUIPC, 17, RISCV_LUI_HIGH_PART(got_address));
++  entry[1] = RISCV_ITYPE(LREG(abfd),  16, 17, RISCV_CONST_LOW_PART(got_address));
++  entry[2] = RISCV_ITYPE(ADDI, 17, 17, RISCV_CONST_LOW_PART(got_address));
++  entry[3] = RISCV_ITYPE(JALR_J, 0, 16, 0);
 +}
 +
 +/* Look up an entry in a MIPS ELF linker hash table.  */
@@ -6723,16 +6115,11 @@ index 0000000..f6b350e
 +      /* We use -2 as a marker to indicate that the information has
 +       not been set.  -1 means there is no associated ifd.  */
 +      ret->esym.ifd = -2;
-+      ret->la25_stub = 0;
 +      ret->possibly_dynamic_relocs = 0;
 +      ret->tls_type = GOT_NORMAL;
 +      ret->global_got_area = GGA_NONE;
-+      ret->got_only_for_calls = TRUE;
 +      ret->readonly_reloc = FALSE;
 +      ret->has_static_relocs = FALSE;
-+      ret->no_fn_stub = FALSE;
-+      ret->has_nonpic_branches = FALSE;
-+      ret->needs_lazy_stub = FALSE;
 +    }
 +
 +  return (struct bfd_hash_entry *) ret;
@@ -6816,299 +6203,31 @@ index 0000000..f6b350e
 +
 + error_return:
 +  if (ext_hdr != NULL)
-+    free (ext_hdr);
-+  if (debug->line != NULL)
-+    free (debug->line);
-+  if (debug->external_dnr != NULL)
-+    free (debug->external_dnr);
-+  if (debug->external_pdr != NULL)
-+    free (debug->external_pdr);
-+  if (debug->external_sym != NULL)
-+    free (debug->external_sym);
-+  if (debug->external_opt != NULL)
-+    free (debug->external_opt);
-+  if (debug->external_aux != NULL)
-+    free (debug->external_aux);
-+  if (debug->ss != NULL)
-+    free (debug->ss);
-+  if (debug->ssext != NULL)
-+    free (debug->ssext);
-+  if (debug->external_fdr != NULL)
-+    free (debug->external_fdr);
-+  if (debug->external_rfd != NULL)
-+    free (debug->external_rfd);
-+  if (debug->external_ext != NULL)
-+    free (debug->external_ext);
-+  return FALSE;
-+}
-+
-+/* We're going to create a stub for H.  Create a symbol for the stub's
-+   value and size, to help make the disassembly easier to read.  */
-+
-+static bfd_boolean
-+mips_elf_create_stub_symbol (struct bfd_link_info *info,
-+                           struct mips_elf_link_hash_entry *h,
-+                           const char *prefix, asection *s, bfd_vma value,
-+                           bfd_vma size)
-+{
-+  struct bfd_link_hash_entry *bh;
-+  struct elf_link_hash_entry *elfh;
-+  const char *name;
-+
-+  /* Create a new symbol.  */
-+  name = ACONCAT ((prefix, h->root.root.root.string, NULL));
-+  bh = NULL;
-+  if (!_bfd_generic_link_add_one_symbol (info, s->owner, name,
-+                                       BSF_LOCAL, s, value, NULL,
-+                                       TRUE, FALSE, &bh))
-+    return FALSE;
-+
-+  /* Make it a local function.  */
-+  elfh = (struct elf_link_hash_entry *) bh;
-+  elfh->type = ELF_ST_INFO (STB_LOCAL, STT_FUNC);
-+  elfh->size = size;
-+  elfh->forced_local = 1;
-+  return TRUE;
-+}
-+
-+/* Hashtable callbacks for mips_elf_la25_stubs.  */
-+
-+static hashval_t
-+mips_elf_la25_stub_hash (const void *entry_)
-+{
-+  const struct mips_elf_la25_stub *entry;
-+
-+  entry = (struct mips_elf_la25_stub *) entry_;
-+  return entry->h->root.root.u.def.section->id
-+    + entry->h->root.root.u.def.value;
-+}
-+
-+static int
-+mips_elf_la25_stub_eq (const void *entry1_, const void *entry2_)
-+{
-+  const struct mips_elf_la25_stub *entry1, *entry2;
-+
-+  entry1 = (struct mips_elf_la25_stub *) entry1_;
-+  entry2 = (struct mips_elf_la25_stub *) entry2_;
-+  return ((entry1->h->root.root.u.def.section
-+         == entry2->h->root.root.u.def.section)
-+        && (entry1->h->root.root.u.def.value
-+            == entry2->h->root.root.u.def.value));
-+}
-+
-+/* Called by the linker to set up the la25 stub-creation code.  FN is
-+   the linker's implementation of add_stub_function.  Return true on
-+   success.  */
-+
-+bfd_boolean
-+_bfd_riscv_elf_init_stubs (struct bfd_link_info *info,
-+                        asection *(*fn) (const char *, asection *,
-+                                         asection *))
-+{
-+  struct mips_elf_link_hash_table *htab;
-+
-+  htab = mips_elf_hash_table (info);
-+  if (htab == NULL)
-+    return FALSE;
-+
-+  htab->add_stub_section = fn;
-+  htab->la25_stubs = htab_try_create (1, mips_elf_la25_stub_hash,
-+                                    mips_elf_la25_stub_eq, NULL);
-+  if (htab->la25_stubs == NULL)
-+    return FALSE;
-+
-+  return TRUE;
-+}
-+
-+/* Return true if H is a locally-defined PIC function, in the sense
-+   that it might need $25 to be valid on entry.  Note that MIPS16
-+   functions never need $25 to be valid on entry; they set up $gp
-+   using PC-relative instructions instead.  */
-+
-+static bfd_boolean
-+mips_elf_local_pic_function_p (struct mips_elf_link_hash_entry *h)
-+{
-+  return ((h->root.root.type == bfd_link_hash_defined
-+         || h->root.root.type == bfd_link_hash_defweak)
-+        && h->root.def_regular
-+        && !bfd_is_abs_section (h->root.root.u.def.section)
-+        && !ELF_ST_IS_MIPS16 (h->root.other)
-+        && (PIC_OBJECT_P (h->root.root.u.def.section->owner)
-+            || ELF_ST_IS_MIPS_PIC (h->root.other)));
-+}
-+
-+/* STUB describes an la25 stub that we have decided to implement
-+   by inserting RDNPC before the target function.
-+   Create the section and redirect the function symbol to it.  */
-+
-+static bfd_boolean
-+mips_elf_add_la25_intro (struct mips_elf_la25_stub *stub,
-+                       struct bfd_link_info *info)
-+{
-+  struct mips_elf_link_hash_table *htab;
-+  char *name;
-+  asection *s, *input_section;
-+  unsigned int align;
-+
-+  htab = mips_elf_hash_table (info);
-+  if (htab == NULL)
-+    return FALSE;
-+
-+  /* Create a unique name for the new section.  */
-+  name = bfd_malloc (11 + sizeof (".text.stub."));
-+  if (name == NULL)
-+    return FALSE;
-+  sprintf (name, ".text.stub.%d", (int) htab_elements (htab->la25_stubs));
-+
-+  /* Create the section.  */
-+  input_section = stub->h->root.root.u.def.section;
-+  s = htab->add_stub_section (name, input_section,
-+                            input_section->output_section);
-+  if (s == NULL)
-+    return FALSE;
-+
-+  /* Make sure that any padding goes before the stub.  */
-+  align = input_section->alignment_power;
-+  if (!bfd_set_section_alignment (s->owner, s, align))
-+    return FALSE;
-+  if (align > 2)
-+    s->size = (1 << align) - 4;
-+
-+  /* Create a symbol for the stub.  */
-+  mips_elf_create_stub_symbol (info, stub->h, ".pic.", s, s->size, 8);
-+  stub->stub_section = s;
-+  stub->offset = s->size;
-+
-+  /* Allocate room for it.  */
-+  s->size += 4;
-+  return TRUE;
-+}
-+
-+/* STUB describes an la25 stub that we have decided to implement
-+   with a separate trampoline.  Allocate room for it and redirect
-+   the function symbol to it.  */
-+
-+static bfd_boolean
-+mips_elf_add_la25_trampoline (struct mips_elf_la25_stub *stub,
-+                            struct bfd_link_info *info)
-+{
-+  struct mips_elf_link_hash_table *htab;
-+  asection *s;
-+
-+  htab = mips_elf_hash_table (info);
-+  if (htab == NULL)
-+    return FALSE;
-+
-+  /* Create a trampoline section, if we haven't already.  */
-+  s = htab->strampoline;
-+  if (s == NULL)
-+    {
-+      asection *input_section = stub->h->root.root.u.def.section;
-+      s = htab->add_stub_section (".text", NULL,
-+                                input_section->output_section);
-+      if (s == NULL || !bfd_set_section_alignment (s->owner, s, 4))
-+      return FALSE;
-+      htab->strampoline = s;
-+    }
-+
-+  /* Create a symbol for the stub.  */
-+  mips_elf_create_stub_symbol (info, stub->h, ".pic.", s, s->size, 16);
-+  stub->stub_section = s;
-+  stub->offset = s->size;
-+
-+  /* Allocate room for it.  */
-+  s->size += 16;
-+  return TRUE;
-+}
-+
-+/* H describes a symbol that needs an la25 stub.  Make sure that an
-+   appropriate stub exists and point H at it.  */
-+
-+static bfd_boolean
-+mips_elf_add_la25_stub (struct bfd_link_info *info,
-+                      struct mips_elf_link_hash_entry *h)
-+{
-+  struct mips_elf_link_hash_table *htab;
-+  struct mips_elf_la25_stub search, *stub;
-+  bfd_boolean use_trampoline_p;
-+  asection *s;
-+  bfd_vma value;
-+  void **slot;
-+
-+  /* Prefer to use LUI/ADDIU stubs if the function is at the beginning
-+     of the section and if we would need no more than 2 nops.  */
-+  s = h->root.root.u.def.section;
-+  value = h->root.root.u.def.value;
-+  use_trampoline_p = (value != 0 || s->alignment_power > 4);
-+
-+  /* Describe the stub we want.  */
-+  search.stub_section = NULL;
-+  search.offset = 0;
-+  search.h = h;
-+
-+  /* See if we've already created an equivalent stub.  */
-+  htab = mips_elf_hash_table (info);
-+  if (htab == NULL)
-+    return FALSE;
-+
-+  slot = htab_find_slot (htab->la25_stubs, &search, INSERT);
-+  if (slot == NULL)
-+    return FALSE;
-+
-+  stub = (struct mips_elf_la25_stub *) *slot;
-+  if (stub != NULL)
-+    {
-+      /* We can reuse the existing stub.  */
-+      h->la25_stub = stub;
-+      return TRUE;
-+    }
-+
-+  /* Create a permanent copy of ENTRY and add it to the hash table.  */
-+  stub = bfd_malloc (sizeof (search));
-+  if (stub == NULL)
-+    return FALSE;
-+  *stub = search;
-+  *slot = stub;
-+
-+  h->la25_stub = stub;
-+  return (use_trampoline_p
-+        ? mips_elf_add_la25_trampoline (stub, info)
-+        : mips_elf_add_la25_intro (stub, info));
-+}
-+
-+/* A mips_elf_link_hash_traverse callback that is called before sizing
-+   sections.  DATA points to a mips_htab_traverse_info structure.  */
-+
-+static bfd_boolean
-+mips_elf_check_symbols (struct mips_elf_link_hash_entry *h, void *data)
-+{
-+  struct mips_htab_traverse_info *hti;
-+
-+  hti = (struct mips_htab_traverse_info *) data;
-+  if (h->root.root.type == bfd_link_hash_warning)
-+    h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link;
-+
-+  if (mips_elf_local_pic_function_p (h))
-+    {
-+      /* H is a function that might need $25 to be valid on entry.
-+       If we're creating a non-PIC relocatable object, mark H as
-+       being PIC.  If we're creating a non-relocatable object with
-+       non-PIC branches and jumps to H, make sure that H has an la25
-+       stub.  */
-+      if (hti->info->relocatable)
-+      {
-+        if (!PIC_OBJECT_P (hti->output_bfd))
-+          h->root.other = ELF_ST_SET_MIPS_PIC (h->root.other);
-+      }
-+      else if (h->has_nonpic_branches && !mips_elf_add_la25_stub (hti->info, h))
-+      {
-+        hti->error = TRUE;
-+        return FALSE;
-+      }
-+    }
-+  return TRUE;
++    free (ext_hdr);
++  if (debug->line != NULL)
++    free (debug->line);
++  if (debug->external_dnr != NULL)
++    free (debug->external_dnr);
++  if (debug->external_pdr != NULL)
++    free (debug->external_pdr);
++  if (debug->external_sym != NULL)
++    free (debug->external_sym);
++  if (debug->external_opt != NULL)
++    free (debug->external_opt);
++  if (debug->external_aux != NULL)
++    free (debug->external_aux);
++  if (debug->ss != NULL)
++    free (debug->ss);
++  if (debug->ssext != NULL)
++    free (debug->ssext);
++  if (debug->external_fdr != NULL)
++    free (debug->external_fdr);
++  if (debug->external_rfd != NULL)
++    free (debug->external_rfd);
++  if (debug->external_ext != NULL)
++    free (debug->external_ext);
++  return FALSE;
 +}
-+\f
 +
 +static inline bfd_boolean
 +got16_reloc_p (int r_type)
@@ -7613,15 +6732,11 @@ index 0000000..f6b350e
 +              h->esym.asym.sc = scText;
 +            else if (strcmp (name, ".data") == 0)
 +              h->esym.asym.sc = scData;
-+            else if (strcmp (name, ".sdata") == 0)
-+              h->esym.asym.sc = scSData;
 +            else if (strcmp (name, ".rodata") == 0
 +                     || strcmp (name, ".rdata") == 0)
 +              h->esym.asym.sc = scRData;
 +            else if (strcmp (name, ".bss") == 0)
 +              h->esym.asym.sc = scBss;
-+            else if (strcmp (name, ".sbss") == 0)
-+              h->esym.asym.sc = scSBss;
 +            else if (strcmp (name, ".init") == 0)
 +              h->esym.asym.sc = scInit;
 +            else if (strcmp (name, ".fini") == 0)
@@ -7640,10 +6755,8 @@ index 0000000..f6b350e
 +  else if (h->root.root.type == bfd_link_hash_defined
 +         || h->root.root.type == bfd_link_hash_defweak)
 +    {
-+      if (h->esym.asym.sc == scCommon)
++      if (h->esym.asym.sc == scCommon || h->esym.asym.sc == scSCommon)
 +      h->esym.asym.sc = scBss;
-+      else if (h->esym.asym.sc == scSCommon)
-+      h->esym.asym.sc = scSBss;
 +
 +      sec = h->root.root.u.def.section;
 +      output_section = sec->output_section;
@@ -7654,32 +6767,6 @@ index 0000000..f6b350e
 +      else
 +      h->esym.asym.value = 0;
 +    }
-+  else
-+    {
-+      struct mips_elf_link_hash_entry *hd = h;
-+
-+      while (hd->root.root.type == bfd_link_hash_indirect)
-+      hd = (struct mips_elf_link_hash_entry *)h->root.root.u.i.link;
-+
-+      if (hd->needs_lazy_stub)
-+      {
-+        /* Set type and value for a symbol with a function stub.  */
-+        h->esym.asym.st = stProc;
-+        sec = hd->root.root.u.def.section;
-+        if (sec == NULL)
-+          h->esym.asym.value = 0;
-+        else
-+          {
-+            output_section = sec->output_section;
-+            if (output_section != NULL)
-+              h->esym.asym.value = (hd->root.plt.offset
-+                                    + sec->output_offset
-+                                    + output_section->vma);
-+            else
-+              h->esym.asym.value = 0;
-+          }
-+      }
-+    }
 +
 +  if (! bfd_ecoff_debug_one_external (einfo->abfd, einfo->debug, einfo->swap,
 +                                    h->root.root.root.string,
@@ -8418,7 +7505,6 @@ index 0000000..f6b350e
 +static bfd_boolean
 +mips_elf_record_global_got_symbol (struct elf_link_hash_entry *h,
 +                                 bfd *abfd, struct bfd_link_info *info,
-+                                 bfd_boolean for_call,
 +                                 unsigned char tls_flag)
 +{
 +  struct mips_elf_link_hash_table *htab;
@@ -8430,8 +7516,6 @@ index 0000000..f6b350e
 +  BFD_ASSERT (htab != NULL);
 +
 +  hmips = (struct mips_elf_link_hash_entry *) h;
-+  if (!for_call)
-+    hmips->got_only_for_calls = FALSE;
 +
 +  /* A global symbol in the GOT must also be in the dynamic symbol
 +     table.  */
@@ -8807,10 +7891,7 @@ index 0000000..f6b350e
 +       Note that the former condition does not always imply the
 +       latter: symbols do not bind locally if they are completely
 +       undefined.  We'll report undefined symbols later if appropriate.  */
-+      if (h->root.dynindx == -1
-+        || (h->got_only_for_calls
-+            ? SYMBOL_CALLS_LOCAL (info, &h->root)
-+            : SYMBOL_REFERENCES_LOCAL (info, &h->root)))
++      if (h->root.dynindx == -1 || SYMBOL_REFERENCES_LOCAL (info, &h->root))
 +      {
 +        /* The symbol belongs in the local GOT.  We no longer need this
 +           entry if it was only used for relocations; those relocations
@@ -9032,8 +8113,7 @@ index 0000000..f6b350e
 +  if (g->got_page_entries == NULL)
 +    return FALSE;
 +  htab->got_info = g;
-+  mips_elf_section_data (s)->elf.this_hdr.sh_flags
-+    |= SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL;
++  mips_elf_section_data (s)->elf.this_hdr.sh_flags |= SHF_ALLOC | SHF_WRITE;
 +
 +  /* We also need a .got.plt section when generating PLTs.  */
 +  s = bfd_make_section_with_flags (abfd, ".got.plt",
@@ -9046,34 +8126,6 @@ index 0000000..f6b350e
 +  return TRUE;
 +}
 +
-+/* Return TRUE if a relocation of type R_TYPE from INPUT_BFD might
-+   require an la25 stub.  See also mips_elf_local_pic_function_p,
-+   which determines whether the destination function ever requires a
-+   stub.  */
-+
-+static bfd_boolean
-+mips_elf_relocation_needs_la25_stub (bfd *input_bfd, int r_type)
-+{
-+  /* We specifically ignore branches and jumps from EF_PIC objects,
-+     where the onus is on the compiler or programmer to perform any
-+     necessary initialization of $25.  Sometimes such initialization
-+     is unnecessary; for example, -mno-shared functions do not use
-+     the incoming value of $25, and may therefore be called directly.  */
-+  if (PIC_OBJECT_P (input_bfd))
-+    return FALSE;
-+
-+  switch (r_type)
-+    {
-+    case R_RISCV_26:
-+    case R_RISCV_PC16:
-+    case R_MIPS16_26:
-+      return TRUE;
-+
-+    default:
-+      return FALSE;
-+    }
-+}
-+\f
 +/* Calculate the value produced by the RELOCATION (which comes from
 +   the INPUT_BFD).  The ADDEND is the addend to use for this
 +   RELOCATION; RELOCATION->R_ADDEND is ignored.
@@ -9122,9 +8174,6 @@ index 0000000..f6b350e
 +  /* TRUE if the symbol referred to by this relocation is a local
 +     symbol.  */
 +  bfd_boolean local_p, was_local_p;
-+  /* TRUE if the symbol referred to by this relocation is
-+     "__gnu_local_gp".  */
-+  bfd_boolean gnu_local_gp_p = FALSE;
 +  Elf_Internal_Shdr *symtab_hdr;
 +  size_t extsymoff;
 +  unsigned long r_symndx;
@@ -9185,10 +8234,6 @@ index 0000000..f6b350e
 +        addend += sec->output_section->vma + sec->output_offset;
 +      }
 +
-+      /* MIPS16 text labels should be treated as odd.  */
-+      if (ELF_ST_IS_MIPS16 (sym->st_other))
-+      ++symbol;
-+
 +      /* Record the name of this symbol, for our caller.  */
 +      *namep = bfd_elf_string_from_elf_section (input_bfd,
 +                                              symtab_hdr->sh_link,
@@ -9211,17 +8256,11 @@ index 0000000..f6b350e
 +      /* Record the name of this symbol, for our caller.  */
 +      *namep = h->root.root.root.string;
 +
-+      /* See if this is the special _gp symbol.  Note that such a
-+       symbol must always be a global symbol.  */
-+      if (strcmp (*namep, "__gnu_local_gp") == 0)
-+      gnu_local_gp_p = TRUE;
-+
-+
 +      /* If this symbol is defined, calculate its address.  Note that
 +       _gp_disp is a magic symbol, always implicitly defined by the
 +       linker, so it's inappropriate to check to see whether or not
 +       its defined.  */
-+      else if ((h->root.root.type == bfd_link_hash_defined
++      if ((h->root.root.type == bfd_link_hash_defined
 +              || h->root.root.type == bfd_link_hash_defweak)
 +             && h->root.root.u.def.section)
 +      {
@@ -9268,22 +8307,11 @@ index 0000000..f6b350e
 +      }
 +    }
 +
-+  /* If this is a direct call to a PIC function, redirect to the
-+     non-PIC stub.  */
-+  if (h != NULL && h->la25_stub
-+         && mips_elf_relocation_needs_la25_stub (input_bfd, r_type))
-+    symbol = (h->la25_stub->stub_section->output_section->vma
-+            + h->la25_stub->stub_section->output_offset
-+            + h->la25_stub->offset);
-+
 +  local_p = h == NULL || SYMBOL_REFERENCES_LOCAL (info, &h->root);
 +
 +  gp0 = _bfd_get_gp_value (input_bfd);
 +  gp = _bfd_get_gp_value (abfd);
 +
-+  if (gnu_local_gp_p)
-+    symbol = gp;
-+
 +  /* If we haven't already determined the GOT offset, and we're going
 +     to need it, get it now.  */
 +  switch (r_type)
@@ -9515,7 +8543,7 @@ index 0000000..f6b350e
 +      /* We're allowed to handle these two relocations identically.
 +       The dynamic linker is allowed to handle the CALL relocations
 +       differently by creating a lazy evaluation stub.  */
-+      value = mips_elf_high (g) << OP_SH_BIGIMMEDIATE;
++      value = (mips_elf_high (g - p + gp) << OP_SH_BIGIMMEDIATE);
 +      break;
 +
 +    case R_RISCV_TLS_GOT_LO16:
@@ -9523,7 +8551,7 @@ index 0000000..f6b350e
 +    case R_RISCV_TLS_LDM_LO16:
 +    case R_RISCV_GOT_LO16:
 +    case R_RISCV_CALL_LO16:
-+      value = (g << OP_SH_IMMEDIATE) & howto->dst_mask;
++      value = ((g - p + gp) << OP_SH_IMMEDIATE) & howto->dst_mask;
 +      break;
 +
 +    case R_RISCV_SUB:
@@ -9612,11 +8640,8 @@ index 0000000..f6b350e
 +      dst_mask = (OP_MASK_IMMHI << OP_SH_IMMHI) | (OP_MASK_IMMLO << OP_SH_IMMLO);
 +    }
 +
-+  /* Clear the field we are setting.  */
-+  x &= ~dst_mask;
-+
-+  /* Set the field.  */
-+  x |= (value & dst_mask);
++  /* Update the field, adding in any nonzero bits in the original. */
++  x = (x &~ dst_mask) | (((x & dst_mask) + value) & dst_mask);
 +
 +  /* Put the value into the output.  */
 +  bfd_put (8 * bfd_get_reloc_size (howto), input_bfd, x, location);
@@ -10058,31 +9083,7 @@ index 0000000..f6b350e
 +    {
 +      const char *name = bfd_get_section_name (abfd, hdr->bfd_section);
 +
-+      /* .sbss is not handled specially here because the GNU/Linux
-+       prelinker can convert .sbss from NOBITS to PROGBITS and
-+       changing it back to NOBITS breaks the binary.  The entry in
-+       _bfd_riscv_elf_special_sections will ensure the correct flags
-+       are set on .sbss if BFD creates it without reading it from an
-+       input file, and without special handling here the flags set
-+       on it in an input file will be followed.  */
-+      if (strcmp (name, ".sdata") == 0
-+        || strcmp (name, ".lit8") == 0
-+        || strcmp (name, ".lit4") == 0)
-+      {
-+        hdr->sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL;
-+        hdr->sh_type = SHT_PROGBITS;
-+      }
-+      else if (strcmp (name, ".srdata") == 0)
-+      {
-+        hdr->sh_flags |= SHF_ALLOC | SHF_MIPS_GPREL;
-+        hdr->sh_type = SHT_PROGBITS;
-+      }
-+      else if (strcmp (name, ".compact_rel") == 0)
-+      {
-+        hdr->sh_flags = 0;
-+        hdr->sh_type = SHT_PROGBITS;
-+      }
-+      else if (strcmp (name, ".rtproc") == 0)
++      if (strcmp (name, ".rtproc") == 0)
 +      {
 +        if (hdr->sh_addralign != 0 && hdr->sh_entsize == 0)
 +          {
@@ -10512,9 +9513,6 @@ index 0000000..f6b350e
 +      && strcmp (input_sec->name, ".scommon") == 0)
 +    sym->st_shndx = SHN_MIPS_SCOMMON;
 +
-+  if (ELF_ST_IS_MIPS16 (sym->st_other))
-+    sym->st_value &= ~1;
-+
 +  return 1;
 +}
 +\f
@@ -10552,26 +9550,6 @@ index 0000000..f6b350e
 +  if (! mips_elf_rel_dyn_section (info, TRUE))
 +    return FALSE;
 +
-+  /* Create .stub section.  */
-+  s = bfd_make_section_with_flags (abfd,
-+                                 MIPS_ELF_STUB_SECTION_NAME (abfd),
-+                                 flags | SEC_CODE);
-+  if (s == NULL
-+      || ! bfd_set_section_alignment (abfd, s,
-+                                    MIPS_ELF_LOG_FILE_ALIGN (abfd)))
-+    return FALSE;
-+  htab->sstubs = s;
-+
-+  if (!info->shared && bfd_get_section_by_name (abfd, ".rld_map") == NULL)
-+    {
-+      s = bfd_make_section_with_flags (abfd, ".rld_map",
-+                                     flags &~ (flagword) SEC_READONLY);
-+      if (s == NULL
-+        || ! bfd_set_section_alignment (abfd, s,
-+                                        MIPS_ELF_LOG_FILE_ALIGN (abfd)))
-+      return FALSE;
-+    }
-+
 +  if (!info->shared)
 +    {
 +      const char *name;
@@ -10590,31 +9568,6 @@ index 0000000..f6b350e
 +
 +      if (! bfd_elf_link_record_dynamic_symbol (info, h))
 +      return FALSE;
-+
-+      if (! mips_elf_hash_table (info)->use_rld_obj_head)
-+      {
-+        /* __rld_map is a four byte word located in the .data section
-+           and is filled in by the rtld to contain a pointer to
-+           the _r_debug structure. Its symbol value will be set in
-+           _bfd_riscv_elf_finish_dynamic_symbol.  */
-+        s = bfd_get_section_by_name (abfd, ".rld_map");
-+        BFD_ASSERT (s != NULL);
-+
-+        name = "__RLD_MAP";
-+        bh = NULL;
-+        if (!(_bfd_generic_link_add_one_symbol
-+              (info, abfd, name, BSF_GLOBAL, s, 0, NULL, FALSE,
-+               get_elf_backend_data (abfd)->collect, &bh)))
-+          return FALSE;
-+
-+        h = (struct elf_link_hash_entry *) bh;
-+        h->non_elf = 0;
-+        h->def_regular = 1;
-+        h->type = STT_OBJECT;
-+
-+        if (! bfd_elf_link_record_dynamic_symbol (info, h))
-+          return FALSE;
-+      }
 +    }
 +
 +  /* Create the .plt, .rel(a).plt, .dynbss and .rel(a).bss sections.
@@ -10631,12 +9584,8 @@ index 0000000..f6b350e
 +      || !htab->splt)
 +    abort ();
 +
-+  if (!info->shared)
-+    {
-+      /* All variants of the plt0 entry are the same size.  */
-+      htab->plt_header_size = RISCV_PLT0_ENTRY_INSNS * 4;
-+      htab->plt_entry_size = RISCV_PLT_ENTRY_INSNS * 4;
-+    }
++  htab->plt_header_size = RISCV_PLT0_ENTRY_INSNS * 4;
++  htab->plt_entry_size = RISCV_PLT_ENTRY_INSNS * 4;
 +
 +  return TRUE;
 +}
@@ -10863,7 +9812,6 @@ index 0000000..f6b350e
 +           against a read-only section.  */
 +        if ((info->shared
 +             || (h != NULL
-+                 && strcmp (h->root.root.string, "__gnu_local_gp") != 0
 +                 && !(!info->nocopyreloc
 +                      && !PIC_OBJECT_P (abfd)
 +                      && MIPS_ELF_READONLY_SECTION (sec))))
@@ -10927,9 +9875,6 @@ index 0000000..f6b350e
 +          return FALSE;
 +      }
 +
-+      if (h != NULL && mips_elf_relocation_needs_la25_stub (abfd, r_type))
-+      ((struct mips_elf_link_hash_entry *) h)->has_nonpic_branches = TRUE;
-+
 +      switch (r_type)
 +      {
 +      case R_RISCV_CALL16:
@@ -10944,24 +9889,6 @@ index 0000000..f6b350e
 +          }
 +        /* Fall through.  */
 +
-+      case R_RISCV_CALL_HI16:
-+      case R_RISCV_CALL_LO16:
-+        if (h != NULL)
-+          {
-+            /* Make sure there is room in the regular GOT to hold the
-+               function's address.  We may eliminate it in favour of
-+               a .got.plt entry later; see mips_elf_count_got_symbols.  */
-+            if (!mips_elf_record_global_got_symbol (h, abfd, info, TRUE, 0))
-+              return FALSE;
-+
-+            /* We need a stub, not a plt entry for the undefined
-+               function.  But we record it as if it needs plt.  See
-+               _bfd_elf_adjust_dynamic_symbol.  */
-+            h->needs_plt = 1;
-+            h->type = STT_FUNC;
-+          }
-+        break;
-+
 +      case R_MIPS16_GOT16:
 +      case R_RISCV_GOT16:
 +      case R_RISCV_GOT_HI16:
@@ -10991,8 +9918,7 @@ index 0000000..f6b350e
 +        /* Fall through.  */
 +
 +      case R_RISCV_GOT_DISP:
-+        if (h && !mips_elf_record_global_got_symbol (h, abfd, info,
-+                                                     FALSE, 0))
++        if (h && !mips_elf_record_global_got_symbol (h, abfd, info, 0))
 +          return FALSE;
 +        break;
 +
@@ -11030,8 +9956,7 @@ index 0000000..f6b350e
 +                (struct mips_elf_link_hash_entry *) h;
 +              hmips->tls_type |= flag;
 +
-+              if (h && !mips_elf_record_global_got_symbol (h, abfd, info,
-+                                                           FALSE, flag))
++              if (h && !mips_elf_record_global_got_symbol (h, abfd, info, flag))
 +                return FALSE;
 +            }
 +          else
@@ -11123,22 +10048,6 @@ index 0000000..f6b350e
 +        break;
 +      }
 +
-+      /* We must not create a stub for a symbol that has relocations
-+       related to taking the function's address. */
-+      if (h != NULL)
-+      switch (r_type)
-+        {
-+        default:
-+          ((struct mips_elf_link_hash_entry *) h)->no_fn_stub = TRUE;
-+          break;
-+        case R_MIPS16_CALL16:
-+        case R_RISCV_CALL16:
-+        case R_RISCV_CALL_HI16:
-+        case R_RISCV_CALL_LO16:
-+        case R_RISCV_JALR:
-+          break;
-+        }
-+
 +      /* Refuse some position-dependent relocations when creating a
 +       shared library.  Do not refuse R_RISCV_32 / R_RISCV_64; they're
 +       not PIC, but we can create dynamic relocations and the result
@@ -11238,7 +10147,6 @@ index 0000000..f6b350e
 +           relocations against it. */
 +        if (hmips->global_got_area > GGA_RELOC_ONLY)
 +          hmips->global_got_area = GGA_RELOC_ONLY;
-+        hmips->got_only_for_calls = FALSE;
 +
 +        mips_elf_allocate_dynamic_relocations
 +          (dynobj, info, hmips->possibly_dynamic_relocs);
@@ -11282,27 +10190,6 @@ index 0000000..f6b350e
 +
 +  hmips = (struct mips_elf_link_hash_entry *) h;
 +
-+  /* If there are call relocations against an externally-defined symbol,
-+     see whether we can create a MIPS lazy-binding stub for it.  We can
-+     only do this if all references to the function are through call
-+     relocations, and in that case, the traditional lazy-binding stubs
-+     are much more efficient than PLT entries. */
-+  if (h->needs_plt && !hmips->no_fn_stub)
-+    {
-+      if (! elf_hash_table (info)->dynamic_sections_created)
-+      return TRUE;
-+
-+      /* If this symbol is not defined in a regular file, then set
-+       the symbol to the stub location.  This is required to make
-+       function pointers compare as equal between the normal
-+       executable and the shared library.  */
-+      if (!h->def_regular)
-+      {
-+        hmips->needs_lazy_stub = TRUE;
-+        htab->lazy_stub_count++;
-+        return TRUE;
-+      }
-+    }
 +  /* As above, VxWorks requires PLT entries for externally-defined
 +     functions that are only accessed through call relocations.
 +
@@ -11313,9 +10200,7 @@ index 0000000..f6b350e
 +     used in practice due to the short ranges involved.  It can occur
 +     for any relative or absolute relocation in executables; in that
 +     case, the PLT entry becomes the function's canonical address.  */
-+  else if (((h->needs_plt && !hmips->no_fn_stub)
-+          || (h->type == STT_FUNC && hmips->has_static_relocs))
-+         && htab->use_plts_and_copy_relocs
++  if (h->type == STT_FUNC && hmips->has_static_relocs
 +         && !SYMBOL_CALLS_LOCAL (info, h)
 +         && !(ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
 +              && h->root.type == bfd_link_hash_undefweak))
@@ -11330,7 +10215,7 @@ index 0000000..f6b350e
 +           entry is 16 bytes and the PLT0 entry is 32 bytes.
 +           Encourage better cache usage by aligning.  We do this
 +           lazily to avoid pessimizing traditional objects.  */
-+        if (!bfd_set_section_alignment (dynobj, htab->splt, 5))
++        if (!bfd_set_section_alignment (dynobj, htab->splt, 4))
 +          return FALSE;
 +
 +        /* Make sure that .got.plt is word-aligned.  We do this lazily
@@ -11341,8 +10226,8 @@ index 0000000..f6b350e
 +
 +        htab->splt->size += htab->plt_header_size;
 +
-+        /* The first two entries in .got.plt are reserved.  */
-+        htab->sgotplt->size += 2 * MIPS_ELF_GOT_SIZE (dynobj);
++        /* The last and first two entries in .got.plt are reserved.  */
++        htab->sgotplt->size += 3 * MIPS_ELF_GOT_SIZE (dynobj);
 +      }
 +
 +      /* Assign the next .plt entry to this symbol.  */
@@ -11351,7 +10236,7 @@ index 0000000..f6b350e
 +
 +      /* If the output file has no definition of the symbol, set the
 +       symbol's value to the address of the stub.  */
-+      if (!info->shared && !h->def_regular)
++      if (!h->def_regular)
 +      {
 +        h->root.u.def.section = htab->splt;
 +        h->root.u.def.value = h->plt.offset;
@@ -11391,17 +10276,6 @@ index 0000000..f6b350e
 +  if (!hmips->has_static_relocs)
 +    return TRUE;
 +
-+  /* We're now relying on copy relocations.  Complain if we have
-+     some that we can't convert.  */
-+  if (!htab->use_plts_and_copy_relocs || info->shared)
-+    {
-+      (*_bfd_error_handler) (_("non-dynamic relocations refer to "
-+                             "dynamic symbol %s"),
-+                           h->root.root.string);
-+      bfd_set_error (bfd_error_bad_value);
-+      return FALSE;
-+    }
-+
 +  /* We must allocate the symbol in our .dynbss section, which will
 +     become part of the .bss section of the executable.  There will be
 +     an entry for this symbol in the .dynsym section.  The dynamic
@@ -11424,35 +10298,19 @@ index 0000000..f6b350e
 +
 +  return _bfd_elf_adjust_dynamic_copy (h, htab->sdynbss);
 +}
-+\f
++
 +/* This function is called after all the input files have been read,
 +   and the input sections have been assigned to output sections.  We
 +   check for any mips16 stub sections that we can discard.  */
 +
 +bfd_boolean
 +_bfd_riscv_elf_always_size_sections (bfd *output_bfd,
-+                                  struct bfd_link_info *info)
++                                  struct bfd_link_info *info ATTRIBUTE_UNUSED)
 +{
-+  asection *ri;
-+  struct mips_elf_link_hash_table *htab;
-+  struct mips_htab_traverse_info hti;
-+
-+  htab = mips_elf_hash_table (info);
-+  BFD_ASSERT (htab != NULL);
-+
 +  /* The .reginfo section has a fixed size.  */
-+  ri = bfd_get_section_by_name (output_bfd, ".reginfo");
++  asection *ri = bfd_get_section_by_name (output_bfd, ".reginfo");
 +  if (ri != NULL)
 +    bfd_set_section_size (output_bfd, ri, sizeof (Elf32_External_RegInfo));
-+
-+  hti.info = info;
-+  hti.output_bfd = output_bfd;
-+  hti.error = FALSE;
-+  mips_elf_link_hash_traverse (mips_elf_hash_table (info),
-+                             mips_elf_check_symbols, &hti);
-+  if (hti.error)
-+    return FALSE;
-+
 +  return TRUE;
 +}
 +
@@ -11553,80 +10411,6 @@ index 0000000..f6b350e
 +  return TRUE;
 +}
 +
-+/* Estimate the size of the .MIPS.stubs section.  */
-+
-+static void
-+mips_elf_estimate_stub_size (bfd *output_bfd, struct bfd_link_info *info)
-+{
-+  struct mips_elf_link_hash_table *htab;
-+  bfd_size_type dynsymcount;
-+
-+  htab = mips_elf_hash_table (info);
-+  BFD_ASSERT (htab != NULL);
-+
-+  if (htab->lazy_stub_count == 0)
-+    return;
-+
-+  /* IRIX rld assumes that a function stub isn't at the end of the .text
-+     section, so add a dummy entry to the end.  */
-+  htab->lazy_stub_count++;
-+
-+  /* Get a worst-case estimate of the number of dynamic symbols needed.
-+     At this point, dynsymcount does not account for section symbols
-+     and count_section_dynsyms may overestimate the number that will
-+     be needed.  */
-+  dynsymcount = (elf_hash_table (info)->dynsymcount
-+               + count_section_dynsyms (output_bfd, info));
-+
-+  /* Determine the size of one stub entry.  */
-+  htab->function_stub_size = (dynsymcount >= RISCV_IMM_REACH/2
-+                            ? MIPS_FUNCTION_STUB_BIG_SIZE
-+                            : MIPS_FUNCTION_STUB_NORMAL_SIZE);
-+
-+  htab->sstubs->size = htab->lazy_stub_count * htab->function_stub_size;
-+}
-+
-+/* A mips_elf_link_hash_traverse callback for which DATA points to the
-+   MIPS hash table.  If H needs a traditional MIPS lazy-binding stub,
-+   allocate an entry in the stubs section.  */
-+
-+static bfd_boolean
-+mips_elf_allocate_lazy_stub (struct mips_elf_link_hash_entry *h, void **data)
-+{
-+  struct mips_elf_link_hash_table *htab;
-+
-+  htab = (struct mips_elf_link_hash_table *) data;
-+  if (h->needs_lazy_stub)
-+    {
-+      h->root.root.u.def.section = htab->sstubs;
-+      h->root.root.u.def.value = htab->sstubs->size;
-+      h->root.plt.offset = htab->sstubs->size;
-+      htab->sstubs->size += htab->function_stub_size;
-+    }
-+  return TRUE;
-+}
-+
-+/* Allocate offsets in the stubs section to each symbol that needs one.
-+   Set the final size of the .MIPS.stub section.  */
-+
-+static void
-+mips_elf_lay_out_lazy_stubs (struct bfd_link_info *info)
-+{
-+  struct mips_elf_link_hash_table *htab;
-+
-+  htab = mips_elf_hash_table (info);
-+  BFD_ASSERT (htab != NULL);
-+
-+  if (htab->lazy_stub_count == 0)
-+    return;
-+
-+  htab->sstubs->size = 0;
-+  mips_elf_link_hash_traverse (htab, mips_elf_allocate_lazy_stub, htab);
-+  htab->sstubs->size += htab->function_stub_size;
-+  BFD_ASSERT (htab->sstubs->size
-+            == htab->lazy_stub_count * htab->function_stub_size);
-+}
-+
 +/* Set the sizes of the dynamic sections.  */
 +
 +bfd_boolean
@@ -11660,8 +10444,6 @@ index 0000000..f6b350e
 +      {
 +        struct elf_link_hash_entry *h;
 +
-+        BFD_ASSERT (htab->use_plts_and_copy_relocs);
-+
 +        h = _bfd_elf_define_linkage_sym (dynobj, info, htab->splt,
 +                                         "_PROCEDURE_LINKAGE_TABLE_");
 +        htab->root.hplt = h;
@@ -11674,13 +10456,9 @@ index 0000000..f6b350e
 +  /* Allocate space for global sym dynamic relocs.  */
 +  elf_link_hash_traverse (&htab->root, allocate_dynrelocs, (PTR) info);
 +
-+  mips_elf_estimate_stub_size (output_bfd, info);
-+
 +  if (!mips_elf_lay_out_got (output_bfd, info))
 +    return FALSE;
 +
-+  mips_elf_lay_out_lazy_stubs (info);
-+
 +  /* The check_relocs and adjust_dynamic_symbol entry points have
 +     determined the sizes of the various dynamic sections.  Allocate
 +     memory for them.  */
@@ -11713,21 +10491,12 @@ index 0000000..f6b350e
 +            info->combreloc = 0;
 +          }
 +      }
-+      else if (! info->shared
-+             && ! mips_elf_hash_table (info)->use_rld_obj_head
-+             && CONST_STRNEQ (name, ".rld_map"))
-+      {
-+        /* We add a room for __rld_map.  It will be filled in by the
-+           rtld to contain a pointer to the _r_debug structure.  */
-+        s->size += 4;
-+      }
 +      else if (s == htab->splt)
 +      {
 +      }
 +      else if (! CONST_STRNEQ (name, ".init")
 +             && s != htab->sgot
 +             && s != htab->sgotplt
-+             && s != htab->sstubs
 +             && s != htab->sdynbss)
 +      {
 +        /* It's not one of our sections, so don't allocate space.  */
@@ -11759,14 +10528,6 @@ index 0000000..f6b350e
 +       must add the entries now so that we get the correct size for
 +       the .dynamic section.  */
 +
-+      /* SGI object has the equivalence of DT_DEBUG in the
-+       DT_MIPS_RLD_MAP entry.  This must come first because glibc
-+       only fills in DT_MIPS_RLD_MAP (not DT_DEBUG) and GDB only
-+       looks at the first one it sees.  */
-+      if (!info->shared
-+        && !MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_RLD_MAP, 0))
-+      return FALSE;
-+
 +      /* The DT_DEBUG entry may be filled in by the dynamic linker and
 +       used by the debugger.  */
 +      if (info->executable
@@ -12096,66 +10857,6 @@ index 0000000..f6b350e
 +
 +  return TRUE;
 +}
-+\f
-+/* A function that iterates over each entry in la25_stubs and fills
-+   in the code for each one.  DATA points to a mips_htab_traverse_info.  */
-+
-+static int
-+mips_elf_create_la25_stub (void **slot, void *data)
-+{
-+  struct mips_htab_traverse_info *hti;
-+  struct mips_elf_link_hash_table *htab;
-+  struct mips_elf_la25_stub *stub;
-+  asection *s;
-+  bfd_byte *loc;
-+  bfd_vma offset, target;
-+
-+  stub = (struct mips_elf_la25_stub *) *slot;
-+  hti = (struct mips_htab_traverse_info *) data;
-+  htab = mips_elf_hash_table (hti->info);
-+  BFD_ASSERT (htab != NULL);
-+
-+  /* Create the section contents, if we haven't already.  */
-+  s = stub->stub_section;
-+  loc = s->contents;
-+  if (loc == NULL)
-+    {
-+      loc = bfd_malloc (s->size);
-+      if (loc == NULL)
-+      {
-+        hti->error = TRUE;
-+        return FALSE;
-+      }
-+      s->contents = loc;
-+    }
-+
-+  /* Work out where in the section this stub should go.  */
-+  offset = stub->offset;
-+
-+  /* Work out the target address.  */
-+  target = (stub->h->root.root.u.def.section->output_section->vma
-+          + stub->h->root.root.u.def.section->output_offset
-+          + stub->h->root.root.u.def.value);
-+
-+  if (stub->stub_section != htab->strampoline)
-+    {
-+      /* This is a simple RDNPC stub.  Zero out the beginning
-+       of the section and write the instruction at the end. */
-+      memset (loc, 0, offset);
-+      loc += offset;
-+      bfd_put_32 (hti->output_bfd, RISCV_ITYPE (RDNPC, 19, 0, 0), loc);
-+    }
-+  else
-+    {
-+      /* This is trampoline.  */
-+      loc += offset;
-+      bfd_put_32 (hti->output_bfd, RISCV_LTYPE (LUI, 18, RISCV_LUI_HIGH_PART(target)), loc);
-+      bfd_put_32 (hti->output_bfd, RISCV_ITYPE (ADDI, 19, 18, RISCV_CONST_LOW_PART(target)), loc + 4);
-+      bfd_put_32 (hti->output_bfd, RISCV_ITYPE (JALR_J, 0, 18, RISCV_CONST_LOW_PART(target)), loc + 8);
-+      bfd_put_32 (hti->output_bfd, 0, loc + 12);
-+    }
-+  return TRUE;
-+}
 +
 +/* Finish up dynamic symbol handling.  We set the contents of various
 +   dynamic sections here.  */
@@ -12170,7 +10871,6 @@ index 0000000..f6b350e
 +  asection *sgot;
 +  struct mips_got_info *g;
 +  const char *name;
-+  int idx;
 +  struct mips_elf_link_hash_table *htab;
 +  struct mips_elf_link_hash_entry *hmips;
 +
@@ -12179,7 +10879,7 @@ index 0000000..f6b350e
 +  dynobj = elf_hash_table (info)->dynobj;
 +  hmips = (struct mips_elf_link_hash_entry *) h;
 +
-+  if (h->plt.offset != MINUS_ONE && hmips->no_fn_stub)
++  if (h->plt.offset != MINUS_ONE)
 +    {
 +      /* We've decided to create a PLT entry for this symbol.  */
 +      bfd_byte *loc;
@@ -12187,7 +10887,6 @@ index 0000000..f6b350e
 +      bfd_vma plt_entry[RISCV_PLT_ENTRY_INSNS];
 +      int i;
 +
-+      BFD_ASSERT (htab->use_plts_and_copy_relocs);
 +      BFD_ASSERT (h->dynindx != -1);
 +      BFD_ASSERT (htab->splt != NULL);
 +      BFD_ASSERT (h->plt.offset <= htab->splt->size);
@@ -12218,7 +10917,8 @@ index 0000000..f6b350e
 +      loc = htab->splt->contents + h->plt.offset;
 +
 +      /* Fill in the PLT entry itself.  */
-+      riscv_make_plt_entry (output_bfd, got_address, plt_entry);
++      riscv_make_plt_entry (output_bfd, got_address,
++                            header_address + h->plt.offset, plt_entry);
 +      for (i = 0; i < RISCV_PLT_ENTRY_INSNS; i++)
 +        bfd_put_32 (output_bfd, plt_entry[i], loc + 4*i);
 +
@@ -12237,68 +10937,6 @@ index 0000000..f6b350e
 +      else
 +      sym->st_value = 0;
 +    }
-+  else if (h->plt.offset != MINUS_ONE)
-+    {
-+      /* We've decided to create a lazy-binding stub.  */
-+      bfd_byte stub[MIPS_FUNCTION_STUB_BIG_SIZE];
-+
-+      /* This symbol has a stub.  Set it up.  */
-+
-+      BFD_ASSERT (h->dynindx != -1);
-+
-+      BFD_ASSERT ((htab->function_stub_size == MIPS_FUNCTION_STUB_BIG_SIZE)
-+                  || (h->dynindx < RISCV_IMM_REACH/2));
-+
-+      /* Values up to 2^31 - 1 are allowed.  Larger values would cause
-+       sign extension at runtime in the stub, resulting in a negative
-+       index value.  */
-+      if (h->dynindx & ~0x7fffffff)
-+      return FALSE;
-+
-+      /* Fill the stub.  */
-+      /* l[w|d] t7, -GP_OFFSET(gp)
-+         move   t5, ra
-+         lui    t6, %hi(idx)
-+         addi   t6, t6, %lo(idx)
-+         jalr   t7
-+       */
-+      idx = 0;
-+      bfd_put_32 (output_bfd, RISCV_ITYPE (LREG(output_bfd), 19, 28, 0), stub + idx);
-+      idx += 4;
-+      bfd_put_32 (output_bfd, RISCV_ITYPE (ADDI, 17, LINK_REG, 0), stub + idx);
-+      idx += 4;
-+      if (htab->function_stub_size == MIPS_FUNCTION_STUB_BIG_SIZE)
-+        {
-+          bfd_put_32 (output_bfd, RISCV_LTYPE (LUI, 18, RISCV_LUI_HIGH_PART(h->dynindx)),
-+                      stub + idx);
-+          idx += 4;
-+
-+        bfd_put_32 (output_bfd, RISCV_ITYPE (ADDI, 18, 18, RISCV_CONST_LOW_PART(h->dynindx)), stub + idx);
-+          idx += 4;
-+        }
-+      else
-+        {
-+        bfd_put_32 (output_bfd, RISCV_ITYPE (ADDI, 18, 0, RISCV_CONST_LOW_PART(h->dynindx)), stub + idx);
-+          idx += 4;
-+        }
-+      bfd_put_32 (output_bfd, RISCV_ITYPE (JALR_J, LINK_REG, 19, 0), stub + idx);
-+      idx += 4;
-+
-+      BFD_ASSERT (h->plt.offset <= htab->sstubs->size);
-+      memcpy (htab->sstubs->contents + h->plt.offset,
-+            stub, htab->function_stub_size);
-+
-+      /* Mark the symbol as undefined.  plt.offset != -1 occurs
-+       only for the referenced symbol.  */
-+      sym->st_shndx = SHN_UNDEF;
-+
-+      /* The run-time linker uses the st_value field of the symbol
-+       to reset the global offset table entry for this external
-+       to its stub address when unlinking a shared object.  */
-+      sym->st_value = (htab->sstubs->output_section->vma
-+                     + htab->sstubs->output_offset
-+                     + h->plt.offset);
-+    }
 +
 +  BFD_ASSERT (h->dynindx != -1
 +            || h->forced_local);
@@ -12338,7 +10976,6 @@ index 0000000..f6b350e
 +      bfd_vma symval;
 +
 +      BFD_ASSERT (h->dynindx != -1);
-+      BFD_ASSERT (htab->use_plts_and_copy_relocs);
 +
 +      s = mips_elf_rel_dyn_section (info, FALSE);
 +      symval = (h->root.u.def.section->output_section->vma
@@ -12348,35 +10985,6 @@ index 0000000..f6b350e
 +                                        h->dynindx, R_RISCV_COPY, symval);
 +    }
 +
-+  if (! info->shared)
-+    {
-+      if (! mips_elf_hash_table (info)->use_rld_obj_head
-+        && (strcmp (name, "__rld_map") == 0
-+            || strcmp (name, "__RLD_MAP") == 0))
-+      {
-+        asection *s = bfd_get_section_by_name (dynobj, ".rld_map");
-+        BFD_ASSERT (s != NULL);
-+        sym->st_value = s->output_section->vma + s->output_offset;
-+        bfd_put_32 (output_bfd, 0, s->contents);
-+        if (mips_elf_hash_table (info)->rld_value == 0)
-+          mips_elf_hash_table (info)->rld_value = sym->st_value;
-+      }
-+      else if (mips_elf_hash_table (info)->use_rld_obj_head
-+             && strcmp (name, "__rld_obj_head") == 0)
-+      {
-+        BFD_ASSERT (bfd_get_section_by_name (dynobj, ".rld_map") != NULL);
-+        mips_elf_hash_table (info)->rld_value = sym->st_value;
-+      }
-+    }
-+
-+  /* Keep dynamic MIPS16 symbols odd.  This allows the dynamic linker to
-+     treat MIPS16 symbols like any other.  */
-+  if (ELF_ST_IS_MIPS16 (sym->st_other))
-+    {
-+      BFD_ASSERT (sym->st_value & 1);
-+      sym->st_other -= STO_MIPS16;
-+    }
-+
 +  return TRUE;
 +}
 +
@@ -12386,7 +10994,7 @@ index 0000000..f6b350e
 +mips_finish_exec_plt (bfd *output_bfd, struct bfd_link_info *info)
 +{
 +  bfd_byte *loc;
-+  bfd_vma gotplt_value;
++  bfd_vma gotplt_value, plt_address;
 +  bfd_vma plt_entry[RISCV_PLT0_ENTRY_INSNS];
 +  struct mips_elf_link_hash_table *htab;
 +  int i;
@@ -12394,13 +11002,14 @@ index 0000000..f6b350e
 +  htab = mips_elf_hash_table (info);
 +  BFD_ASSERT (htab != NULL);
 +
++  plt_address = htab->splt->output_section->vma + htab->splt->output_offset;
 +  /* Calculate the value of .got.plt.  */
 +  gotplt_value = (htab->sgotplt->output_section->vma
 +                + htab->sgotplt->output_offset);
 +
 +  /* Install the PLT header.  */
 +  loc = htab->splt->contents;
-+  riscv_make_plt0_entry (output_bfd, gotplt_value, plt_entry);
++  riscv_make_plt0_entry (output_bfd, gotplt_value, plt_address, plt_entry);
 +  for (i = 0; i < RISCV_PLT0_ENTRY_INSNS; i++)
 +    bfd_put_32 (output_bfd, plt_entry[i], loc + 4*i);
 +}
@@ -12539,10 +11148,6 @@ index 0000000..f6b350e
 +            dyn.d_un.d_val = g->local_gotno - htab->reserved_gotno;
 +            break;
 +
-+          case DT_MIPS_RLD_MAP:
-+            dyn.d_un.d_ptr = mips_elf_hash_table (info)->rld_value;
-+            break;
-+
 +          case DT_MIPS_OPTIONS:
 +            s = (bfd_get_section_by_name
 +                 (output_bfd, MIPS_ELF_OPTIONS_SECTION_NAME (output_bfd)));
@@ -12550,17 +11155,14 @@ index 0000000..f6b350e
 +            break;
 +
 +          case DT_PLTREL:
-+            BFD_ASSERT (htab->use_plts_and_copy_relocs);
 +            dyn.d_un.d_val = DT_REL;
 +            break;
 +
 +          case DT_PLTRELSZ:
-+            BFD_ASSERT (htab->use_plts_and_copy_relocs);
 +            dyn.d_un.d_val = htab->srelplt->size;
 +            break;
 +
 +          case DT_JMPREL:
-+            BFD_ASSERT (htab->use_plts_and_copy_relocs);
 +            dyn.d_un.d_ptr = (htab->srelplt->output_section->vma
 +                              + htab->srelplt->output_offset);
 +            break;
@@ -12694,10 +11296,7 @@ index 0000000..f6b350e
 +  }
 +
 +  if (htab->splt && htab->splt->size > 0)
-+    {
-+      BFD_ASSERT (!info->shared);
-+      mips_finish_exec_plt (output_bfd, info);
-+    }
++    mips_finish_exec_plt (output_bfd, info);
 +  return TRUE;
 +}
 +
@@ -12991,14 +11590,10 @@ index 0000000..f6b350e
 +  dirmips->possibly_dynamic_relocs += indmips->possibly_dynamic_relocs;
 +  if (indmips->readonly_reloc)
 +    dirmips->readonly_reloc = TRUE;
-+  if (indmips->no_fn_stub)
-+    dirmips->no_fn_stub = TRUE;
 +  if (indmips->global_got_area < dirmips->global_got_area)
 +    dirmips->global_got_area = indmips->global_got_area;
 +  if (indmips->global_got_area < GGA_NONE)
 +    indmips->global_got_area = GGA_NONE;
-+  if (indmips->has_nonpic_branches)
-+    dirmips->has_nonpic_branches = TRUE;
 +
 +  if (dirmips->tls_type == 0)
 +    dirmips->tls_type = indmips->tls_type;
@@ -13432,39 +12027,20 @@ index 0000000..f6b350e
 +  for (i = 0; i < SIZEOF_MIPS_DYNSYM_SECNAMES; i++)
 +    ret->dynsym_sec_strindex[i] = (bfd_size_type) -1;
 +#endif
-+  ret->procedure_count = 0;
-+  ret->use_rld_obj_head = FALSE;
-+  ret->rld_value = 0;
-+  ret->use_plts_and_copy_relocs = FALSE;
 +  ret->srelbss = NULL;
 +  ret->sdynbss = NULL;
 +  ret->srelplt = NULL;
 +  ret->srelplt2 = NULL;
 +  ret->sgotplt = NULL;
 +  ret->splt = NULL;
-+  ret->sstubs = NULL;
 +  ret->sgot = NULL;
 +  ret->got_info = NULL;
 +  ret->plt_header_size = 0;
 +  ret->plt_entry_size = 0;
-+  ret->lazy_stub_count = 0;
-+  ret->function_stub_size = 0;
-+  ret->strampoline = NULL;
-+  ret->la25_stubs = NULL;
-+  ret->add_stub_section = NULL;
 +
 +  return &ret->root.root;
 +}
 +
-+/* A function that the linker calls if we are allowed to use PLTs
-+   and copy relocs.  */
-+
-+void
-+_bfd_riscv_elf_use_plts_and_copy_relocs (struct bfd_link_info *info)
-+{
-+  mips_elf_hash_table (info)->use_plts_and_copy_relocs = TRUE;
-+}
-+\f
 +/* We need to use a special link routine to handle the .reginfo and
 +   the .mdebug sections.  We need to merge all instances of these
 +   sections together, not write them all out sequentially.  */
@@ -13477,7 +12053,6 @@ index 0000000..f6b350e
 +  asection *reginfo_sec, *mdebug_sec;
 +  Elf32_RegInfo reginfo;
 +  struct ecoff_debug_info debug;
-+  struct mips_htab_traverse_info hti;
 +  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
 +  const struct ecoff_debug_swap *swap = bed->elf_backend_ecoff_debug_swap;
 +  HDRR *symhdr = &debug.symbolic_header;
@@ -13490,12 +12065,12 @@ index 0000000..f6b350e
 +  static const char * const secname[] =
 +  {
 +    ".text", ".init", ".fini", ".data",
-+    ".rodata", ".sdata", ".sbss", ".bss"
++    ".rodata", ".bss"
 +  };
 +  static const int sc[] =
 +  {
 +    scText, scInit, scFini, scData,
-+    scRData, scSData, scSBss, scBss
++    scRData, scBss
 +  };
 +
 +  /* Sort the dynamic symbols so that those with GOT entries come after
@@ -13506,14 +12081,6 @@ index 0000000..f6b350e
 +  if (!mips_elf_sort_hash_table (abfd, info))
 +    return FALSE;
 +
-+  /* Create any scheduled LA25 stubs.  */
-+  hti.info = info;
-+  hti.output_bfd = abfd;
-+  hti.error = FALSE;
-+  htab_traverse (htab->la25_stubs, mips_elf_create_la25_stub, &hti);
-+  if (hti.error)
-+    return FALSE;
-+
 +  /* Get a value for the GP register.  */
 +  if (elf_gp (abfd) == 0)
 +    {
@@ -13975,15 +12542,6 @@ index 0000000..f6b350e
 +
 +  ok = TRUE;
 +
-+  if (((new_flags & (EF_MIPS_PIC | EF_MIPS_CPIC)) != 0)
-+      != ((old_flags & (EF_MIPS_PIC | EF_MIPS_CPIC)) != 0))
-+    {
-+      (*_bfd_error_handler)
-+      (_("%B: warning: linking abicalls files with non-abicalls files"),
-+       ibfd);
-+      ok = TRUE;
-+    }
-+
 +  if (new_flags & (EF_MIPS_PIC | EF_MIPS_CPIC))
 +    elf_elfheader (obfd)->e_flags |= EF_MIPS_CPIC;
 +  if (! (new_flags & EF_MIPS_PIC))
@@ -14287,29 +12845,12 @@ index 0000000..f6b350e
 +        + RISCV_PLT0_ENTRY_INSNS * 4
 +        + i * RISCV_PLT_ENTRY_INSNS * 4);
 +}
-+
-+void
-+_bfd_riscv_post_process_headers (bfd *abfd, struct bfd_link_info *link_info)
-+{
-+  struct mips_elf_link_hash_table *htab;
-+  Elf_Internal_Ehdr *i_ehdrp;
-+
-+  i_ehdrp = elf_elfheader (abfd);
-+  if (link_info)
-+    {
-+      htab = mips_elf_hash_table (link_info);
-+      BFD_ASSERT (htab != NULL);
-+
-+      if (htab->use_plts_and_copy_relocs)
-+      i_ehdrp->e_ident[EI_ABIVERSION] = 1;
-+    }
-+}
 diff --git a/binutils-2.21.1/bfd/elfxx-riscv.h b/binutils-2.21.1/bfd/elfxx-riscv.h
 new file mode 100644
-index 0000000..311fa8a
+index 0000000..6531e81
 --- /dev/null
 +++ binutils-2.21.1/bfd/elfxx-riscv.h
-@@ -0,0 +1,150 @@
+@@ -0,0 +1,144 @@
 +/* RISC-V ELF specific backend routines.
 +   Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
 +   Free Software Foundation, Inc.
@@ -14441,13 +12982,8 @@ index 0000000..311fa8a
 +extern char *_bfd_riscv_elf_get_target_dtag (bfd_vma);
 +extern void _bfd_riscv_elf_use_plts_and_copy_relocs
 +  (struct bfd_link_info *);
-+extern bfd_boolean _bfd_riscv_elf_init_stubs
-+  (struct bfd_link_info *,
-+   asection *(*) (const char *, asection *, asection *));
 +extern bfd_vma _bfd_riscv_elf_plt_sym_val
 +  (bfd_vma, const asection *, const arelent *rel);
-+extern void _bfd_riscv_post_process_headers
-+  (bfd *abfd, struct bfd_link_info *link_info);
 +
 +extern const struct bfd_elf_special_section _bfd_riscv_elf_special_sections [];
 +
@@ -14459,7 +12995,6 @@ index 0000000..311fa8a
 +#define elf_backend_special_sections _bfd_riscv_elf_special_sections
 +#define elf_backend_eh_frame_address_size _bfd_riscv_elf_eh_frame_address_size
 +#define elf_backend_merge_symbol_attribute  _bfd_riscv_elf_merge_symbol_attribute
-+#define elf_backend_post_process_headers _bfd_riscv_post_process_headers
 diff --git a/binutils-2.21.1/bfd/targets.c b/binutils-2.21.1/bfd/targets.c
 index 3e99754..a1f375c 100644
 --- a/binutils-2.21.1/bfd/targets.c
@@ -14617,10 +13152,10 @@ index 1aa9bb4..435df2b 100644
  @am__fastdepCC_TRUE@  $(am__mv) $(DEPDIR)/tc-rx.Tpo $(DEPDIR)/tc-rx.Po
 diff --git a/binutils-2.21.1/gas/config/tc-riscv.c b/binutils-2.21.1/gas/config/tc-riscv.c
 new file mode 100644
-index 0000000..26ee5ed
+index 0000000..ddaf7cc
 --- /dev/null
 +++ binutils-2.21.1/gas/config/tc-riscv.c
-@@ -0,0 +1,4138 @@
+@@ -0,0 +1,3858 @@
 +/* tc-mips.c -- assemble code for a MIPS chip.
 +   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
 +   2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation, Inc.
@@ -14739,18 +13274,11 @@ index 0000000..26ee5ed
 +  fixS *fixp[3];
 +};
 +
-+/* The ABI to use.  */
-+enum mips_abi_level
-+{
-+  ABI_32,
-+  ABI_64,
-+};
-+
-+/* MIPS ABI we are using for this output file.  */
-+static enum mips_abi_level mips_abi = ABI_64;
-+
-+/* Whether or not we have code that can call pic code.  */
-+int mips_abicalls = FALSE;
++static bfd_boolean rv64 = TRUE; /* RV64 (true) or RV32 (false) */
++#define HAVE_32BIT_SYMBOLS 1 /* LUI/ADDI for symbols, even in RV64 */
++#define HAVE_32BIT_ADDRESSES (!rv64)
++#define LOAD_ADDRESS_INSN (HAVE_32BIT_ADDRESSES ? "lw" : "ld")
++#define ADD32_INSN (rv64 ? "addiw" : "addi")
 +
 +/* This is the set of options which may be modified by the .set
 +   pseudo-op.  We use a struct so that .set push and .set pop are more
@@ -14771,32 +13299,10 @@ index 0000000..26ee5ed
 +   The object format code reads them and puts them in the appropriate
 +   place.  */
 +unsigned long mips_gprmask;
-+unsigned long mips_fprmask;
-+
-+/* True if the given ABI requires 32-bit registers.  */
-+#define ABI_NEEDS_32BIT_REGS(ABI) ((ABI) == ABI_32)
-+
-+/* Likewise 64-bit registers.  */
-+#define ABI_NEEDS_64BIT_REGS(ABI) ((ABI) == ABI_64)
-+
-+#define HAVE_32BIT_GPRS ABI_NEEDS_32BIT_REGS (mips_abi)
-+
-+#define HAVE_64BIT_GPRS (!HAVE_32BIT_GPRS)
-+
-+#define HAVE_64BIT_OBJECTS ABI_NEEDS_64BIT_REGS (mips_abi)
-+
-+/* The ABI-derived address size.  */
-+#define HAVE_64BIT_ADDRESSES HAVE_64BIT_GPRS
-+#define HAVE_32BIT_ADDRESSES (!HAVE_64BIT_ADDRESSES)
-+
-+/* The size of symbolic constants (i.e., expressions of the form
-+   "SYMBOL" or "SYMBOL + OFFSET").  */
-+#define HAVE_32BIT_SYMBOLS 1
-+#define HAVE_64BIT_SYMBOLS (!HAVE_32BIT_SYMBOLS)
-+
-+/* MIPS PIC level.  */
++unsigned long mips_fprmask;
 +
-+enum mips_pic_level mips_pic;
++/* Whether or not we're generating position-independent code.  */
++static bfd_boolean is_pic = FALSE;
 +
 +/* handle of the OPCODE hash table */
 +static struct hash_control *op_hash = NULL;
@@ -14841,9 +13347,6 @@ index 0000000..26ee5ed
 +   equivalent to seeing no -g option at all.  */
 +static int mips_debug = 0;
 +
-+/* Nop instructions used by emit_nop.  */
-+static struct mips_cl_insn nop_insn;
-+
 +/* For ECOFF and ELF, relocations against symbols are done in two
 +   parts, with a HI relocation and a LO relocation.  Each relocation
 +   has only 16 bits of space to store an addend.  This means that in
@@ -14950,15 +13453,9 @@ index 0000000..26ee5ed
 +static void s_cons (int);
 +static void s_float_cons (int);
 +static void s_mips_globl (int);
-+static void s_option (int);
 +static void s_mipsset (int);
-+static void s_abicalls (int);
 +static void s_dtprelword (int);
 +static void s_dtpreldword (int);
-+static void s_gpword (int);
-+static void s_gpdword (int);
-+static void s_insn (int);
-+static void s_mips_stab (int);
 +static void s_mips_weakext (int);
 +static void s_mips_file (int);
 +static void s_mips_loc (int);
@@ -14985,17 +13482,10 @@ index 0000000..26ee5ed
 +static const pseudo_typeS mips_pseudo_table[] =
 +{
 +  /* MIPS specific pseudo-ops.  */
-+  {"option", s_option, 0},
 +  {"set", s_mipsset, 0},
 +  {"rdata", s_change_sec, 'r'},
-+  {"sdata", s_change_sec, 's'},
-+  {"livereg", s_ignore, 0},
-+  {"abicalls", s_abicalls, 0},
 +  {"dtprelword", s_dtprelword, 0},
 +  {"dtpreldword", s_dtpreldword, 0},
-+  {"gpword", s_gpword, 0},
-+  {"gpdword", s_gpdword, 0},
-+  {"insn", s_insn, 0},
 +
 +  /* Relatively generic pseudo-ops that happen to be used on MIPS
 +     chips.  */
@@ -15025,7 +13515,6 @@ index 0000000..26ee5ed
 +  {"section", s_change_section, 0},
 +  {"short", s_cons, 1},
 +  {"single", s_float_cons, 'f'},
-+  {"stabn", s_mips_stab, 'n'},
 +  {"text", s_change_sec, 't'},
 +  {"word", s_cons, 2},
 +
@@ -15103,7 +13592,7 @@ index 0000000..26ee5ed
 +const char *
 +mips_target_format (void)
 +{
-+  return HAVE_64BIT_OBJECTS ? "elf64-littleriscv" : "elf32-littleriscv";
++  return rv64 ? "elf64-littleriscv" : "elf32-littleriscv";
 +}
 +
 +/* Return the length of instruction INSN.  */
@@ -15577,73 +14066,72 @@ index 0000000..26ee5ed
 +
 +/* Remaining symbolic register names */
 +#define SYMBOLIC_REGISTER_NAMES \
-+    {"zero",  RTYPE_GP | 0},  \
-+    {"ra",    RTYPE_GP | 1},  \
-+    {"v0",    RTYPE_GP | 2},  \
-+    {"v1",    RTYPE_GP | 3},  \
-+    {"a0",    RTYPE_GP | 4},  \
-+    {"a1",    RTYPE_GP | 5},  \
-+    {"a2",    RTYPE_GP | 6},  \
-+    {"a3",    RTYPE_GP | 7},  \
-+    {"a4",    RTYPE_GP | 8},  \
-+    {"a5",    RTYPE_GP | 9},  \
-+    {"a6",    RTYPE_GP | 10},  \
-+    {"a7",    RTYPE_GP | 11}, \
-+    {"t0",    RTYPE_GP | 12}, \
-+    {"t1",    RTYPE_GP | 13}, \
-+    {"t2",    RTYPE_GP | 14}, \
-+    {"t3",    RTYPE_GP | 15}, \
-+    {"t4",    RTYPE_GP | 16}, \
-+    {"t5",    RTYPE_GP | 17}, \
-+    {"t6",    RTYPE_GP | 18}, \
-+    {"t7",    RTYPE_GP | 19}, \
-+    {"s0",    RTYPE_GP | 20}, \
-+    {"s1",    RTYPE_GP | 21}, \
-+    {"s2",    RTYPE_GP | 22}, \
-+    {"s3",    RTYPE_GP | 23}, \
-+    {"s4",    RTYPE_GP | 24}, \
-+    {"s5",    RTYPE_GP | 25}, \
-+    {"s6",    RTYPE_GP | 26}, \
-+    {"s7",    RTYPE_GP | 27}, \
-+    {"s8",    RTYPE_GP | 28}, \
-+    {"gp",    RTYPE_GP | 28}, \
-+    {"s9",    RTYPE_GP | 29}, \
-+    {"sp",    RTYPE_GP | 30}, \
-+    {"tp",    RTYPE_GP | 31}
-+
-+#define FP_SYMBOLIC_REGISTER_NAMES \
-+    {"ft0",   RTYPE_FPU | 0},  \
-+    {"ft1",   RTYPE_FPU | 1},  \
-+    {"fv0",   RTYPE_FPU | 2},  \
-+    {"fv1",   RTYPE_FPU | 3},  \
-+    {"fa0",   RTYPE_FPU | 4},  \
-+    {"fa1",   RTYPE_FPU | 5},  \
-+    {"fa2",   RTYPE_FPU | 6},  \
-+    {"fa3",   RTYPE_FPU | 7},  \
-+    {"fa4",   RTYPE_FPU | 8},  \
-+    {"fa5",   RTYPE_FPU | 9},  \
-+    {"fa6",   RTYPE_FPU | 10},  \
-+    {"fa7",   RTYPE_FPU | 11}, \
-+    {"ft2",   RTYPE_FPU | 12}, \
-+    {"ft3",   RTYPE_FPU | 13}, \
-+    {"ft4",   RTYPE_FPU | 14}, \
-+    {"ft5",   RTYPE_FPU | 15}, \
-+    {"ft6",   RTYPE_FPU | 16}, \
-+    {"ft7",   RTYPE_FPU | 17}, \
-+    {"ft8",   RTYPE_FPU | 18}, \
-+    {"ft9",   RTYPE_FPU | 19}, \
-+    {"fs0",   RTYPE_FPU | 20}, \
-+    {"fs1",   RTYPE_FPU | 21}, \
-+    {"fs2",   RTYPE_FPU | 22}, \
-+    {"fs3",   RTYPE_FPU | 23}, \
-+    {"fs4",   RTYPE_FPU | 24}, \
-+    {"fs5",   RTYPE_FPU | 25}, \
-+    {"fs6",   RTYPE_FPU | 26}, \
-+    {"fs7",   RTYPE_FPU | 27}, \
-+    {"fs8",   RTYPE_FPU | 28}, \
-+    {"fs9",   RTYPE_FPU | 29}, \
-+    {"ft10",  RTYPE_FPU | 30}, \
-+    {"ft11",  RTYPE_FPU | 31}
++  { "zero",    0 | RTYPE_GP }, \
++  { "ra",      1 | RTYPE_GP }, \
++  { "s0",      2 | RTYPE_GP }, \
++  { "s1",      3 | RTYPE_GP }, \
++  { "s2",      4 | RTYPE_GP }, \
++  { "s3",      5 | RTYPE_GP }, \
++  { "s4",      6 | RTYPE_GP }, \
++  { "s5",      7 | RTYPE_GP }, \
++  { "s6",      8 | RTYPE_GP }, \
++  { "s7",      9 | RTYPE_GP }, \
++  { "s8",     10 | RTYPE_GP }, \
++  { "s9",     11 | RTYPE_GP }, \
++  { "s10",    12 | RTYPE_GP }, \
++  { "s11",    13 | RTYPE_GP }, \
++  { "sp",     14 | RTYPE_GP }, \
++  { "tp",     15 | RTYPE_GP }, \
++  { "v0",     16 | RTYPE_GP }, \
++  { "v1",     17 | RTYPE_GP }, \
++  { "a0",     18 | RTYPE_GP }, \
++  { "a1",     19 | RTYPE_GP }, \
++  { "a2",     20 | RTYPE_GP }, \
++  { "a3",     21 | RTYPE_GP }, \
++  { "a4",     22 | RTYPE_GP }, \
++  { "a5",     23 | RTYPE_GP }, \
++  { "a6",     24 | RTYPE_GP }, \
++  { "a7",     25 | RTYPE_GP }, \
++  { "a8",     26 | RTYPE_GP }, \
++  { "a9",     27 | RTYPE_GP }, \
++  { "a10",    28 | RTYPE_GP }, \
++  { "a11",    29 | RTYPE_GP }, \
++  { "a12",    30 | RTYPE_GP }, \
++  { "a13",    31 | RTYPE_GP }
++
++#define FP_SYMBOLIC_REGISTER_NAMES  \
++  { "fs0",     0 | RTYPE_FPU }, \
++  { "fs1",     1 | RTYPE_FPU }, \
++  { "fs2",     2 | RTYPE_FPU }, \
++  { "fs3",     3 | RTYPE_FPU }, \
++  { "fs4",     4 | RTYPE_FPU }, \
++  { "fs5",     5 | RTYPE_FPU }, \
++  { "fs6",     6 | RTYPE_FPU }, \
++  { "fs7",     7 | RTYPE_FPU }, \
++  { "fs8",     8 | RTYPE_FPU }, \
++  { "fs9",     9 | RTYPE_FPU }, \
++  { "fs10",   10 | RTYPE_FPU }, \
++  { "fs11",   11 | RTYPE_FPU }, \
++  { "fs12",   12 | RTYPE_FPU }, \
++  { "fs13",   13 | RTYPE_FPU }, \
++  { "fs14",   14 | RTYPE_FPU }, \
++  { "fs15",   15 | RTYPE_FPU }, \
++  { "fv0",    16 | RTYPE_FPU }, \
++  { "fv1",    17 | RTYPE_FPU }, \
++  { "fa0",    18 | RTYPE_FPU }, \
++  { "fa1",    19 | RTYPE_FPU }, \
++  { "fa2",    20 | RTYPE_FPU }, \
++  { "fa3",    21 | RTYPE_FPU }, \
++  { "fa4",    22 | RTYPE_FPU }, \
++  { "fa5",    23 | RTYPE_FPU }, \
++  { "fa6",    24 | RTYPE_FPU }, \
++  { "fa7",    25 | RTYPE_FPU }, \
++  { "fa8",    26 | RTYPE_FPU }, \
++  { "fa9",    27 | RTYPE_FPU }, \
++  { "fa10",   28 | RTYPE_FPU }, \
++  { "fa11",   29 | RTYPE_FPU }, \
++  { "fa12",   30 | RTYPE_FPU }, \
++  { "fa13",   31 | RTYPE_FPU }
 +
 +#define RISCV_VEC_GR_REGISTER_NAMES \
 +    {"vx0",   RTYPE_VGR_REG | 0}, \
@@ -15718,10 +14206,6 @@ index 0000000..26ee5ed
 +  FP_REGISTER_NAMES,
 +  CR_REGISTER_NUMBERS,
 +
-+  /* The $txx registers depends on the abi,
-+     these will be added later into the symbol table from
-+     one of the tables below once mips_abi is set after 
-+     parsing of arguments from the command line. */
 +  SYMBOLIC_REGISTER_NAMES,
 +  FP_SYMBOLIC_REGISTER_NAMES,
 +
@@ -15777,7 +14261,6 @@ index 0000000..26ee5ed
 +{
 +  const char *retval = NULL;
 +  int i = 0;
-+  int broken = 0;
 +
 +  if (! bfd_set_arch_mach (stdoutput, bfd_arch_riscv, CPU_UNKNOWN))
 +    as_warn (_("Could not set architecture and machine"));
@@ -15801,20 +14284,13 @@ index 0000000..26ee5ed
 +        if (riscv_opcodes[i].pinfo != INSN_MACRO)
 +          {
 +            if (!validate_mips_insn (&riscv_opcodes[i]))
-+              broken = 1;
-+            if (nop_insn.insn_mo == NULL && strcmp (name, "nop") == 0)
-+              {
-+                create_insn (&nop_insn, riscv_opcodes + i);
-+              }
++              as_fatal (_("Broken assembler.  No assembly attempted."));
 +          }
 +        ++i;
 +      }
 +      while ((i < NUMOPCODES) && !strcmp (riscv_opcodes[i].name, name));
 +    }
 +
-+  if (broken)
-+    as_fatal (_("Broken assembler.  No assembly attempted."));
-+
 +  reg_names_hash = hash_new ();
 +  for (i = 0; reg_names[i].name; i++)
 +    {
@@ -15867,7 +14343,7 @@ index 0000000..26ee5ed
 +      if (strncmp (TARGET_OS, "elf", 3) != 0)
 +        flags |= SEC_ALLOC | SEC_LOAD;
 +
-+      if (mips_abi != ABI_64)
++      if (!rv64)
 +        {
 +          sec = subseg_new (".reginfo", (subsegT) 0);
 +
@@ -16100,6 +14576,7 @@ index 0000000..26ee5ed
 +          default:
 +            internalError ();
 +          }
++          *reloc_type = BFD_RELOC_UNUSED;
 +      }
 +      else if (*reloc_type < BFD_RELOC_UNUSED)
 +      {
@@ -16125,7 +14602,7 @@ index 0000000..26ee5ed
 +
 +        /* These relocations can have an addend that won't fit in
 +           4 octets for 64bit assembly.  */
-+        if (HAVE_64BIT_GPRS
++        if (rv64
 +            && ! howto->partial_inplace
 +            && (reloc_type[0] == BFD_RELOC_32
 +                || reloc_type[0] == BFD_RELOC_GPREL16
@@ -16234,19 +14711,6 @@ index 0000000..26ee5ed
 +  gas_assert (mo);
 +  gas_assert (strcmp (name, mo->name) == 0);
 +
-+  while (1)
-+    {
-+      /* Search until we get a match for NAME.  It is assumed here that
-+       macros will never generate MDMX, MIPS-3D, or MT instructions.  */
-+      if (strcmp (fmt, mo->args) == 0
-+        && mo->pinfo != INSN_MACRO)
-+      break;
-+
-+      ++mo;
-+      gas_assert (mo->name);
-+      gas_assert (strcmp (name, mo->name) == 0);
-+    }
-+
 +  create_insn (&insn, mo);
 +  for (;;)
 +    {
@@ -16354,8 +14818,15 @@ index 0000000..26ee5ed
 +        INSERT_OPERAND (RM, insn, va_arg (args, int));
 +        continue;
 +
++      case 'O': /* An off-by-4 PC-relative address for PIC. */
++        INSERT_OPERAND (IMMEDIATE, insn, 4);
++        macro_read_relocs (&args, r);
++        gas_assert (*r == BFD_RELOC_RISCV_TLS_GD_LO16
++                || *r == BFD_RELOC_RISCV_TLS_GOT_LO16
++                || *r == BFD_RELOC_MIPS_GOT_LO16);
++        continue;
++
 +      case 'j':
-+      case 'o':
 +        macro_read_relocs (&args, r);
 +        gas_assert (*r == BFD_RELOC_GPREL16
 +                || *r == BFD_RELOC_MIPS_LITERAL
@@ -16441,6 +14912,8 @@ index 0000000..26ee5ed
 +static void
 +normalize_constant_expr (expressionS *ex)
 +{
++  if (rv64)
++    return;
 +  if (ex->X_op == O_constant
 +      && IS_ZEXT_32BIT_NUM (ex->X_add_number))
 +    ex->X_add_number = (((ex->X_add_number & 0xffffffff) ^ 0x80000000)
@@ -16465,45 +14938,39 @@ index 0000000..26ee5ed
 + * Generate a "lui" instruction.
 + */
 +static void
-+macro_build_lui (expressionS *ep, int regnum)
++macro_build_lui (const char* name, expressionS *ep, int regnum, bfd_reloc_code_real_type reloc)
 +{
-+  expressionS high_expr;
 +  const struct riscv_opcode *mo;
 +  struct mips_cl_insn insn;
-+  bfd_reloc_code_real_type r[3]
-+    = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
-+  const char *name = "lui";
-+  const char *fmt = "d,u";
++  bfd_reloc_code_real_type r[3] = {reloc, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED};
 +
-+  high_expr = *ep;
-+
-+  if (high_expr.X_op == O_constant)
-+    {
-+      /* We can compute the instruction now without a relocation entry.  */
-+      high_expr.X_add_number = ((high_expr.X_add_number + RISCV_IMM_REACH/2)
-+                              >> RISCV_IMM_BITS) & (RISCV_IMM_REACH-1);
-+      *r = BFD_RELOC_UNUSED;
-+    }
-+  else
-+    {
-+      gas_assert (ep->X_op == O_symbol);
-+      *r = BFD_RELOC_HI16_S;
-+    }
++  gas_assert (ep->X_op == O_symbol);
 +
 +  mo = hash_find (op_hash, name);
-+  gas_assert (strcmp (name, mo->name) == 0);
-+  gas_assert (strcmp (fmt, mo->args) == 0);
++  gas_assert (mo);
 +  create_insn (&insn, mo);
 +
 +  insn.insn_opcode = insn.insn_mo->match;
 +  INSERT_OPERAND (RD, insn, regnum);
-+  if (*r == BFD_RELOC_UNUSED)
-+    {
-+      insn.insn_opcode |= high_expr.X_add_number;
-+      append_insn (&insn, NULL, r);
-+    }
-+  else
-+    append_insn (&insn, &high_expr, r);
++  append_insn (&insn, ep, r);
++}
++
++/* Load an entry from the GOT. */
++static void
++load_static_addr (int destreg, expressionS *ep)
++{
++  macro_build_lui ("lui", ep, destreg, BFD_RELOC_HI16_S);
++  macro_build (ep, "addi", "d,s,j", destreg, destreg, BFD_RELOC_LO16);
++}
++
++/* Load an entry from the GOT. */
++static void
++load_got_addr (int destreg, expressionS *ep, const char* lo_insn,
++               bfd_reloc_code_real_type hi_reloc,
++             bfd_reloc_code_real_type lo_reloc)
++{
++  macro_build_lui ("auipc", ep, destreg, hi_reloc);
++  macro_build (ep, lo_insn, "d,O(b)", destreg, lo_reloc, destreg);
 +}
 +
 +/* Warn if an expression is not a constant.  */
@@ -16516,28 +14983,26 @@ index 0000000..26ee5ed
 +  else if (ex->X_op != O_constant)
 +    as_bad (_("Instruction %s requires absolute expression"),
 +          ip->insn_mo->name);
-+
-+  if (HAVE_32BIT_GPRS)
-+    normalize_constant_expr (ex);
++  normalize_constant_expr (ex);
 +}
 +
-+/* load_register generates an unoptimized instruction sequence to load
++/* load_const generates an unoptimized instruction sequence to load
 + * an absolute expression into a register. */
 +static void
-+load_register (int reg, expressionS *ep)
++load_const (int reg, expressionS *ep)
 +{
 +  gas_assert (ep->X_op == O_constant);
 +  gas_assert (reg != ZERO);
 +
 +  // this is an awful way to generate arbitrary 64-bit constants.
 +  // fortunately, this is just used for hand-coded assembly programs.
-+  if(HAVE_64BIT_GPRS && !IS_SEXT_32BIT_NUM(ep->X_add_number))
++  if (rv64 && !IS_SEXT_32BIT_NUM(ep->X_add_number))
 +  {
 +    expressionS upper = *ep, lower = *ep;
 +    upper.X_add_number = (int64_t)ep->X_add_number >> (RISCV_IMM_BITS-1);
-+    load_register(reg, &upper);
++    load_const(reg, &upper);
 +
-+    macro_build (NULL, "sll", "d,s,>", reg, reg, RISCV_IMM_BITS-1);
++    macro_build (NULL, "slli", "d,s,>", reg, reg, RISCV_IMM_BITS-1);
 +
 +    lower.X_add_number = ep->X_add_number & (RISCV_IMM_REACH/2-1);
 +    if (lower.X_add_number != 0)
@@ -16557,10 +15022,7 @@ index 0000000..26ee5ed
 +    }
 +
 +    if((ep->X_add_number & (RISCV_IMM_REACH-1)) || hi_reg == ZERO)
-+    {
-+      macro_build (ep, (HAVE_64BIT_GPRS ? "addiw" : "addi"), "d,s,j",
-+                   reg, hi_reg, BFD_RELOC_LO16);
-+    }
++      macro_build (ep, ADD32_INSN, "d,s,j", reg, hi_reg, BFD_RELOC_LO16);
 +  }
 +}
 +
@@ -16596,46 +15058,33 @@ index 0000000..26ee5ed
 +    {
 +    case M_LA_AB:
 +      /* Load the address of a symbol into a register. */
-+
-+      if(offset_expr.X_op == O_constant
-+         && offset_expr.X_add_number >= -(signed)RISCV_IMM_REACH/2
-+         && offset_expr.X_add_number < (signed)RISCV_IMM_REACH/2)
-+      {
-+        macro_build (&offset_expr, "addi",
-+                     "d,s,j", dreg, breg, BFD_RELOC_LO16);
-+        break;
-+      }
-+
-+      if(!IS_SEXT_32BIT_NUM (offset_expr.X_add_number))
++      if (!IS_SEXT_32BIT_NUM (offset_expr.X_add_number))
 +        as_bad(_("offset too large"));
++      if (breg == dreg && breg != ZERO)
++        as_bad(_("expression too complex: dest and base regs must differ"));
 +
-+      if(breg == dreg && breg != ZERO)
-+        as_bad(_("expression too complex"));
-+
-+      if(offset_expr.X_op == O_constant)
-+      {
-+        load_register(dreg, &offset_expr);
-+        if(breg != ZERO)
-+           macro_build (NULL, "add", "d,s,t", dreg, dreg, breg);
-+
-+        break;
-+      }
-+
-+      /* We're loading a symbol, not an absolute address. */
-+      if(mips_pic != NO_PIC)
-+        as_bad("can't use la with PIC");
-+
-+      if(HAVE_64BIT_SYMBOLS)
-+        as_bad("la is unimplemented for 64-bit symbols");
-+
-+      macro_build_lui (&offset_expr, dreg);
-+      macro_build (&offset_expr, "addi", "d,s,j",
-+                   dreg, dreg, BFD_RELOC_LO16);
++      if (offset_expr.X_op == O_constant)
++        load_const (dreg, &offset_expr);
++      else if (is_pic) /* O_symbol */
++      load_got_addr (dreg, &offset_expr, LOAD_ADDRESS_INSN,
++                     BFD_RELOC_MIPS_GOT_HI16, BFD_RELOC_MIPS_GOT_LO16);
++      else /* non-PIC O_symbol */
++      load_static_addr (dreg, &offset_expr);
 +
 +      if (breg != ZERO)
 +        macro_build (NULL, "add", "d,s,t", dreg, dreg, breg);
 +      break;
 +
++    case M_LA_TLS_GD: 
++      load_got_addr(dreg, &offset_expr, "addi",
++                    BFD_RELOC_RISCV_TLS_GD_HI16, BFD_RELOC_RISCV_TLS_GD_LO16);
++      break;
++
++    case M_LA_TLS_IE: 
++      load_got_addr(dreg, &offset_expr, LOAD_ADDRESS_INSN,
++                    BFD_RELOC_RISCV_TLS_GOT_HI16, BFD_RELOC_RISCV_TLS_GOT_LO16);
++      break;
++
 +    case M_J: /* replace "j $rs" with "ret" if rs=ra, else with "jr $rs" */
 +      if (sreg == LINK_REG)
 +        macro_build (NULL, "ret", "");
@@ -16644,7 +15093,7 @@ index 0000000..26ee5ed
 +      break;
 +
 +    case M_LI:
-+      load_register (dreg, &imm_expr);
++      load_const (dreg, &imm_expr);
 +      break;
 +
 +    default:
@@ -17100,8 +15549,7 @@ index 0000000..26ee5ed
 +            if (imm_expr.X_op != O_big
 +                && imm_expr.X_op != O_constant)
 +              insn_error = _("absolute expression required");
-+            if (HAVE_32BIT_GPRS)
-+              normalize_constant_expr (&imm_expr);
++            normalize_constant_expr (&imm_expr);
 +            s = expr_end;
 +            continue;
 +
@@ -17131,7 +15579,7 @@ index 0000000..26ee5ed
 +                    && imm_expr.X_op == O_constant
 +                    && imm_expr.X_add_number < 0
 +                    && imm_expr.X_unsigned
-+                    && HAVE_64BIT_GPRS)
++                    && rv64)
 +                  break;
 +
 +                /* For compatibility with older assemblers, we accept
@@ -17238,28 +15686,8 @@ index 0000000..26ee5ed
 +{
 +  {"%lo", BFD_RELOC_LO16},
 +#ifdef OBJ_ELF
-+  {"%call_hi", BFD_RELOC_MIPS_CALL_HI16},
-+  {"%call_lo", BFD_RELOC_MIPS_CALL_LO16},
-+  {"%call16", BFD_RELOC_MIPS_CALL16},
-+  {"%got_disp", BFD_RELOC_MIPS_GOT_DISP},
-+  {"%got_hi", BFD_RELOC_MIPS_GOT_HI16},
-+  {"%got_lo", BFD_RELOC_MIPS_GOT_LO16},
-+  {"%got", BFD_RELOC_MIPS_GOT16},
-+  {"%gp_rel", BFD_RELOC_GPREL16},
-+  {"%neg", BFD_RELOC_MIPS_SUB},
-+  {"%tlsgd", BFD_RELOC_MIPS_TLS_GD},
-+  {"%tlsgd_hi", BFD_RELOC_RISCV_TLS_GD_HI16},
-+  {"%tlsgd_lo", BFD_RELOC_RISCV_TLS_GD_LO16},
-+  {"%tlsldm", BFD_RELOC_MIPS_TLS_LDM},
-+  {"%tlsldm_hi", BFD_RELOC_RISCV_TLS_LDM_HI16},
-+  {"%tlsldm_lo", BFD_RELOC_RISCV_TLS_LDM_LO16},
-+  {"%dtprel_hi", BFD_RELOC_MIPS_TLS_DTPREL_HI16},
-+  {"%dtprel_lo", BFD_RELOC_MIPS_TLS_DTPREL_LO16},
 +  {"%tprel_hi", BFD_RELOC_MIPS_TLS_TPREL_HI16},
 +  {"%tprel_lo", BFD_RELOC_MIPS_TLS_TPREL_LO16},
-+  {"%gottprel", BFD_RELOC_MIPS_TLS_GOTTPREL},
-+  {"%gottp_hi", BFD_RELOC_RISCV_TLS_GOT_HI16},
-+  {"%gottp_lo", BFD_RELOC_RISCV_TLS_GOT_LO16},
 +#endif
 +  {"%hi", BFD_RELOC_HI16_S}
 +};
@@ -17393,8 +15821,10 @@ index 0000000..26ee5ed
 +
 +enum options
 +  {
-+    OPTION_MARCH = OPTION_MD_BASE,
-+    OPTION_MABI,
++    OPTION_M32 = OPTION_MD_BASE,
++    OPTION_M64,
++    OPTION_PIC,
++    OPTION_NO_PIC,
 +    OPTION_EB,
 +    OPTION_EL,
 +    OPTION_MRVC,
@@ -17404,10 +15834,11 @@ index 0000000..26ee5ed
 +  
 +struct option md_longopts[] =
 +{
-+  /* Options which specify architecture.  */
-+  {"mabi", required_argument, NULL, OPTION_MABI},
-+
-+  /* Miscellaneous options.  */
++  {"m32", no_argument, NULL, OPTION_M32},
++  {"m64", no_argument, NULL, OPTION_M64},
++  {"fPIC", no_argument, NULL, OPTION_PIC},
++  {"fpic", no_argument, NULL, OPTION_PIC},
++  {"fno-pic", no_argument, NULL, OPTION_NO_PIC},
 +  {"EB", no_argument, NULL, OPTION_EB},
 +  {"EL", no_argument, NULL, OPTION_EL},
 +  {"mrvc", no_argument, NULL, OPTION_MRVC},
@@ -17445,16 +15876,20 @@ index 0000000..26ee5ed
 +      mips_opts.rvc = 0;
 +      break;
 +
-+    case OPTION_MABI:
-+      if (strcmp (arg, "32") == 0)
-+      mips_abi = ABI_32;
-+      else if (strcmp (arg, "64") == 0)
-+        mips_abi = ABI_64;
-+      else
-+      {
-+        as_fatal (_("invalid abi -mabi=%s"), arg);
-+        return 0;
-+      }
++    case OPTION_M32:
++      rv64 = FALSE;
++      break;
++
++    case OPTION_M64:
++      rv64 = TRUE;
++      break;
++
++    case OPTION_NO_PIC:
++      is_pic = FALSE;
++      break;
++
++    case OPTION_PIC:
++      is_pic = TRUE;
 +      break;
 +
 +    default:
@@ -17842,18 +16277,6 @@ index 0000000..26ee5ed
 +      }
 +      demand_empty_rest_of_line ();
 +      break;
-+
-+    case 's':
-+      seg = subseg_new (".sdata", (subsegT) get_absolute_expression ());
-+      if (IS_ELF)
-+      {
-+        bfd_set_section_flags (stdoutput, seg,
-+                               SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA);
-+        if (strncmp (TARGET_OS, "elf", 3) != 0)
-+          record_alignment (seg, 4);
-+      }
-+      demand_empty_rest_of_line ();
-+      break;
 +    }
 +
 +  auto_align = 1;
@@ -18035,37 +16458,6 @@ index 0000000..26ee5ed
 +  demand_empty_rest_of_line ();
 +}
 +
-+static void
-+s_option (int x ATTRIBUTE_UNUSED)
-+{
-+  char *opt;
-+  char c;
-+
-+  opt = input_line_pointer;
-+  c = get_symbol_end ();
-+
-+  if (strncmp (opt, "pic", 3) == 0)
-+    {
-+      int i;
-+
-+      i = atoi (opt + 3);
-+      if (i == 0)
-+      mips_pic = NO_PIC;
-+      else if (i == 2)
-+      {
-+      mips_pic = SVR4_PIC;
-+        mips_abicalls = TRUE;
-+      }
-+      else
-+      as_bad (_(".option pic%d not supported"), i);
-+    }
-+  else
-+    as_warn (_("Unrecognized option \"%s\""), opt);
-+
-+  *input_line_pointer = c;
-+  demand_empty_rest_of_line ();
-+}
-+
 +/* This structure is used to hold a stack of .set values.  */
 +
 +struct mips_option_stack
@@ -18131,18 +16523,6 @@ index 0000000..26ee5ed
 +  demand_empty_rest_of_line ();
 +}
 +
-+/* Handle the .abicalls pseudo-op.  I believe this is equivalent to
-+   .option pic2.  It means to generate SVR4 PIC calls.  */
-+
-+static void
-+s_abicalls (int ignore ATTRIBUTE_UNUSED)
-+{
-+  mips_pic = SVR4_PIC;
-+  mips_abicalls = TRUE;
-+
-+  demand_empty_rest_of_line ();
-+}
-+
 +/* Handle the .dtprelword and .dtpreldword pseudo-ops.  They generate
 +   a 32-bit or 64-bit DTP-relative relocation (BYTES says which) for
 +   use in DWARF debug information.  */
@@ -18189,120 +16569,6 @@ index 0000000..26ee5ed
 +  s_dtprel_internal (8);
 +}
 +
-+/* Handle the .gpword pseudo-op.  This is used when generating PIC
-+   code.  It generates a 32 bit GP relative reloc.  */
-+
-+static void
-+s_gpword (int ignore ATTRIBUTE_UNUSED)
-+{
-+  segment_info_type *si;
-+  struct insn_label_list *l;
-+  symbolS *label;
-+  expressionS ex;
-+  char *p;
-+
-+  /* When not generating PIC code, this is treated as .word.  */
-+  if (mips_pic != SVR4_PIC)
-+    {
-+      s_cons (2);
-+      return;
-+    }
-+
-+  si = seg_info (now_seg);
-+  l = si->label_list;
-+  label = l != NULL ? l->label : NULL;
-+  mips_clear_insn_labels ();
-+  if (auto_align)
-+    mips_align (2, 0, label);
-+  mips_clear_insn_labels ();
-+
-+  expression (&ex);
-+
-+  if (ex.X_op != O_symbol || ex.X_add_number != 0)
-+    {
-+      as_bad (_("Unsupported use of .gpword"));
-+      ignore_rest_of_line ();
-+    }
-+
-+  p = frag_more (4);
-+  md_number_to_chars (p, 0, 4);
-+  fix_new_exp (frag_now, p - frag_now->fr_literal, 4, &ex, FALSE,
-+             BFD_RELOC_GPREL32);
-+
-+  demand_empty_rest_of_line ();
-+}
-+
-+static void
-+s_gpdword (int ignore ATTRIBUTE_UNUSED)
-+{
-+  segment_info_type *si;
-+  struct insn_label_list *l;
-+  symbolS *label;
-+  expressionS ex;
-+  char *p;
-+
-+  /* When not generating PIC code, this is treated as .dword.  */
-+  if (mips_pic != SVR4_PIC)
-+    {
-+      s_cons (3);
-+      return;
-+    }
-+
-+  si = seg_info (now_seg);
-+  l = si->label_list;
-+  label = l != NULL ? l->label : NULL;
-+  mips_clear_insn_labels ();
-+  if (auto_align)
-+    mips_align (3, 0, label);
-+  mips_clear_insn_labels ();
-+
-+  expression (&ex);
-+
-+  if (ex.X_op != O_symbol || ex.X_add_number != 0)
-+    {
-+      as_bad (_("Unsupported use of .gpdword"));
-+      ignore_rest_of_line ();
-+    }
-+
-+  p = frag_more (8);
-+  md_number_to_chars (p, 0, 8);
-+  fix_new_exp (frag_now, p - frag_now->fr_literal, 4, &ex, FALSE,
-+             BFD_RELOC_GPREL32)->fx_tcbit = 1;
-+
-+  /* GPREL32 composed with 64 gives a 64-bit GP offset.  */
-+  fix_new (frag_now, p - frag_now->fr_literal, 8, NULL, 0,
-+         FALSE, BFD_RELOC_64)->fx_tcbit = 1;
-+
-+  demand_empty_rest_of_line ();
-+}
-+
-+/* Handle the .insn pseudo-op.  This marks instruction labels in
-+   mips16 mode.  This permits the linker to handle them specially,
-+   such as generating jalx instructions when needed.  We also make
-+   them odd for the duration of the assembly, in order to generate the
-+   right sort of code.  We will make them even in the adjust_symtab
-+   routine, while leaving them marked.  This is convenient for the
-+   debugger and the disassembler.  The linker knows to make them odd
-+   again.  */
-+
-+static void
-+s_insn (int ignore ATTRIBUTE_UNUSED)
-+{
-+  demand_empty_rest_of_line ();
-+}
-+
-+/* Handle a .stabn directive.  We need these in order to mark a label
-+   as being a mips16 text label correctly.  Sometimes the compiler
-+   will emit a label, followed by a .stabn, and then switch sections.
-+   If the label and .stabn are in mips16 mode, then the label is
-+   really a mips16 text label.  */
-+
-+static void
-+s_mips_stab (int type)
-+{
-+  s_stab (type);
-+}
-+
 +/* Handle the .weakext pseudo-op as defined in Kane and Heinrich.  */
 +
 +static void
@@ -18612,7 +16878,7 @@ index 0000000..26ee5ed
 +mips_elf_final_processing (void)
 +{
 +  /* Write out the register information.  */
-+  if (mips_abi != ABI_64)
++  if (!rv64)
 +    {
 +      Elf32_RegInfo s;
 +
@@ -18646,21 +16912,13 @@ index 0000000..26ee5ed
 +
 +  /* Set the MIPS ELF flag bits.  FIXME: There should probably be some
 +     sort of BFD interface for this.  */
-+  if (mips_pic != NO_PIC)
++  if (is_pic)
 +    {
 +      elf_elfheader (stdoutput)->e_flags |= EF_MIPS_PIC;
 +      elf_elfheader (stdoutput)->e_flags |= EF_MIPS_CPIC;
 +    }
-+  if (mips_abicalls)
-+    elf_elfheader (stdoutput)->e_flags |= EF_MIPS_CPIC;
-+
-+  /* Set the MIPS ELF ABI flags.  */
-+  if (mips_abi == ABI_64)
-+    elf_elfheader (stdoutput)->e_flags |= E_RISCV_ABI_64;
-+  else if (mips_abi == ABI_32)
-+    elf_elfheader (stdoutput)->e_flags |= E_RISCV_ABI_32;
-+  else
-+    gas_assert(0);
++
++  elf_elfheader (stdoutput)->e_flags |= rv64 ? E_RISCV_ABI_64 : E_RISCV_ABI_32;
 +}
 +
 +#endif /* OBJ_ELF || OBJ_MAYBE_ELF */
@@ -18715,30 +16973,27 @@ index 0000000..26ee5ed
 +md_show_usage (FILE *stream)
 +{
 +  fprintf (stream, _("\
-+MIPS options:\n\
-+-EB            generate big endian output\n\
-+-EL            generate little endian output\n\
-+-mabi=ABI      create ABI conformant object file for:\n\
-+                 32, 64\n\
++RISC-V options:\n\
++  -m32           assemble RV32 code\n\
++  -m64           assemble RV64 code (default)\n\
++  -fpic          generate position-independent code\n\
++  -fno-pic       don't generate position-independent code (default)\n\
 +"));
 +}
 +
 +enum dwarf2_format
 +mips_dwarf2_format (asection *sec ATTRIBUTE_UNUSED)
 +{
-+  if (HAVE_64BIT_SYMBOLS)
-+    return dwarf2_format_64bit;
-+  else
++  if (HAVE_32BIT_SYMBOLS)
 +    return dwarf2_format_32bit;
++  else
++    return dwarf2_format_64bit;
 +}
 +
 +int
 +mips_dwarf2_addr_size (void)
 +{
-+  if (HAVE_64BIT_OBJECTS)
-+    return 8;
-+  else
-+    return 4;
++  return rv64 ? 8 : 4;
 +}
 +
 +/* Standard calling conventions leave the CFA at SP on entry.  */
@@ -18761,10 +17016,10 @@ index 0000000..26ee5ed
 +}
 diff --git a/binutils-2.21.1/gas/config/tc-riscv.h b/binutils-2.21.1/gas/config/tc-riscv.h
 new file mode 100644
-index 0000000..f1c56ae
+index 0000000..4703ddc
 --- /dev/null
 +++ binutils-2.21.1/gas/config/tc-riscv.h
-@@ -0,0 +1,159 @@
+@@ -0,0 +1,146 @@
 +/* tc-mips.h -- header file for tc-mips.c.
 +   Copyright 1993, 1994, 1995, 1996, 1997, 2000, 2001, 2002, 2003, 2004,
 +   2005, 2006, 2007  Free Software Foundation, Inc.
@@ -18840,19 +17095,6 @@ index 0000000..f1c56ae
 +#define TARGET_FORMAT mips_target_format()
 +extern const char *mips_target_format (void);
 +
-+/* MIPS PIC level.  */
-+
-+enum mips_pic_level
-+{
-+  /* Do not generate PIC code.  */
-+  NO_PIC,
-+
-+  /* Generate PIC code as in the SVR4 MIPS ABI.  */
-+  SVR4_PIC
-+};
-+
-+extern enum mips_pic_level mips_pic;
-+
 +#define md_after_parse_args() mips_after_parse_args()
 +extern void mips_after_parse_args (void);
 +
@@ -19470,7 +17712,7 @@ index 0000000..3ab671f
 +#endif /* _ELF_RISCV_H */
 diff --git a/binutils-2.21.1/include/opcode/riscv-opc.h b/binutils-2.21.1/include/opcode/riscv-opc.h
 new file mode 100644
-index 0000000..8a94c8e
+index 0000000..19e20b9
 --- /dev/null
 +++ binutils-2.21.1/include/opcode/riscv-opc.h
 @@ -0,0 +1,571 @@
@@ -19497,8 +17739,6 @@ index 0000000..8a94c8e
 +#define  MASK_VVCFG 0xf801ffff
 +#define MATCH_MOVZ 0x2f7
 +#define  MASK_MOVZ 0x1ffff
-+#define MATCH_FCVT_LU_S 0x9053
-+#define  MASK_FCVT_LU_S 0x3ff1ff
 +#define MATCH_C_LD 0x9
 +#define  MASK_C_LD 0x1f
 +#define MATCH_C_SRLI32 0xc19
@@ -19947,14 +18187,16 @@ index 0000000..8a94c8e
 +#define  MASK_VMST 0x1ffff
 +#define MATCH_SETPCR 0xfb
 +#define  MASK_SETPCR 0x3ff
-+#define MATCH_RDNPC 0x26b
-+#define  MASK_RDNPC 0x7ffffff
++#define MATCH_FCVT_LU_S 0x9053
++#define  MASK_FCVT_LU_S 0x3ff1ff
 +#define MATCH_VXCPTHOLD 0x277b
 +#define  MASK_VXCPTHOLD 0xffffffff
 +#define MATCH_FCVT_S_L 0xc053
 +#define  MASK_FCVT_S_L 0x3ff1ff
 +#define MATCH_VFLSEGSTD 0xd8b
 +#define  MASK_VFLSEGSTD 0xfff
++#define MATCH_AUIPC 0x17
++#define  MASK_AUIPC 0x7f
 +#define MATCH_C_ADD 0x1a
 +#define  MASK_C_ADD 0x801f
 +#define MATCH_FCVT_LU_D 0x90d3
@@ -20047,10 +18289,10 @@ index 0000000..8a94c8e
 +#define  MASK_SD 0x3ff
 diff --git a/binutils-2.21.1/include/opcode/riscv.h b/binutils-2.21.1/include/opcode/riscv.h
 new file mode 100644
-index 0000000..2a3d835
+index 0000000..bef6f25
 --- /dev/null
 +++ binutils-2.21.1/include/opcode/riscv.h
-@@ -0,0 +1,253 @@
+@@ -0,0 +1,257 @@
 +/* riscv.h.  RISC-V opcode list for GDB, the GNU debugger.
 +   Copyright 2011
 +   Free Software Foundation, Inc.
@@ -20121,6 +18363,8 @@ index 0000000..2a3d835
 +  ((MATCH_ ## insn) | ((rd) << OP_SH_RD) | (((bigimm) & ((1<<RISCV_BIGIMM_BITS)-1)) << OP_SH_BIGIMMEDIATE))
 +#define RISCV_ITYPE(insn, rd, rs1, imm) \
 +  ((MATCH_ ## insn) | ((rd) << OP_SH_RD) | ((rs1) << OP_SH_RS) | (((imm) & (RISCV_IMM_REACH-1)) << OP_SH_IMMEDIATE))
++#define RISCV_BTYPE(insn, rs1, rs2, imm) \
++  ((MATCH_ ## insn) | ((rs1) << OP_SH_RS) | ((rs2) << OP_SH_RT) | (((imm) & OP_MASK_IMMLO) << OP_SH_IMMLO) | ((((imm) >> RISCV_IMMLO_BITS) & OP_MASK_IMMHI) << OP_SH_IMMHI))
 +#define RISCV_RTYPE(insn, rd, rs1, rs2) \
 +  ((MATCH_ ## insn) | ((rd) << OP_SH_RD) | ((rs1) << OP_SH_RS) | ((rs2) << OP_SH_RT))
 +
@@ -20281,6 +18525,8 @@ index 0000000..2a3d835
 +enum
 +{
 +  M_LA_AB,
++  M_LA_TLS_GD,
++  M_LA_TLS_IE,
 +  M_J,
 +  M_LI,
 +  M_NUM_MACROS
@@ -20567,10 +18813,10 @@ index 0000000..1c23f51
 +'
 diff --git a/binutils-2.21.1/ld/emultempl/riscvelf.em b/binutils-2.21.1/ld/emultempl/riscvelf.em
 new file mode 100644
-index 0000000..c595ff4
+index 0000000..003b4ea
 --- /dev/null
 +++ binutils-2.21.1/ld/emultempl/riscvelf.em
-@@ -0,0 +1,241 @@
+@@ -0,0 +1,49 @@
 +# This shell script emits a C file. -*- C -*-
 +#   Copyright 2004, 2006, 2007, 2008 Free Software Foundation, Inc.
 +#
@@ -20602,10 +18848,6 @@ index 0000000..c595ff4
 +   && elf_tdata (bfd) != NULL                         \
 +   && elf_object_id (bfd) == MIPS_ELF_DATA)
 +
-+/* Fake input file for stubs.  */
-+static lang_input_statement_type *stub_file;
-+static bfd *stub_bfd;
-+
 +static void
 +riscv_after_parse (void)
 +{
@@ -20621,197 +18863,9 @@ index 0000000..c595ff4
 +  after_parse_default ();
 +}
 +
-+struct hook_stub_info
-+{
-+  lang_statement_list_type add;
-+  asection *input_section;
-+};
-+
-+/* Traverse the linker tree to find the spot where the stub goes.  */
-+
-+static bfd_boolean
-+hook_in_stub (struct hook_stub_info *info, lang_statement_union_type **lp)
-+{
-+  lang_statement_union_type *l;
-+  bfd_boolean ret;
-+
-+  for (; (l = *lp) != NULL; lp = &l->header.next)
-+    {
-+      switch (l->header.type)
-+      {
-+      case lang_constructors_statement_enum:
-+        ret = hook_in_stub (info, &constructor_list.head);
-+        if (ret)
-+          return ret;
-+        break;
-+
-+      case lang_output_section_statement_enum:
-+        ret = hook_in_stub (info,
-+                            &l->output_section_statement.children.head);
-+        if (ret)
-+          return ret;
-+        break;
-+
-+      case lang_wild_statement_enum:
-+        ret = hook_in_stub (info, &l->wild_statement.children.head);
-+        if (ret)
-+          return ret;
-+        break;
-+
-+      case lang_group_statement_enum:
-+        ret = hook_in_stub (info, &l->group_statement.children.head);
-+        if (ret)
-+          return ret;
-+        break;
-+
-+      case lang_input_section_enum:
-+        if (info->input_section == NULL
-+            || l->input_section.section == info->input_section)
-+          {
-+            /* We've found our section.  Insert the stub immediately
-+               before its associated input section.  */
-+            *lp = info->add.head;
-+            *(info->add.tail) = l;
-+            return TRUE;
-+          }
-+        break;
-+
-+      case lang_data_statement_enum:
-+      case lang_reloc_statement_enum:
-+      case lang_object_symbols_statement_enum:
-+      case lang_output_statement_enum:
-+      case lang_target_statement_enum:
-+      case lang_input_statement_enum:
-+      case lang_assignment_statement_enum:
-+      case lang_padding_statement_enum:
-+      case lang_address_statement_enum:
-+      case lang_fill_statement_enum:
-+        break;
-+
-+      default:
-+        FAIL ();
-+        break;
-+      }
-+    }
-+  return FALSE;
-+}
-+
-+/* Create a new stub section called STUB_SEC_NAME and arrange for it to
-+   be linked in OUTPUT_SECTION.  The section should go at the beginning of
-+   OUTPUT_SECTION if INPUT_SECTION is null, otherwise it must go immediately
-+   before INPUT_SECTION.  */
-+
-+static asection *
-+riscv_add_stub_section (const char *stub_sec_name, asection *input_section,
-+                     asection *output_section)
-+{
-+  asection *stub_sec;
-+  flagword flags;
-+  const char *secname;
-+  lang_output_section_statement_type *os;
-+  struct hook_stub_info info;
-+
-+  /* Create the stub file, if we haven't already.  */
-+  if (stub_file == NULL)
-+    {
-+      stub_file = lang_add_input_file ("linker stubs",
-+                                     lang_input_file_is_fake_enum,
-+                                     NULL);
-+      stub_bfd = bfd_create ("linker stubs", link_info.output_bfd);
-+      if (stub_bfd == NULL
-+        || !bfd_set_arch_mach (stub_bfd,
-+                               bfd_get_arch (link_info.output_bfd),
-+                               bfd_get_mach (link_info.output_bfd)))
-+      {
-+        einfo ("%F%P: can not create BFD %E\n");
-+        return NULL;
-+      }
-+      stub_bfd->flags |= BFD_LINKER_CREATED;
-+      stub_file->the_bfd = stub_bfd;
-+      ldlang_add_file (stub_file);
-+    }
-+
-+  /* Create the section.  */
-+  stub_sec = bfd_make_section_anyway (stub_bfd, stub_sec_name);
-+  if (stub_sec == NULL)
-+    goto err_ret;
-+
-+  /* Set the flags.  */
-+  flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE
-+         | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_KEEP);
-+  if (!bfd_set_section_flags (stub_bfd, stub_sec, flags))
-+    goto err_ret;
-+
-+  /* Create an output section statement.  */
-+  secname = bfd_get_section_name (output_section->owner, output_section);
-+  os = lang_output_section_find (secname);
-+
-+  /* Initialize a statement list that contains only the new statement.  */
-+  lang_list_init (&info.add);
-+  lang_add_section (&info.add, stub_sec, os);
-+  if (info.add.head == NULL)
-+    goto err_ret;
-+
-+  /* Insert the new statement in the appropriate place.  */
-+  info.input_section = input_section;
-+  if (hook_in_stub (&info, &os->children.head))
-+    return stub_sec;
-+
-+ err_ret:
-+  einfo ("%X%P: can not make stub section: %E\n");
-+  return NULL;
-+}
-+
-+/* This is called before the input files are opened.  */
-+
-+static void
-+riscv_create_output_section_statements (void)
-+{
-+  if (is_riscv_elf (link_info.output_bfd))
-+    _bfd_riscv_elf_init_stubs (&link_info, riscv_add_stub_section);
-+}
-+
-+/* This is called after we have merged the private data of the input bfds.  */
-+
-+static void
-+riscv_before_allocation (void)
-+{
-+  flagword flags;
-+  
-+  flags = elf_elfheader (link_info.output_bfd)->e_flags;
-+  if (!link_info.shared
-+      && !link_info.nocopyreloc
-+      && (flags & (EF_MIPS_PIC | EF_MIPS_CPIC)) == EF_MIPS_CPIC)
-+    _bfd_riscv_elf_use_plts_and_copy_relocs (&link_info);
-+
-+  gld${EMULATION_NAME}_before_allocation ();
-+}
-+
-+/* Avoid processing the fake stub_file in vercheck, stat_needed and
-+   check_needed routines.  */
-+
-+static void (*real_func) (lang_input_statement_type *);
-+
-+static void riscv_for_each_input_file_wrapper (lang_input_statement_type *l)
-+{
-+  if (l != stub_file)
-+    (*real_func) (l);
-+}
-+
-+static void
-+riscv_lang_for_each_input_file (void (*func) (lang_input_statement_type *))
-+{
-+  real_func = func;
-+  lang_for_each_input_file (&riscv_for_each_input_file_wrapper);
-+}
-+
-+#define lang_for_each_input_file riscv_lang_for_each_input_file
-+
 +EOF
 +
 +LDEMUL_AFTER_PARSE=riscv_after_parse
-+LDEMUL_BEFORE_ALLOCATION=riscv_before_allocation
-+LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS=riscv_create_output_section_statements
 diff --git a/binutils-2.21.1/opcodes/configure b/binutils-2.21.1/opcodes/configure
 index fe7c01e..b4e9869 100755
 --- a/binutils-2.21.1/opcodes/configure
@@ -20857,10 +18911,10 @@ index 0fb35ac..cef365e 100644
        if (bfd_get_mach (abfd) == bfd_mach_ppc_620)
 diff --git a/binutils-2.21.1/opcodes/riscv-dis.c b/binutils-2.21.1/opcodes/riscv-dis.c
 new file mode 100644
-index 0000000..f890f07
+index 0000000..cc9dd85
 --- /dev/null
 +++ binutils-2.21.1/opcodes/riscv-dis.c
-@@ -0,0 +1,903 @@
+@@ -0,0 +1,902 @@
 +/* Print mips instructions for GDB, the GNU debugger, or for objdump.
 +   Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
 +   2000, 2001, 2002, 2003, 2005, 2007, 2008
@@ -20917,14 +18971,14 @@ index 0000000..f890f07
 +  "x24",  "x25",  "x26",  "x27",  "x28",  "x29",  "x30",  "x31"
 +};
 +
-+static const char * const mips_gpr_names_abi[32] =
-+{
-+  "zero", "ra",   "v0",   "v1",   "a0",   "a1",   "a2",   "a3",
-+  "a4",   "a5",   "a6",   "a7",   "t0",   "t1",   "t2",   "t3",
-+  "t4",   "t5",   "t6",   "t7",   "s0",   "s1",   "s2",   "s3",
-+  "s4",   "s5",   "s6",   "s7",   "s8",   "s9",   "sp",   "tp"
++static const char* mips_gpr_names_abi[32] = {
++  "zero", "ra", "s0", "s1",  "s2",  "s3",  "s4",  "s5",
++  "s6",   "s7", "s8", "s9", "s10", "s11",  "sp",  "tp",
++  "v0",   "v1", "a0", "a1",  "a2",  "a3",  "a4",  "a5",
++  "a6",   "a7", "a8", "a9", "a10", "a11", "a12", "a13"
 +};
 +
++
 +static const char * const mips_fpr_names_numeric[32] =
 +{
 +  "f0",   "f1",   "f2",   "f3",   "f4",   "f5",   "f6",   "f7",
@@ -20933,12 +18987,11 @@ index 0000000..f890f07
 +  "f24",  "f25",  "f26",  "f27",  "f28",  "f29",  "f30",  "f31"
 +};
 +
-+static const char * const mips_fpr_names_abi[32] =
-+{
-+  "ft0",  "ft1",  "fv0",  "fv1",  "fa0",  "fa1",  "fa2",  "fa3",
-+  "fa4",  "fa5",  "fa6",  "fa7",  "ft2",  "ft3",  "ft4",  "ft5",
-+  "ft6",  "ft7",  "ft8",  "ft9",  "fs0",  "fs1",  "fs2",  "fs3",
-+  "fs4",  "fs5",  "fs6",  "fs7",  "fs8",  "fs9",  "ft10", "ft11"
++static const char* mips_fpr_names_abi[32] = {
++  "fs0", "fs1",  "fs2",  "fs3",  "fs4",  "fs5",  "fs6",  "fs7",
++  "fs8", "fs9", "fs10", "fs11", "fs12", "fs13", "fs14", "fs15",
++  "fv0", "fv1", "fa0",   "fa1",  "fa2",  "fa3",  "fa4",  "fa5",
++  "fa6", "fa7", "fa8",   "fa9", "fa10", "fa11", "fa12", "fa13"
 +};
 +
 +static const char * const mips_cp0_names_numeric[32] =
@@ -21766,10 +19819,10 @@ index 0000000..f890f07
 +}
 diff --git a/binutils-2.21.1/opcodes/riscv-opc.c b/binutils-2.21.1/opcodes/riscv-opc.c
 new file mode 100644
-index 0000000..3d4410a
+index 0000000..0a28605
 --- /dev/null
 +++ binutils-2.21.1/opcodes/riscv-opc.c
-@@ -0,0 +1,466 @@
+@@ -0,0 +1,470 @@
 +/* mips-opc.c -- MIPS opcode list.
 +   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
 +   2003, 2004, 2005, 2007, 2008, 2009  Free Software Foundation, Inc.
@@ -21828,6 +19881,7 @@ index 0000000..3d4410a
 +#define MASK_RT (OP_MASK_RT << OP_SH_RT)
 +#define MASK_RD (OP_MASK_RD << OP_SH_RD)
 +#define MASK_IMM (OP_MASK_IMMEDIATE << OP_SH_IMMEDIATE)
++#define MASK_BIGIMM (OP_MASK_BIGIMMEDIATE << OP_SH_BIGIMMEDIATE)
 +#define MASK_RM (OP_MASK_RM << OP_SH_RM)
 +
 +const struct riscv_opcode riscv_builtin_opcodes[] =
@@ -21957,6 +20011,8 @@ index 0000000..3d4410a
 +{"divu",    "d,s,t",  MATCH_DIVU, MASK_DIVU,  WR_xd|RD_xs1|RD_xs2 },
 +{"divuw",    "d,s,t", MATCH_DIVUW, MASK_DIVUW,  WR_xd|RD_xs1|RD_xs2 },
 +{"la",     "d,A(b)",  0,    (int) M_LA_AB,    INSN_MACRO },
++{"la.tls.gd", "d,A",  0,    (int) M_LA_TLS_GD,        INSN_MACRO },
++{"la.tls.ie", "d,A",  0,    (int) M_LA_TLS_IE,        INSN_MACRO },
 +{"mffsr",   "d",      MATCH_MFFSR, MASK_MFFSR,  WR_xd },
 +{"mtfsr",   "s",      MATCH_MTFSR, MASK_MTFSR | MASK_RD,  RD_xs1 },
 +{"mtfsr",   "d,s",    MATCH_MTFSR, MASK_MTFSR,  WR_xd|RD_xs1 },
@@ -22033,7 +20089,8 @@ index 0000000..3d4410a
 +{"or",     "d,s,j",   MATCH_ORI, MASK_ORI,     WR_xd|RD_xs1 },
 +{"ori",     "d,s,j",  MATCH_ORI, MASK_ORI,     WR_xd|RD_xs1 },
 +  /* pref and prefx are at the start of the table.  */
-+{"rdnpc",   "d",      MATCH_RDNPC, MASK_RDNPC,  WR_xd },
++{"auipc",   "d,u",    MATCH_AUIPC, MASK_AUIPC,  WR_xd },
++{"rdpc",   "d",               MATCH_AUIPC, MASK_AUIPC | MASK_BIGIMM,  WR_xd },
 +{"rem",    "d,s,t",   MATCH_REM, MASK_REM,  WR_xd|RD_xs1|RD_xs2 },
 +{"remw",    "d,s,t",  MATCH_REMW, MASK_REMW,  WR_xd|RD_xs1|RD_xs2 },
 +{"remu",    "d,s,t",  MATCH_REMU, MASK_REMU,  WR_xd|RD_xs1|RD_xs2 },
index aa24d37..67fb715 100644 (file)
@@ -69,10 +69,10 @@ index ada68dd..321d4f2 100644
  
 diff --git a/gcc-4.6.1/gcc/config/riscv/constraints.md b/gcc-4.6.1/gcc/config/riscv/constraints.md
 new file mode 100644
-index 0000000..d994f47
+index 0000000..f09a4bd
 --- /dev/null
 +++ gcc-4.6.1/gcc/config/riscv/constraints.md
-@@ -0,0 +1,137 @@
+@@ -0,0 +1,121 @@
 +;; Constraint definitions for MIPS.
 +;; Copyright (C) 2006, 2007, 2008, 2010 Free Software Foundation, Inc.
 +;;
@@ -115,28 +115,12 @@ index 0000000..d994f47
 +(define_register_constraint "b" "ALL_REGS"
 +  "@internal")
 +
-+;; MIPS16 code always calls through a MIPS16 register; see mips_emit_call_insn
-+;; for details.
-+(define_register_constraint "c" "TARGET_ABICALLS ? PIC_FN_ADDR_REG : GR_REGS"
-+  "A register suitable for use in an indirect jump.  This will always be
-+   @code{$25} for @option{-mabicalls}.")
-+
-+(define_register_constraint "j" "PIC_FN_ADDR_REG"
++(define_register_constraint "j" "V1_REG"
 +  "@internal")
 +
-+;; Don't use this constraint in gcc code!  It runs the risk of
-+;; introducing a spill failure; see tls_get_tp_<mode>.
-+(define_register_constraint "v" "V1_REG"
-+  "Register @code{$3}.  Do not use this constraint in new code;
-+   it is retained only for compatibility with glibc.")
-+
 +(define_register_constraint "z" "GR_REGS"
 +  "A floating-point condition code register.")
 +
-+(define_constraint "kf"
-+  "@internal"
-+  (match_operand 0 "force_to_mem_operand"))
-+
 +;; This is a normal rather than a register constraint because we can
 +;; never use the stack pointer as a reload register.
 +(define_constraint "ks"
@@ -212,10 +196,10 @@ index 0000000..d994f47
 +       (match_test "op == CONST0_RTX (mode)")))
 diff --git a/gcc-4.6.1/gcc/config/riscv/crti.asm b/gcc-4.6.1/gcc/config/riscv/crti.asm
 new file mode 100644
-index 0000000..700232d
+index 0000000..ce9b393
 --- /dev/null
 +++ gcc-4.6.1/gcc/config/riscv/crti.asm
-@@ -0,0 +1,49 @@
+@@ -0,0 +1,42 @@
 +/* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
 +
 +This file is part of GCC.
@@ -239,38 +223,31 @@ index 0000000..700232d
 +see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 +<http://www.gnu.org/licenses/>.  */
 +
-+/* 4 slots for argument spill area.  1 for cpreturn, 1 for stack.
-+   Return spill offset of 40 and 20.  Aligned to 16 bytes for n32.  */
++#ifdef __riscv64
++# define SR sd
++#else
++# define SR sw
++#endif
 +
 +      .section .init,"ax",@progbits
 +      .globl  _init
 +      .type   _init,@function
 +_init:
-+#ifdef __riscv64
-+      add     sp, sp, -48
-+      sd      ra, 40(sp)
-+#else
-+      add     sp, sp, -32
-+      sw      ra, 20(sp)
-+#endif
++      add     sp, sp, -8
++      SR      ra, 0(sp)
 +
 +      .section .fini,"ax",@progbits
 +      .globl  _fini
 +      .type   _fini,@function
 +_fini:
-+#ifdef __riscv64
-+      add     sp, sp, -48
-+      sd      ra, 40(sp)
-+#else
-+      add     sp, sp, -32
-+      sw      ra, 20(sp)
-+#endif
++      add     sp, sp, -8
++      SR      ra, 0(sp)
 diff --git a/gcc-4.6.1/gcc/config/riscv/crtn.asm b/gcc-4.6.1/gcc/config/riscv/crtn.asm
 new file mode 100644
-index 0000000..3d72ef8
+index 0000000..2b82d24
 --- /dev/null
 +++ gcc-4.6.1/gcc/config/riscv/crtn.asm
-@@ -0,0 +1,46 @@
+@@ -0,0 +1,38 @@
 +/* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
 +
 +This file is part of GCC.
@@ -294,29 +271,21 @@ index 0000000..3d72ef8
 +see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 +<http://www.gnu.org/licenses/>.  */
 +
-+/* 4 slots for argument spill area.  1 for cpreturn, 1 for stack.
-+   Return spill offset of 40 and 20.  Aligned to 16 bytes for n32.  */
-+
-+      .section .init,"ax",@progbits
 +#ifdef __riscv64
-+      ld      ra, 40(sp)
-+      add     sp, sp, 48
++# define LR ld
 +#else
-+      lw      ra, 20(sp)
-+      add     sp, sp, 32
++# define LR lw
 +#endif
++
++      .section .init,"ax",@progbits
++      LR      ra, 0(sp)
++      addi    sp, sp, 8
 +      ret
 +
 +      .section .fini,"ax",@progbits
-+#ifdef        __riscv64
-+      ld      ra, 40(sp)
-+      add     sp, sp, 48
-+#else
-+      lw      ra, 20(sp)
-+      add     sp, sp, 32
-+#endif
++      LR      ra, 0(sp)
++      addi    sp, sp, 8
 +      ret
-+
 diff --git a/gcc-4.6.1/gcc/config/riscv/elf.h b/gcc-4.6.1/gcc/config/riscv/elf.h
 new file mode 100644
 index 0000000..5725537
@@ -613,10 +582,10 @@ index 0000000..02f7cd5
 +#endif
 diff --git a/gcc-4.6.1/gcc/config/riscv/linux.h b/gcc-4.6.1/gcc/config/riscv/linux.h
 new file mode 100644
-index 0000000..cbae60e
+index 0000000..25fb105
 --- /dev/null
 +++ gcc-4.6.1/gcc/config/riscv/linux.h
-@@ -0,0 +1,124 @@
+@@ -0,0 +1,115 @@
 +/* Definitions for MIPS running Linux-based GNU systems with ELF format.
 +   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
 +   2007, 2008, 2010, 2011 Free Software Foundation, Inc.
@@ -717,20 +686,11 @@ index 0000000..cbae60e
 +
 +#define MD_UNWIND_SUPPORT "config/riscv/linux-unwind.h"
 +
-+#ifdef HAVE_AS_NO_SHARED
-+/* Default to -mno-shared for non-PIC.  */
-+# define NO_SHARED_SPECS \
-+  "%{mshared|mno-shared|fpic|fPIC|fpie|fPIE:;:-mno-shared}"
-+#else
-+# define NO_SHARED_SPECS ""
-+#endif
-+
 +/* -march=native handling only makes sense with compiler running on
 +   a RISC-V machine.  */
 +#define MARCH_MTUNE_NATIVE_SPECS ""
 +
 +#define LINUX_DRIVER_SELF_SPECS \
-+  NO_SHARED_SPECS             \
 +  MARCH_MTUNE_NATIVE_SPECS
 +
 +#undef DRIVER_SELF_SPECS
@@ -743,7 +703,7 @@ index 0000000..cbae60e
 +   "%{shared|pie:crtendS.o%s;:crtend.o%s} crtn.o%s"
 diff --git a/gcc-4.6.1/gcc/config/riscv/linux64.h b/gcc-4.6.1/gcc/config/riscv/linux64.h
 new file mode 100644
-index 0000000..7262396
+index 0000000..c742cf1
 --- /dev/null
 +++ gcc-4.6.1/gcc/config/riscv/linux64.h
 @@ -0,0 +1,58 @@
@@ -774,7 +734,7 @@ index 0000000..7262396
 +#define DRIVER_SELF_SPECS \
 +  LINUX_DRIVER_SELF_SPECS \
 +  " %{!EB:%{!EL:%(endian_spec)}}" \
-+  " %{!mabi=*: -mabi=64}"
++  " %{" OPT_ARCH32 ": -m32} %{" OPT_ARCH64 ": -m64}" \
 +
 +#undef LIB_SPEC
 +#define LIB_SPEC "\
@@ -794,11 +754,11 @@ index 0000000..7262396
 +  %{!shared: \
 +    %{!static: \
 +      %{rdynamic:-export-dynamic} \
-+      %{mabi=64: -dynamic-linker " LINUX_DYNAMIC_LINKER64 "} \
-+      %{mabi=32: -dynamic-linker " LINUX_DYNAMIC_LINKER32 "}} \
++      %{" OPT_ARCH64 ": -dynamic-linker " LINUX_DYNAMIC_LINKER64 "} \
++      %{" OPT_ARCH32 ": -dynamic-linker " LINUX_DYNAMIC_LINKER32 "}} \
 +    %{static:-static}} \
-+%{mabi=64:-melf64%{EB:b}%{EL:l}riscv} \
-+%{mabi=32:-melf32%{EB:b}%{EL:l}riscv}"
++%{" OPT_ARCH64 ":-melf64%{EB:b}%{EL:l}riscv} \
++%{" OPT_ARCH32 ":-melf32%{EB:b}%{EL:l}riscv}"
 +
 +/* GNU/Linux doesn't use the same floating-point format that IRIX uses
 +   for long double.  There's no need to override this here, since
@@ -1066,10 +1026,10 @@ index 0000000..2a3d835
 +#endif /* _MIPS_H_ */
 diff --git a/gcc-4.6.1/gcc/config/riscv/predicates.md b/gcc-4.6.1/gcc/config/riscv/predicates.md
 new file mode 100644
-index 0000000..29d9208
+index 0000000..14ee358
 --- /dev/null
 +++ gcc-4.6.1/gcc/config/riscv/predicates.md
-@@ -0,0 +1,209 @@
+@@ -0,0 +1,191 @@
 +;; Predicate definitions for MIPS.
 +;; Copyright (C) 2004, 2007, 2008 Free Software Foundation, Inc.
 +;;
@@ -1140,16 +1100,14 @@ index 0000000..29d9208
 +
 +  if (symbol_type == SYMBOL_ABSOLUTE)
 +    {
-+      /* We can only use direct calls if we're sure that the target
-+       function does not need t7 to be valid on entry.  If we're
-+       non-PIC, t7 can be set up using the PLT. */
-+      if (TARGET_ABICALLS && flag_pic)
-+      return false;
-+
-+      /* If -mlong-calls or if this function has an explicit long_call
-+       attribute, we must use register addressing.  The
-+       SYMBOL_FLAG_LONG_CALL bit is set by mips_encode_section_info.  */
-+      return !(GET_CODE (op) == SYMBOL_REF && SYMBOL_REF_LONG_CALL_P (op));
++      if (GET_CODE (op) == SYMBOL_REF)
++      {
++        if (flag_pic && !riscv_symbol_binds_local_p (op))
++          return false;
++        if (SYMBOL_REF_LONG_CALL_P (op))
++          return false;
++      }
++      return true;
 +    }
 +
 +  return false;
@@ -1249,22 +1207,6 @@ index 0000000..29d9208
 +        && type == SYMBOL_ABSOLUTE);
 +})
 +
-+(define_predicate "force_to_mem_operand"
-+  (match_code "const,symbol_ref,label_ref")
-+{
-+  enum mips_symbol_type symbol_type;
-+  return (mips_symbolic_constant_p (op, &symbol_type)
-+        && symbol_type == SYMBOL_FORCE_TO_MEM);
-+})
-+
-+(define_predicate "got_disp_operand"
-+  (match_code "const,symbol_ref,label_ref")
-+{
-+  enum mips_symbol_type type;
-+  return (mips_symbolic_constant_p (op, &type)
-+        && type == SYMBOL_GOT_DISP);
-+})
-+
 +(define_predicate "symbol_ref_operand"
 +  (match_code "symbol_ref"))
 +
@@ -1551,10 +1493,10 @@ index 0000000..7848f7c
 +
 diff --git a/gcc-4.6.1/gcc/config/riscv/riscv-opc.h b/gcc-4.6.1/gcc/config/riscv/riscv-opc.h
 new file mode 100644
-index 0000000..e417397
+index 0000000..19e20b9
 --- /dev/null
 +++ gcc-4.6.1/gcc/config/riscv/riscv-opc.h
-@@ -0,0 +1,545 @@
+@@ -0,0 +1,571 @@
 +/* Automatically generated by parse-opcodes */
 +#define MATCH_MOVN 0x6f7
 +#define  MASK_MOVN 0x1ffff
@@ -1564,6 +1506,8 @@ index 0000000..e417397
 +#define  MASK_REMUW 0x1ffff
 +#define MATCH_FMIN_D 0x180d3
 +#define  MASK_FMIN_D 0x1ffff
++#define MATCH_LR_W 0x1012b
++#define  MASK_LR_W 0x3fffff
 +#define MATCH_VLSTHU 0x128b
 +#define  MASK_VLSTHU 0x1ffff
 +#define MATCH_C_SWSP 0x8
@@ -1572,12 +1516,14 @@ index 0000000..e417397
 +#define  MASK_BLTU 0x3ff
 +#define MATCH_VLSEGSTWU 0xb0b
 +#define  MASK_VLSEGSTWU 0xfff
++#define MATCH_VVCFG 0x473
++#define  MASK_VVCFG 0xf801ffff
 +#define MATCH_MOVZ 0x2f7
 +#define  MASK_MOVZ 0x1ffff
-+#define MATCH_FCVT_LU_S 0x9053
-+#define  MASK_FCVT_LU_S 0x3ff1ff
-+#define MATCH_FENCE_L_CV 0x32f
-+#define  MASK_FENCE_L_CV 0x3ff
++#define MATCH_C_LD 0x9
++#define  MASK_C_LD 0x1f
++#define MATCH_C_SRLI32 0xc19
++#define  MASK_C_SRLI32 0x1c1f
 +#define MATCH_FMIN_S 0x18053
 +#define  MASK_FMIN_S 0x1ffff
 +#define MATCH_C_LW0 0x12
@@ -1588,6 +1534,8 @@ index 0000000..e417397
 +#define  MASK_LB 0x3ff
 +#define MATCH_VLWU 0x30b
 +#define  MASK_VLWU 0x3fffff
++#define MATCH_FCVT_S_WU 0xf053
++#define  MASK_FCVT_S_WU 0x3ff1ff
 +#define MATCH_FCVT_D_L 0xc0d3
 +#define  MASK_FCVT_D_L 0x3ff1ff
 +#define MATCH_LH 0x83
@@ -1600,10 +1548,8 @@ index 0000000..e417397
 +#define  MASK_ADD 0x1ffff
 +#define MATCH_FCVT_D_S 0x100d3
 +#define  MASK_FCVT_D_S 0x3ff1ff
-+#define MATCH_FENCE_G_V 0x2af
-+#define  MASK_FENCE_G_V 0x3ff
 +#define MATCH_MFPCR 0x17b
-+#define  MASK_MFPCR 0x7c1ffff
++#define  MASK_MFPCR 0x3fffff
 +#define MATCH_C_FSD 0x18
 +#define  MASK_C_FSD 0x1f
 +#define MATCH_FMAX_D 0x190d3
@@ -1622,12 +1568,12 @@ index 0000000..e417397
 +#define  MASK_VFLSTD 0x1ffff
 +#define MATCH_C_LI 0x0
 +#define  MASK_C_LI 0x1f
-+#define MATCH_DI 0xfb
-+#define  MASK_DI 0x7ffffff
++#define MATCH_FADD_D 0xd3
++#define  MASK_FADD_D 0x1f1ff
 +#define MATCH_SLTIU 0x193
 +#define  MASK_SLTIU 0x3ff
 +#define MATCH_MTPCR 0x1fb
-+#define  MASK_MTPCR 0xf801ffff
++#define  MASK_MTPCR 0x1ffff
 +#define MATCH_VLB 0xb
 +#define  MASK_VLB 0x3fffff
 +#define MATCH_STOP 0x177
@@ -1648,6 +1594,8 @@ index 0000000..e417397
 +#define  MASK_MUL 0x1ffff
 +#define MATCH_C_LW 0xa
 +#define  MASK_C_LW 0x1f
++#define MATCH_VXCPTEVAC 0x237b
++#define  MASK_VXCPTEVAC 0xf83fffff
 +#define MATCH_VLW 0x10b
 +#define  MASK_VLW 0x3fffff
 +#define MATCH_VSSEGSTW 0x90f
@@ -1684,8 +1632,8 @@ index 0000000..e417397
 +#define  MASK_MFTX_D 0x3fffff
 +#define MATCH_DIV 0x633
 +#define  MASK_DIV 0x1ffff
-+#define MATCH_C_LD 0x9
-+#define  MASK_C_LD 0x1f
++#define MATCH_VTCFG 0xc73
++#define  MASK_VTCFG 0xf801ffff
 +#define MATCH_MFTX_S 0x1c053
 +#define  MASK_MFTX_S 0x3fffff
 +#define MATCH_VSSEGSTH 0x88f
@@ -1694,8 +1642,6 @@ index 0000000..e417397
 +#define  MASK_VVCFGIVL 0x3ff
 +#define MATCH_J 0x67
 +#define  MASK_J 0x7f
-+#define MATCH_EI 0x7b
-+#define  MASK_EI 0x7ffffff
 +#define MATCH_FENCE 0x12f
 +#define  MASK_FENCE 0x3ff
 +#define MATCH_VSW 0x10f
@@ -1708,6 +1654,8 @@ index 0000000..e417397
 +#define  MASK_FCVT_L_S 0x3ff1ff
 +#define MATCH_FLE_S 0x17053
 +#define  MASK_FLE_S 0x1ffff
++#define MATCH_FENCE_V_L 0x22f
++#define  MASK_FENCE_V_L 0x3ff
 +#define MATCH_VSB 0xf
 +#define  MASK_VSB 0x3fffff
 +#define MATCH_MFFSR 0x1d053
@@ -1744,6 +1692,8 @@ index 0000000..e417397
 +#define  MASK_MTFSR 0x3fffff
 +#define MATCH_VSSTH 0x108f
 +#define  MASK_VSSTH 0x1ffff
++#define MATCH_SC_W 0x1052b
++#define  MASK_SC_W 0x1ffff
 +#define MATCH_REM 0x733
 +#define  MASK_REM 0x1ffff
 +#define MATCH_SRLIW 0x29b
@@ -1804,16 +1754,24 @@ index 0000000..e417397
 +#define  MASK_VSSEGD 0x1ffff
 +#define MATCH_SRL 0x2b3
 +#define  MASK_SRL 0x1ffff
++#define MATCH_VENQCMD 0x2b7b
++#define  MASK_VENQCMD 0xf801ffff
++#define MATCH_FSUB_D 0x10d3
++#define  MASK_FSUB_D 0x1f1ff
 +#define MATCH_VFMTS 0x1973
 +#define  MASK_VFMTS 0x1ffff
++#define MATCH_VENQIMM1 0x2f7b
++#define  MASK_VENQIMM1 0xf801ffff
 +#define MATCH_FSGNJX_S 0x7053
 +#define  MASK_FSGNJX_S 0x1ffff
 +#define MATCH_VFMSV 0x973
 +#define  MASK_VFMSV 0x3fffff
-+#define MATCH_FEQ_D 0x150d3
-+#define  MASK_FEQ_D 0x1ffff
++#define MATCH_VENQIMM2 0x337b
++#define  MASK_VENQIMM2 0xf801ffff
 +#define MATCH_FCVT_D_WU 0xf0d3
 +#define  MASK_FCVT_D_WU 0x3ff1ff
++#define MATCH_VXCPTRESTORE 0x77b
++#define  MASK_VXCPTRESTORE 0xf83fffff
 +#define MATCH_VMTS 0x1873
 +#define  MASK_VMTS 0x1ffff
 +#define MATCH_OR 0x333
@@ -1858,8 +1816,10 @@ index 0000000..e417397
 +#define  MASK_RDTIME 0x7ffffff
 +#define MATCH_ANDI 0x393
 +#define  MASK_ANDI 0x3ff
-+#define MATCH_C_SRLI32 0xc19
-+#define  MASK_C_SRLI32 0x1c1f
++#define MATCH_CLEARPCR 0x7b
++#define  MASK_CLEARPCR 0x3ff
++#define MATCH_VENQCNT 0x377b
++#define  MASK_VENQCNT 0xf801ffff
 +#define MATCH_FSGNJN_D 0x60d3
 +#define  MASK_FSGNJN_D 0x1ffff
 +#define MATCH_FNMADD_S 0x4f
@@ -1880,14 +1840,12 @@ index 0000000..e417397
 +#define  MASK_C_BNE 0x1f
 +#define MATCH_FNMADD_D 0xcf
 +#define  MASK_FNMADD_D 0x1ff
-+#define MATCH_FENCE_G_CV 0x3af
-+#define  MASK_FENCE_G_CV 0x3ff
 +#define MATCH_AMOADD_D 0x1ab
 +#define  MASK_AMOADD_D 0x1ffff
 +#define MATCH_C_SW 0xd
 +#define  MASK_C_SW 0x1f
-+#define MATCH_AMOMAX_W 0x152b
-+#define  MASK_AMOMAX_W 0x1ffff
++#define MATCH_LR_D 0x101ab
++#define  MASK_LR_D 0x3fffff
 +#define MATCH_C_MOVE 0x2
 +#define  MASK_C_MOVE 0x801f
 +#define MATCH_FMOVN 0xef7
@@ -1906,10 +1864,14 @@ index 0000000..e417397
 +#define  MASK_FCVT_D_LU 0x3ff1ff
 +#define MATCH_AMOMAX_D 0x15ab
 +#define  MASK_AMOMAX_D 0x1ffff
++#define MATCH_FSD 0x1a7
++#define  MASK_FSD 0x3ff
 +#define MATCH_FCVT_W_D 0xa0d3
 +#define  MASK_FCVT_W_D 0x3ff1ff
 +#define MATCH_FMOVZ 0xaf7
 +#define  MASK_FMOVZ 0x1ffff
++#define MATCH_FEQ_D 0x150d3
++#define  MASK_FEQ_D 0x1ffff
 +#define MATCH_C_OR3 0x21c
 +#define  MASK_C_OR3 0x31f
 +#define MATCH_VMVV 0x73
@@ -1978,6 +1940,8 @@ index 0000000..e417397
 +#define  MASK_VSH 0x3fffff
 +#define MATCH_VLSEGSTB 0x80b
 +#define  MASK_VLSEGSTB 0xfff
++#define MATCH_VXCPTSAVE 0x37b
++#define  MASK_VXCPTSAVE 0xf83fffff
 +#define MATCH_VLSEGSTD 0x98b
 +#define  MASK_VLSEGSTD 0xfff
 +#define MATCH_VFLSEGD 0x258b
@@ -1986,6 +1950,8 @@ index 0000000..e417397
 +#define  MASK_VFLSEGW 0x1ffff
 +#define MATCH_VLSEGSTH 0x88b
 +#define  MASK_VLSEGSTH 0xfff
++#define MATCH_AMOMAX_W 0x152b
++#define  MASK_AMOMAX_W 0x1ffff
 +#define MATCH_FSGNJ_D 0x50d3
 +#define  MASK_FSGNJ_D 0x1ffff
 +#define MATCH_VFLSEGSTW 0xd0b
@@ -1994,30 +1960,32 @@ index 0000000..e417397
 +#define  MASK_C_SUB 0x801f
 +#define MATCH_MULHU 0x5b3
 +#define  MASK_MULHU 0x1ffff
-+#define MATCH_FCVT_L_D 0x80d3
-+#define  MASK_FCVT_L_D 0x3ff1ff
++#define MATCH_FENCE_V_G 0x2af
++#define  MASK_FENCE_V_G 0x3ff
 +#define MATCH_VMSV 0x873
 +#define  MASK_VMSV 0x3fffff
 +#define MATCH_VMST 0x1073
 +#define  MASK_VMST 0x1ffff
-+#define MATCH_FADD_D 0xd3
-+#define  MASK_FADD_D 0x1f1ff
-+#define MATCH_FCVT_S_WU 0xf053
-+#define  MASK_FCVT_S_WU 0x3ff1ff
-+#define MATCH_RDNPC 0x26b
-+#define  MASK_RDNPC 0x7ffffff
++#define MATCH_SETPCR 0xfb
++#define  MASK_SETPCR 0x3ff
++#define MATCH_FCVT_LU_S 0x9053
++#define  MASK_FCVT_LU_S 0x3ff1ff
++#define MATCH_VXCPTHOLD 0x277b
++#define  MASK_VXCPTHOLD 0xffffffff
 +#define MATCH_FCVT_S_L 0xc053
 +#define  MASK_FCVT_S_L 0x3ff1ff
 +#define MATCH_VFLSEGSTD 0xd8b
 +#define  MASK_VFLSEGSTD 0xfff
++#define MATCH_AUIPC 0x17
++#define  MASK_AUIPC 0x7f
 +#define MATCH_C_ADD 0x1a
 +#define  MASK_C_ADD 0x801f
 +#define MATCH_FCVT_LU_D 0x90d3
 +#define  MASK_FCVT_LU_D 0x3ff1ff
 +#define MATCH_VFLD 0x58b
 +#define  MASK_VFLD 0x3fffff
-+#define MATCH_FSUB_D 0x10d3
-+#define  MASK_FSUB_D 0x1f1ff
++#define MATCH_SC_D 0x105ab
++#define  MASK_SC_D 0x1ffff
 +#define MATCH_FMADD_S 0x43
 +#define  MASK_FMADD_S 0x1ff
 +#define MATCH_FCVT_W_S 0xa053
@@ -2026,6 +1994,8 @@ index 0000000..e417397
 +#define  MASK_VSSEGH 0x1ffff
 +#define MATCH_FSQRT_S 0x4053
 +#define  MASK_FSQRT_S 0x3ff1ff
++#define MATCH_VXCPTKILL 0xb7b
++#define  MASK_VXCPTKILL 0xffffffff
 +#define MATCH_C_SRAI 0x1019
 +#define  MASK_C_SRAI 0x1c1f
 +#define MATCH_AMOMIN_W 0x112b
@@ -2040,8 +2010,6 @@ index 0000000..e417397
 +#define  MASK_VFSW 0x3fffff
 +#define MATCH_AMOSWAP_D 0x5ab
 +#define  MASK_AMOSWAP_D 0x1ffff
-+#define MATCH_FENCE_L_V 0x22f
-+#define  MASK_FENCE_L_V 0x3ff
 +#define MATCH_FSQRT_D 0x40d3
 +#define  MASK_FSQRT_D 0x3ff1ff
 +#define MATCH_VFLW 0x50b
@@ -2064,8 +2032,8 @@ index 0000000..e417397
 +#define  MASK_FADD_S 0x1f1ff
 +#define MATCH_VLSEGB 0x200b
 +#define  MASK_VLSEGB 0x1ffff
-+#define MATCH_FSD 0x1a7
-+#define  MASK_FSD 0x3ff
++#define MATCH_FCVT_L_D 0x80d3
++#define  MASK_FCVT_L_D 0x3ff1ff
 +#define MATCH_VLSEGD 0x218b
 +#define  MASK_VLSEGD 0x1ffff
 +#define MATCH_VLSEGH 0x208b
@@ -2102,10 +2070,10 @@ index 0000000..e417397
 +#define  MASK_SD 0x3ff
 diff --git a/gcc-4.6.1/gcc/config/riscv/riscv-protos.h b/gcc-4.6.1/gcc/config/riscv/riscv-protos.h
 new file mode 100644
-index 0000000..7b8a972
+index 0000000..7852d1f
 --- /dev/null
 +++ gcc-4.6.1/gcc/config/riscv/riscv-protos.h
-@@ -0,0 +1,205 @@
+@@ -0,0 +1,135 @@
 +/* Prototypes of target machine for GNU compiler.  MIPS version.
 +   Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
 +   1999, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011
@@ -2140,32 +2108,9 @@ index 0000000..7b8a972
 +       The symbol's value will be calculated using absolute relocations,
 +       such as %hi and %lo.
 +
-+   SYMBOL_FORCE_TO_MEM
-+       The symbol's value must be forced to memory and loaded from there.
-+
-+   SYMBOL_GOT_DISP
-+       The symbol's value will be loaded directly from the GOT.
-+
-+   SYMBOL_GOTOFF_DISP
-+       An UNSPEC wrapper around a SYMBOL_GOT_DISP.  It represents the
-+       the offset from _gp of the symbol's GOT entry.
-+
-+   SYMBOL_GOTOFF_CALL
-+       Like SYMBOL_GOTOFF_DISP, but used when calling a global function.
-+       The GOT entry is allowed to point to a stub rather than to the
-+       function itself.
-+
-+   SYMBOL_GOTOFF_LOADGP
-+       An UNSPEC wrapper around a function's address.  It represents the
-+       offset of _gp from the start of the function.
-+
 +   SYMBOL_TLS
 +       A thread-local symbol.
 +
-+   SYMBOL_TLSGD
-+   SYMBOL_TLSLDM
-+   SYMBOL_DTPREL
-+   SYMBOL_GOTTPREL
 +   SYMBOL_TPREL
 +       UNSPEC wrappers around SYMBOL_TLS, corresponding to the
 +       thread-local storage relocation operators.
@@ -2174,55 +2119,10 @@ index 0000000..7b8a972
 +       For a 32-bit symbolic address X, this is the value of %hi(X). */
 +enum mips_symbol_type {
 +  SYMBOL_ABSOLUTE,
-+  SYMBOL_FORCE_TO_MEM,
-+  SYMBOL_GOT_DISP,
-+  SYMBOL_GOTOFF_DISP,
-+  SYMBOL_GOTOFF_CALL,
-+  SYMBOL_GOTOFF_LOADGP,
 +  SYMBOL_TLS,
-+  SYMBOL_TLSGD,
-+  SYMBOL_TLSLDM,
-+  SYMBOL_DTPREL,
-+  SYMBOL_GOTTPREL,
 +  SYMBOL_TPREL,
-+  SYMBOL_32_HIGH
-+};
-+#define NUM_SYMBOL_TYPES (SYMBOL_32_HIGH + 1)
-+
-+/* Identifiers a style of $gp initialization sequence.
-+
-+   LOADGP_NONE
-+      No initialization sequence is needed.
-+
-+   LOADGP_NEWABI
-+      The n32 and n64 PIC sequence (the kind traditionally generated
-+      by .cpsetup).
-+
-+   LOADGP_ABSOLUTE
-+      The GNU absolute sequence, as generated by loadgp_absolute. */
-+enum mips_loadgp_style {
-+  LOADGP_NONE,
-+  LOADGP_NEWABI,
-+  LOADGP_ABSOLUTE
-+};
-+
-+struct mips16e_save_restore_info;
-+
-+/* Classifies a type of call.
-+
-+   MIPS_CALL_NORMAL
-+      A normal call or call_value pattern.
-+
-+   MIPS_CALL_SIBCALL
-+      A sibcall or sibcall_value pattern.
-+
-+   MIPS_CALL_EPILOGUE
-+      A call inserted in the epilogue.  */
-+enum mips_call_type {
-+  MIPS_CALL_NORMAL,
-+  MIPS_CALL_SIBCALL,
-+  MIPS_CALL_EPILOGUE
 +};
++#define NUM_SYMBOL_TYPES (SYMBOL_TPREL + 1)
 +
 +extern bool mips_symbolic_constant_p (rtx, enum mips_symbol_type *);
 +extern int mips_regno_mode_ok_for_base_p (int, enum machine_mode, bool);
@@ -2231,7 +2131,6 @@ index 0000000..7b8a972
 +extern int mips_split_const_insns (rtx);
 +extern int mips_load_store_insns (rtx, rtx);
 +extern rtx mips_emit_move (rtx, rtx);
-+extern rtx mips_got_load (rtx, rtx, enum mips_symbol_type);
 +extern bool mips_split_symbol (rtx, rtx, enum machine_mode, rtx *);
 +extern rtx mips_unspec_address (rtx, enum mips_symbol_type);
 +extern void mips_move_integer (rtx, rtx, HOST_WIDE_INT);
@@ -2249,7 +2148,7 @@ index 0000000..7b8a972
 +extern void mips_expand_vcondv2sf (rtx, rtx, rtx, enum rtx_code, rtx, rtx);
 +extern void mips_expand_conditional_move (rtx *);
 +#endif
-+extern rtx mips_expand_call (enum mips_call_type, rtx, rtx, rtx, rtx, bool);
++extern rtx mips_expand_call (bool, rtx, rtx, rtx);
 +extern void mips_expand_fcc_reload (rtx, rtx, rtx);
 +extern void mips_set_return_address (rtx, rtx);
 +extern bool mips_expand_block_move (rtx, rtx, rtx);
@@ -2282,8 +2181,6 @@ index 0000000..7b8a972
 +
 +extern HOST_WIDE_INT mips_initial_elimination_offset (int, int);
 +extern rtx mips_return_addr (int, rtx);
-+extern bool mips_must_initialize_gp_p (void);
-+extern enum mips_loadgp_style mips_current_loadgp_style (void);
 +extern void mips_emit_save_slot_move (rtx, rtx, rtx);
 +extern void mips_expand_prologue (void);
 +extern void mips_expand_epilogue (bool);
@@ -2309,14 +2206,15 @@ index 0000000..7b8a972
 +extern void mips_expand_vector_init (rtx, rtx);
 +
 +extern bool mips_epilogue_uses (unsigned int);
++extern bool riscv_symbol_binds_local_p (const_rtx x);
 +
 +#endif /* ! GCC_MIPS_PROTOS_H */
 diff --git a/gcc-4.6.1/gcc/config/riscv/riscv.c b/gcc-4.6.1/gcc/config/riscv/riscv.c
 new file mode 100644
-index 0000000..a4d85c4
+index 0000000..26603b4
 --- /dev/null
 +++ gcc-4.6.1/gcc/config/riscv/riscv.c
-@@ -0,0 +1,6416 @@
+@@ -0,0 +1,5958 @@
 +/* Subroutines used for MIPS code generation.
 +   Copyright (C) 1989, 1990, 1991, 1993, 1994, 1995, 1996, 1997, 1998,
 +   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
@@ -2377,6 +2275,7 @@ index 0000000..a4d85c4
 +#include "bitmap.h"
 +#include "diagnostic.h"
 +#include "target-globals.h"
++#include <stdint.h>
 +
 +/*----------------------------------------------------------------------*/
 +/* RISCV_SYSCFG_VLEN_MAX                                                */
@@ -2537,22 +2436,6 @@ index 0000000..a4d85c4
 +
 +  /* The current frame information, calculated by mips_compute_frame_info.  */
 +  struct mips_frame_info frame;
-+
-+  /* The register to use as the function's global pointer, or INVALID_REGNUM
-+     if the function doesn't need one.  */
-+  unsigned int global_pointer;
-+
-+  /* True if the function has "inflexible" and "flexible" references
-+     to the global pointer.  See mips_cfun_has_inflexible_gp_ref_p
-+     and mips_cfun_has_flexible_gp_ref_p for details.  */
-+  bool has_flexible_gp_insn_p;
-+
-+  /* True if the function's prologue must load the global pointer
-+     value into pic_offset_table_rtx and store the same value in
-+     the function's cprestore slot (if any).  Even if this value
-+     is currently false, we may decide to set it to true later;
-+     see mips_must_initialize_gp_p () for details.  */
-+  bool must_initialize_gp_p;
 +};
 +
 +/* Information about a single argument.  */
@@ -2657,9 +2540,6 @@ index 0000000..a4d85c4
 +/* The processor that we should tune the code for.  */
 +enum processor mips_tune;
 +
-+/* Which ABI to use.  */
-+int mips_abi = MIPS_ABI_DEFAULT;
-+
 +/* Which cost information to use.  */
 +static const struct mips_rtx_cost_data *mips_cost;
 +
@@ -2685,25 +2565,14 @@ index 0000000..a4d85c4
 +
 +/* Index R is the smallest register class that contains register R.  */
 +const enum reg_class mips_regno_to_class[FIRST_PSEUDO_REGISTER] = {
-+/*
-+yunsup: new register mapping
-+x0, ra, v0, v1,
-+a0, a1, a2, a3,
-+a4, a5, a6, a7,
-+t0, t1, t2, t3,
-+t4, t5, t6, t7,
-+s0, s1, s2, s3,
-+s4, s5, s6, s7,
-+s8, s9, sp, tp
-+*/
-+  LEA_REGS,   LEA_REGS,       LEA_REGS,       V1_REG,
-+  LEA_REGS,   LEA_REGS,       LEA_REGS,       LEA_REGS,
-+  LEA_REGS,   LEA_REGS,       LEA_REGS,       LEA_REGS,
-+  LEA_REGS,   LEA_REGS,       LEA_REGS,       LEA_REGS,
-+  LEA_REGS,   LEA_REGS,       LEA_REGS,       PIC_FN_ADDR_REG,
-+  LEA_REGS,   LEA_REGS,       LEA_REGS,       LEA_REGS,
-+  LEA_REGS,   LEA_REGS,       LEA_REGS,       LEA_REGS,
-+  LEA_REGS,   LEA_REGS,       LEA_REGS,       LEA_REGS,
++  GR_REGS,    GR_REGS,        GR_REGS,        GR_REGS,
++  GR_REGS,    GR_REGS,        GR_REGS,        GR_REGS,
++  GR_REGS,    GR_REGS,        GR_REGS,        GR_REGS,
++  GR_REGS,    GR_REGS,        GR_REGS,        GR_REGS,
++  GR_REGS,    V1_REG,         GR_REGS,        GR_REGS,
++  GR_REGS,    GR_REGS,        GR_REGS,        GR_REGS,
++  GR_REGS,    GR_REGS,        GR_REGS,        GR_REGS,
++  GR_REGS,    GR_REGS,        GR_REGS,        GR_REGS,
 +  FP_REGS,    FP_REGS,        FP_REGS,        FP_REGS,
 +  FP_REGS,    FP_REGS,        FP_REGS,        FP_REGS,
 +  FP_REGS,    FP_REGS,        FP_REGS,        FP_REGS,
@@ -2938,6 +2807,18 @@ index 0000000..a4d85c4
 +  return GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x) != 0;
 +}
 +
++bool
++riscv_symbol_binds_local_p (const_rtx x)
++{
++  if (SYMBOL_REF_DECL (x))
++    {
++      if (DECL_BUILT_IN_CLASS (SYMBOL_REF_DECL (x)))
++      return true; /* Force local binding of memset etc. */
++      return targetm.binds_local_p (SYMBOL_REF_DECL (x));
++    }
++  return SYMBOL_REF_LOCAL_P (x);
++}
++
 +/* Return the method that should be used to access SYMBOL_REF or
 +   LABEL_REF X in context CONTEXT.  */
 +
@@ -2946,11 +2827,6 @@ index 0000000..a4d85c4
 +{
 +  if (mips_tls_symbol_p (x))
 +    return SYMBOL_TLS;
-+
-+  /* Don't use GOT accesses when -mno-shared is in effect.  */
-+  if (TARGET_ABICALLS && flag_pic)
-+    return SYMBOL_GOT_DISP;
-+
 +  return SYMBOL_ABSOLUTE;
 +}
 +
@@ -2996,47 +2872,34 @@ index 0000000..a4d85c4
 +      x = UNSPEC_ADDRESS (x);
 +    }
 +  else if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
-+    {
-+      *symbol_type = mips_classify_symbol (x);
-+      if (*symbol_type == SYMBOL_TLS)
-+      return false;
-+    }
++    *symbol_type = mips_classify_symbol (x);
 +  else
 +    return false;
 +
 +  if (offset == const0_rtx)
 +    return true;
 +
++  if (flag_pic)
++  /* Load the base address from the GOT, then add the offset. The offset
++     calculation can usually be folded into the load or store instruction. */
++    return false;
++
 +  /* Check whether a nonzero offset is valid for the underlying
 +     relocations.  */
 +  switch (*symbol_type)
 +    {
 +    case SYMBOL_ABSOLUTE:
-+    case SYMBOL_FORCE_TO_MEM:
-+    case SYMBOL_32_HIGH:
 +      /* If the target has 64-bit pointers and the object file only
 +       supports 32-bit symbols, the values of those symbols will be
 +       sign-extended.  In this case we can't allow an arbitrary offset
 +       in case the 32-bit value X + OFFSET has a different sign from X.  */
-+      if (Pmode == DImode)
-+      return offset_within_block_p (x, INTVAL (offset));
-+
-+      /* In other cases the relocations can handle any offset.  */
-+      return true;
++      return Pmode == SImode || offset_within_block_p (x, INTVAL (offset));
 +
 +    case SYMBOL_TPREL:
-+    case SYMBOL_DTPREL:
 +      /* There is no carry between the HI and LO REL relocations, so the
 +       offset is only valid if we know it won't lead to such a carry.  */
 +      return mips_offset_within_alignment_p (x, INTVAL (offset));
 +
-+    case SYMBOL_GOT_DISP:
-+    case SYMBOL_GOTOFF_DISP:
-+    case SYMBOL_GOTOFF_CALL:
-+    case SYMBOL_GOTOFF_LOADGP:
-+    case SYMBOL_TLSGD:
-+    case SYMBOL_TLSLDM:
-+    case SYMBOL_GOTTPREL:
 +    case SYMBOL_TLS:
 +      return false;
 +    }
@@ -3054,40 +2917,9 @@ index 0000000..a4d85c4
 +  switch (type)
 +    {
 +    case SYMBOL_ABSOLUTE:
-+      return 2;
-+
-+    case SYMBOL_FORCE_TO_MEM:
-+      /* LEAs will be converted into constant-pool references by
-+       mips_reorg.  */
-+      if (mode == MAX_MACHINE_MODE)
-+      return 1;
-+
-+      /* The constant must be loaded and then dereferenced.  */
-+      return 0;
-+
-+    case SYMBOL_GOT_DISP:
-+      /* The constant will have to be loaded from the GOT before it
-+       is used in an address.  */
-+      if (mode != MAX_MACHINE_MODE)
-+      return 0;
-+
-+      /* Fall through.  */
-+
-+    case SYMBOL_GOTOFF_DISP:
-+    case SYMBOL_GOTOFF_CALL:
-+    case SYMBOL_GOTOFF_LOADGP:
-+    case SYMBOL_32_HIGH:
-+    case SYMBOL_TLSGD:
-+    case SYMBOL_TLSLDM:
-+    case SYMBOL_DTPREL:
-+    case SYMBOL_GOTTPREL:
 +    case SYMBOL_TPREL:
-+      /* A 16-bit constant formed by a single relocation, or a 32-bit
-+       constant formed from a high 16-bit relocation and a low 16-bit
-+       relocation.  Use mips_split_p to determine which.  32-bit
-+       constants need an "lui; addiu" sequence for normal mode and
-+       an "li; sll; addiu" sequence for MIPS16 mode.  */
-+      return !mips_split_p[type] ? 1 : 2;
++      /* One of LUI or AUIPC, followed by one of ADDI, LD, or LW. */
++      return 2;
 +
 +    case SYMBOL_TLS:
 +      /* We don't treat a bare TLS symbol as a constant.  */
@@ -3131,7 +2963,7 @@ index 0000000..a4d85c4
 +    return true;
 +
 +  split_const (x, &base, &offset);
-+  if (mips_symbolic_constant_p (base, &type) && type != SYMBOL_FORCE_TO_MEM)
++  if (mips_symbolic_constant_p (base, &type))
 +    {
 +      /* The same optimization as for CONST_INT.  */
 +      if (SMALL_INT (offset) && mips_symbol_insns (type, MAX_MACHINE_MODE) > 0)
@@ -3278,9 +3110,7 @@ index 0000000..a4d85c4
 +    case LABEL_REF:
 +    case SYMBOL_REF:
 +      info->type = ADDRESS_SYMBOLIC;
-+      return (mips_symbolic_constant_p (x, &info->symbol_type)
-+            && mips_symbol_insns (info->symbol_type, mode) > 0
-+            && !mips_split_p[info->symbol_type]);
++      return false;
 +
 +    default:
 +      return false;
@@ -3484,33 +3314,6 @@ index 0000000..a4d85c4
 +    }
 +}
 +
-+/* Emit a call sequence with call pattern PATTERN and return the call
-+   instruction itself (which is not necessarily the last instruction
-+   emitted).  ORIG_ADDR is the original, unlegitimized address,
-+   ADDR is the legitimized form, and LAZY_P is true if the call
-+   address is lazily-bound.  */
-+
-+static rtx
-+mips_emit_call_insn (rtx pattern, bool lazy_p)
-+{
-+  rtx insn;
-+
-+  insn = emit_call_insn (pattern);
-+
-+  if (lazy_p)
-+    /* Lazy-binding stubs require $gp to be valid on entry.  */
-+    use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx);
-+
-+  if (TARGET_USE_GOT)
-+    {
-+      /* See the comment above load_call<mode> for details.  */
-+      use_reg (&CALL_INSN_FUNCTION_USAGE (insn),
-+             gen_rtx_REG (Pmode, GOT_VERSION_REGNUM));
-+      emit_insn (gen_update_got_version ());
-+    }
-+  return insn;
-+}
-+\f
 +/* Wrap symbol or label BASE in an UNSPEC address of type SYMBOL_TYPE,
 +   then add CONST_INT OFFSET to the result.  */
 +
@@ -3570,43 +3373,6 @@ index 0000000..a4d85c4
 +  return base;
 +}
 +
-+/* Return the RHS of a load_call<mode> insn.  */
-+
-+static rtx
-+mips_unspec_call (rtx reg, rtx symbol)
-+{
-+  rtvec vec;
-+
-+  vec = gen_rtvec (3, reg, symbol, gen_rtx_REG (SImode, GOT_VERSION_REGNUM));
-+  return gen_rtx_UNSPEC (Pmode, vec, UNSPEC_LOAD_CALL);
-+}
-+
-+/* Create and return a GOT reference of type TYPE for address ADDR.
-+   TEMP, if nonnull, is a scratch Pmode base register.  */
-+
-+rtx
-+mips_got_load (rtx temp, rtx addr, enum mips_symbol_type type)
-+{
-+  rtx base, high, lo_sum_symbol;
-+
-+  base = pic_offset_table_rtx;
-+
-+  /* If we used the temporary register to load $gp, we can't use
-+     it for the high part as well.  */
-+  if (temp != NULL && reg_overlap_mentioned_p (base, temp))
-+    temp = NULL;
-+
-+  high = mips_unspec_offset_high (temp, base, addr, type);
-+  lo_sum_symbol = mips_unspec_address (addr, type);
-+
-+  if (type == SYMBOL_GOTOFF_CALL)
-+    return mips_unspec_call (high, lo_sum_symbol);
-+  else
-+    return (Pmode == SImode
-+          ? gen_unspec_gotsi (high, lo_sum_symbol)
-+          : gen_unspec_gotdi (high, lo_sum_symbol));
-+}
-+
 +/* If MODE is MAX_MACHINE_MODE, ADDR appears as a move operand, otherwise
 +   it appears in a MEM of that mode.  Return true if ADDR is a legitimate
 +   constant in that context and can be split into high and low parts.
@@ -3633,19 +3399,11 @@ index 0000000..a4d85c4
 +        && mips_split_p[symbol_type])
 +      {
 +        if (low_out)
-+          switch (symbol_type)
-+            {
-+            case SYMBOL_GOT_DISP:
-+              /* SYMBOL_GOT_DISP symbols are loaded from the GOT.  */
-+              *low_out = mips_got_load (temp, addr, SYMBOL_GOTOFF_DISP);
-+              break;
-+
-+            default:
-+              high = gen_rtx_HIGH (Pmode, copy_rtx (addr));
-+              high = mips_force_temporary (temp, high);
-+              *low_out = gen_rtx_LO_SUM (Pmode, high, addr);
-+              break;
-+            }
++          {
++            high = gen_rtx_HIGH (Pmode, copy_rtx (addr));
++            high = mips_force_temporary (temp, high);
++            *low_out = gen_rtx_LO_SUM (Pmode, high, addr);
++          }
 +        return true;
 +      }
 +    }
@@ -3673,7 +3431,21 @@ index 0000000..a4d85c4
 +    }
 +  return plus_constant (reg, offset);
 +}
-+\f
++
++/* Load an entry from the GOT. */
++static rtx riscv_got_load(rtx dest, rtx sym)
++{
++  return (Pmode == DImode ? gen_got_loaddi(dest, sym) : gen_got_loadsi(dest, sym));
++}
++static rtx riscv_got_load_tls_gd(rtx dest, rtx sym)
++{
++  return (Pmode == DImode ? gen_got_load_tls_gddi(dest, sym) : gen_got_load_tls_gdsi(dest, sym));
++}
++static rtx riscv_got_load_tls_ie(rtx dest, rtx sym)
++{
++  return (Pmode == DImode ? gen_got_load_tls_iedi(dest, sym) : gen_got_load_tls_iesi(dest, sym));
++}
++
 +/* The __tls_get_attr symbol.  */
 +static GTY(()) rtx mips_tls_symbol;
 +
@@ -3683,25 +3455,19 @@ index 0000000..a4d85c4
 +   return value location.  */
 +
 +static rtx
-+mips_call_tls_get_addr (rtx sym, enum mips_symbol_type type, rtx v0)
++mips_call_tls_get_addr (rtx sym, rtx v0)
 +{
-+  rtx insn, loc, a0, temp;
++  rtx insn, a0;
 +
 +  a0 = gen_rtx_REG (Pmode, GP_ARG_FIRST);
 +
 +  if (!mips_tls_symbol)
 +    mips_tls_symbol = init_one_libfunc ("__tls_get_addr");
 +
-+  temp = gen_reg_rtx (Pmode);
-+  loc = mips_unspec_offset_high (temp, pic_offset_table_rtx, sym, type);
-+  loc = gen_rtx_LO_SUM (Pmode, loc,
-+                      mips_unspec_address (sym, type));
-+
 +  start_sequence ();
-+
-+  emit_insn (gen_rtx_SET (Pmode, a0, loc));
-+  insn = mips_expand_call (MIPS_CALL_NORMAL, v0, mips_tls_symbol,
-+                         const0_rtx, NULL_RTX, false);
++  
++  emit_insn (riscv_got_load_tls_gd(a0, sym));
++  insn = mips_expand_call (false, v0, mips_tls_symbol, const0_rtx);
 +  RTL_CONST_CALL_P (insn) = 1;
 +  use_reg (&CALL_INSN_FUNCTION_USAGE (insn), a0);
 +  insn = get_insns ();
@@ -3718,7 +3484,7 @@ index 0000000..a4d85c4
 +static rtx
 +mips_legitimize_tls_address (rtx loc)
 +{
-+  rtx dest, insn, v0, tp, tmp1, tmp2, eqv;
++  rtx dest, insn, v0, tp, tmp1;
 +  enum tls_model model;
 +
 +  model = SYMBOL_REF_TLS_MODEL (loc);
@@ -3730,34 +3496,19 @@ index 0000000..a4d85c4
 +
 +  switch (model)
 +    {
++    case TLS_MODEL_LOCAL_DYNAMIC:
++      /* We don't support LDM TLS, so fall through.*/
 +    case TLS_MODEL_GLOBAL_DYNAMIC:
 +      v0 = gen_rtx_REG (Pmode, GP_RETURN);
-+      insn = mips_call_tls_get_addr (loc, SYMBOL_TLSGD, v0);
++      insn = mips_call_tls_get_addr (loc, v0);
 +      dest = gen_reg_rtx (Pmode);
 +      emit_libcall_block (insn, dest, v0, loc);
 +      break;
 +
-+    case TLS_MODEL_LOCAL_DYNAMIC:
-+      v0 = gen_rtx_REG (Pmode, GP_RETURN);
-+      insn = mips_call_tls_get_addr (loc, SYMBOL_TLSLDM, v0);
-+      tmp1 = gen_reg_rtx (Pmode);
-+
-+      /* Attach a unique REG_EQUIV, to allow the RTL optimizers to
-+       share the LDM result with other LD model accesses.  */
-+      eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
-+                          UNSPEC_TLS_LDM);
-+      emit_libcall_block (insn, tmp1, v0, eqv);
-+
-+      tmp2 = mips_unspec_offset_high (NULL, tmp1, loc, SYMBOL_DTPREL);
-+      dest = gen_rtx_LO_SUM (Pmode, tmp2,
-+                           mips_unspec_address (loc, SYMBOL_DTPREL));
-+      break;
-+
 +    case TLS_MODEL_INITIAL_EXEC:
 +      tp = gen_rtx_REG (Pmode, THREAD_POINTER_REGNUM);
 +      tmp1 = gen_reg_rtx (Pmode);
-+      tmp2 = mips_got_load (tmp1, loc, SYMBOL_GOTTPREL);
-+      emit_insn (gen_rtx_SET (VOIDmode, tmp1, tmp2));
++      emit_insn (riscv_got_load_tls_ie(tmp1, loc));
 +      dest = gen_reg_rtx (Pmode);
 +      emit_insn (gen_add3_insn (dest, tmp1, tp));
 +      break;
@@ -3819,6 +3570,36 @@ index 0000000..a4d85c4
 +  return x;
 +}
 +
++static int
++riscv_split_integer_cost (HOST_WIDE_INT val)
++{
++  int cost = 0;
++  struct mips_integer_op codes[MIPS_MAX_INTEGER_OPS];
++  int32_t loval = val, hival = (val - (int32_t)val) >> 32;
++
++  cost += riscv_build_integer(codes, loval);
++  if (loval != hival)
++    cost += riscv_build_integer(codes, hival);
++  return cost + 2;
++}
++
++/* Try to split a 64b integer into 32b parts, then reassemble. */
++
++static rtx
++riscv_split_integer (HOST_WIDE_INT val, enum machine_mode mode)
++{
++  int32_t loval = val, hival = (val - (int32_t)val) >> 32;
++  rtx hi = gen_reg_rtx (mode), lo = gen_reg_rtx (mode);
++
++  mips_move_integer (hi, hi, hival);
++  mips_move_integer (lo, lo, loval);
++
++  hi = gen_rtx_fmt_ee (ASHIFT, mode, hi, GEN_INT (32));
++  hi = force_reg (mode, hi);
++
++  return gen_rtx_fmt_ee (PLUS, mode, hi, lo);
++}
++
 +/* Load VALUE into DEST.  TEMP is as for mips_force_temporary.  */
 +
 +void
@@ -3832,21 +3613,8 @@ index 0000000..a4d85c4
 +  mode = GET_MODE (dest);
 +  num_ops = riscv_build_integer (codes, value);
 +
-+  if (can_create_pseudo_p () && num_ops > 4)
-+    {
-+      /* Split into two 32-bit constants. Account for SExt of lower word. */
-+      rtx upper = gen_reg_rtx (mode);
-+      HOST_WIDE_INT correction = (value & 0x80000000L) ? 1 : 0;
-+      mips_move_integer (upper, upper, (value >> 32) + correction);
-+
-+      rtx lower = gen_reg_rtx (mode);
-+      mips_move_integer (lower, lower, value << 32 >> 32);
-+
-+      upper = gen_rtx_fmt_ee (ASHIFT, mode, upper, GEN_INT (32));
-+      upper = force_reg (mode, upper);
-+
-+      x = gen_rtx_fmt_ee (PLUS, mode, upper, lower);
-+    }
++  if (can_create_pseudo_p () && num_ops >= riscv_split_integer_cost (value))
++    x = riscv_split_integer (value, mode);
 +  else
 +    {
 +      /* Apply each binary operation to X. */
@@ -4213,11 +3981,6 @@ index 0000000..a4d85c4
 +    case SYMBOL_REF:
 +    case LABEL_REF:
 +    case CONST_DOUBLE:
-+      if (force_to_mem_operand (x, VOIDmode))
-+      {
-+        *total = COSTS_N_INSNS (1);
-+        return true;
-+      }
 +      cost = mips_const_insns (x);
 +      if (cost > 0)
 +      {
@@ -4648,6 +4411,12 @@ index 0000000..a4d85c4
 +        gcc_assert (!mips_split_p[symbol_type]);
 +        return "li\t%0,%R1";
 +      }
++
++      if (symbolic_operand (src, VOIDmode))
++      {
++        gcc_assert (flag_pic);
++        return "la\t%0,%1";
++      }
 +    }
 +  if (src_code == REG && FP_REG_P (REGNO (src)))
 +    {
@@ -5481,51 +5250,6 @@ index 0000000..a4d85c4
 +  std_expand_builtin_va_start (valist, nextarg);
 +}
 +
-+/* Return true if SYMBOL_REF X binds locally.  */
-+
-+static bool
-+mips_symbol_binds_local_p (const_rtx x)
-+{
-+  return (SYMBOL_REF_DECL (x)
-+        ? targetm.binds_local_p (SYMBOL_REF_DECL (x))
-+        : SYMBOL_REF_LOCAL_P (x));
-+}
-+
-+/* Return true if calls to X can use R_MIPS_CALL* relocations.  */
-+
-+static bool
-+mips_ok_for_lazy_binding_p (rtx x)
-+{
-+  return (TARGET_USE_GOT
-+        && GET_CODE (x) == SYMBOL_REF
-+        && !SYMBOL_REF_BIND_NOW_P (x)
-+        && !mips_symbol_binds_local_p (x));
-+}
-+
-+/* Load function address ADDR into register DEST.  TYPE is as for
-+   mips_expand_call.  Return true if we used an explicit lazy-binding
-+   sequence.  */
-+
-+static bool
-+mips_load_call_address (enum mips_call_type type, rtx dest, rtx addr)
-+{
-+  /* If we're generating PIC, and this call is to a global function,
-+     try to allow its address to be resolved lazily.  This isn't
-+     possible for sibcalls when $gp is call-saved because the value
-+     of $gp on entry to the stub would be our caller's gp, not ours.  */
-+  if (type != MIPS_CALL_SIBCALL && mips_ok_for_lazy_binding_p (addr))
-+    {
-+      addr = mips_got_load (dest, addr, SYMBOL_GOTOFF_CALL);
-+      emit_insn (gen_rtx_SET (VOIDmode, dest, addr));
-+      return true;
-+    }
-+  else
-+    {
-+      mips_emit_move (dest, addr);
-+      return false;
-+    }
-+}
-+
 +/* Expand a call of type TYPE.  RESULT is where the result will go (null
 +   for "call"s and "sibcall"s), ADDR is the address of the function,
 +   ARGS_SIZE is the size of the arguments and AUX is the value passed
@@ -5536,26 +5260,22 @@ index 0000000..a4d85c4
 +   Return the call itself.  */
 +
 +rtx
-+mips_expand_call (enum mips_call_type type, rtx result, rtx addr,
-+                rtx args_size, rtx aux ATTRIBUTE_UNUSED, bool lazy_p)
++mips_expand_call (bool sibcall_p, rtx result, rtx addr, rtx args_size)
 +{
-+  rtx orig_addr, pattern;
++  rtx pattern, insn;
 +
-+  orig_addr = addr;
 +  if (!call_insn_operand (addr, VOIDmode))
 +    {
-+      if (type == MIPS_CALL_EPILOGUE)
-+      addr = MIPS_EPILOGUE_TEMP (Pmode);
-+      else
-+      addr = gen_reg_rtx (Pmode);
-+      lazy_p |= mips_load_call_address (type, addr, orig_addr);
++      rtx reg = MIPS_EPILOGUE_TEMP (Pmode, true);
++      mips_emit_move (reg, addr);
++      addr = reg;
 +    }
 +
 +  if (result == 0)
 +    {
 +      rtx (*fn) (rtx, rtx);
 +
-+      if (type == MIPS_CALL_SIBCALL)
++      if (sibcall_p)
 +      fn = gen_sibcall_internal;
 +      else
 +      fn = gen_call_internal;
@@ -5568,7 +5288,7 @@ index 0000000..a4d85c4
 +      rtx (*fn) (rtx, rtx, rtx, rtx);
 +      rtx reg1, reg2;
 +
-+      if (type == MIPS_CALL_SIBCALL)
++      if (sibcall_p)
 +      fn = gen_sibcall_value_multiple_internal;
 +      else
 +      fn = gen_call_value_multiple_internal;
@@ -5581,7 +5301,7 @@ index 0000000..a4d85c4
 +    {
 +      rtx (*fn) (rtx, rtx, rtx);
 +
-+      if (type == MIPS_CALL_SIBCALL)
++      if (sibcall_p)
 +      fn = gen_sibcall_value_internal;
 +      else
 +      fn = gen_call_value_internal;
@@ -5592,7 +5312,16 @@ index 0000000..a4d85c4
 +      pattern = fn (result, addr, args_size);
 +    }
 +
-+  return mips_emit_call_insn (pattern, lazy_p);
++  insn = emit_call_insn (pattern);
++
++  if (TARGET_USE_GOT)
++    {
++      /* See the comment above load_call<mode> for details.  */
++      use_reg (&CALL_INSN_FUNCTION_USAGE (insn),
++             gen_rtx_REG (Pmode, GOT_VERSION_REGNUM));
++      emit_insn (gen_update_got_version ());
++    }
++  return insn;
 +}
 +
 +/* Emit straight-line code to move LENGTH bytes from SRC to DEST.
@@ -5755,42 +5484,12 @@ index 0000000..a4d85c4
 +  memset (mips_hi_relocs, '\0', sizeof (mips_hi_relocs));
 +  memset (mips_lo_relocs, '\0', sizeof (mips_lo_relocs));
 +
-+  mips_split_p[SYMBOL_ABSOLUTE] = true;
-+  mips_hi_relocs[SYMBOL_ABSOLUTE] = "%hi(";
-+  mips_lo_relocs[SYMBOL_ABSOLUTE] = "%lo(";
-+
-+  mips_lo_relocs[SYMBOL_32_HIGH] = "%hi(";
-+
-+  /* The HIGH and LO_SUM are matched by special .md patterns.  */
-+  mips_split_p[SYMBOL_GOT_DISP] = true;
-+
-+  mips_split_p[SYMBOL_GOTOFF_DISP] = true;
-+  mips_hi_relocs[SYMBOL_GOTOFF_DISP] = "%got_hi(";
-+  mips_lo_relocs[SYMBOL_GOTOFF_DISP] = "%got_lo(";
-+
-+  mips_split_p[SYMBOL_GOTOFF_CALL] = true;
-+  mips_hi_relocs[SYMBOL_GOTOFF_CALL] = "%call_hi(";
-+  mips_lo_relocs[SYMBOL_GOTOFF_CALL] = "%call_lo(";
-+
-+  mips_split_p[SYMBOL_GOTTPREL] = true;
-+  mips_hi_relocs[SYMBOL_GOTTPREL] = "%gottp_hi(";
-+  mips_lo_relocs[SYMBOL_GOTTPREL] = "%gottp_lo(";
-+
-+  mips_split_p[SYMBOL_TLSGD] = true;
-+  mips_hi_relocs[SYMBOL_TLSGD] = "%tlsgd_hi(";
-+  mips_lo_relocs[SYMBOL_TLSGD] = "%tlsgd_lo(";
-+
-+  mips_split_p[SYMBOL_TLSLDM] = true;
-+  mips_hi_relocs[SYMBOL_TLSLDM] = "%tlsldm_hi(";
-+  mips_lo_relocs[SYMBOL_TLSLDM] = "%tlsldm_lo(";
-+
-+  mips_split_p[SYMBOL_GOTOFF_LOADGP] = true;
-+  mips_hi_relocs[SYMBOL_GOTOFF_LOADGP] = "%hi(%neg(%gp_rel(";
-+  mips_lo_relocs[SYMBOL_GOTOFF_LOADGP] = "%lo(%neg(%gp_rel(";
-+
-+  mips_split_p[SYMBOL_DTPREL] = true;
-+  mips_hi_relocs[SYMBOL_DTPREL] = "%dtprel_hi(";
-+  mips_lo_relocs[SYMBOL_DTPREL] = "%dtprel_lo(";
++  if (!flag_pic)
++    {
++      mips_split_p[SYMBOL_ABSOLUTE] = true;
++      mips_hi_relocs[SYMBOL_ABSOLUTE] = "%hi(";
++      mips_lo_relocs[SYMBOL_ABSOLUTE] = "%lo(";
++    }
 +
 +  mips_split_p[SYMBOL_TPREL] = true;
 +  mips_hi_relocs[SYMBOL_TPREL] = "%tprel_hi(";
@@ -6258,22 +5957,6 @@ index 0000000..a4d85c4
 +}
 +#endif
 +
-+/* Implement TARGET_ASM_FILE_START.  */
-+
-+static void
-+mips_file_start (void)
-+{
-+  default_file_start ();
-+
-+  /* If TARGET_ABICALLS, tell GAS to generate -KPIC code.  */
-+  if (TARGET_ABICALLS)
-+    {
-+      fprintf (asm_out_file, "\t.abicalls\n");
-+      if (!flag_pic)
-+      fprintf (asm_out_file, "\t.option\tpic0\n");
-+    }
-+}
-+\f
 +/* Make the last instruction frame-related and note that it performs
 +   the operation described by FRAME_PATTERN.  */
 +
@@ -6303,136 +5986,6 @@ index 0000000..a4d85c4
 +  return set;
 +}
 +
-+/* Return true if predicate PRED is true for at least one instruction.
-+   Cache the result in *CACHE, and assume that the result is true
-+   if *CACHE is already true.  */
-+
-+static bool
-+mips_find_gp_ref (bool *cache, bool (*pred) (rtx))
-+{
-+  rtx insn;
-+
-+  if (!*cache)
-+    {
-+      push_topmost_sequence ();
-+      for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
-+      if (USEFUL_INSN_P (insn) && pred (insn))
-+        {
-+          *cache = true;
-+          break;
-+        }
-+      pop_topmost_sequence ();
-+    }
-+  return *cache;
-+}
-+
-+/* Return true if INSN refers to the global pointer in a "flexible" way.
-+   See mips_cfun_has_flexible_gp_ref_p for details.  */
-+
-+static bool
-+mips_insn_has_flexible_gp_ref_p (rtx insn)
-+{
-+  return (get_attr_got (insn) != GOT_UNSET
-+        || reg_overlap_mentioned_p (pic_offset_table_rtx, PATTERN (insn)));
-+}
-+
-+/* Return true if the current function references the global pointer,
-+   but if those references do not inherently require the global pointer
-+   to be $28.  Assume !mips_cfun_has_inflexible_gp_ref_p ().  */
-+
-+static bool
-+mips_cfun_has_flexible_gp_ref_p (void)
-+{
-+  return mips_find_gp_ref (&cfun->machine->has_flexible_gp_insn_p,
-+                         mips_insn_has_flexible_gp_ref_p);
-+}
-+
-+/* Return true if the current function's prologue must load the global
-+   pointer value into pic_offset_table_rtx and store the same value in
-+   the function's cprestore slot (if any).
-+
-+   One problem we have to deal with is that, when emitting GOT-based
-+   position independent code, long-branch sequences will need to load
-+   the address of the branch target from the GOT.  We don't know until
-+   the very end of compilation whether (and where) the function needs
-+   long branches, so we must ensure that _any_ branch can access the
-+   global pointer in some form.  However, we do not want to pessimize
-+   the usual case in which all branches are short.
-+
-+   We handle this as follows:
-+
-+   (1) During reload, we set cfun->machine->global_pointer to
-+       INVALID_REGNUM if we _know_ that the current function
-+       doesn't need a global pointer.  This is only valid if
-+       long branches don't need the GOT.
-+
-+       Otherwise, we assume that we might need a global pointer
-+       and pick an appropriate register.
-+
-+   (2) If cfun->machine->global_pointer != INVALID_REGNUM,
-+       we ensure that the global pointer is available at every
-+       block boundary bar entry and exit.  We do this in one of two ways:
-+
-+       - If the function has a cprestore slot, we ensure that this
-+       slot is valid at every branch.  However, as explained in
-+       point (6) below, there is no guarantee that pic_offset_table_rtx
-+       itself is valid if new uses of the global pointer are introduced
-+       after the first post-epilogue split.
-+
-+       We guarantee that the cprestore slot is valid by loading it
-+       into a fake register, CPRESTORE_SLOT_REGNUM.  We then make
-+       this register live at every block boundary bar function entry
-+       and exit.  It is then invalid to move the load (and thus the
-+       preceding store) across a block boundary.
-+
-+       - If the function has no cprestore slot, we guarantee that
-+       pic_offset_table_rtx itself is valid at every branch.
-+
-+   (3) During prologue and epilogue generation, we emit "ghost"
-+       placeholder instructions to manipulate the global pointer.
-+
-+   (4) During prologue generation, we set cfun->machine->must_initialize_gp_p
-+       and cfun->machine->must_restore_gp_when_clobbered_p if we already know
-+       that the function needs a global pointer.  (There is no need to set
-+       them earlier than this, and doing it as late as possible leads to
-+       fewer false positives.)
-+
-+   (5) If cfun->machine->must_initialize_gp_p is true during a
-+       split_insns pass, we split the ghost instructions into real
-+       instructions.  These split instructions can then be optimized in
-+       the usual way.  Otherwise, we keep the ghost instructions intact,
-+       and optimize for the case where they aren't needed.  We still
-+       have the option of splitting them later, if we need to introduce
-+       new uses of the global pointer.
-+
-+       For example, the scheduler ignores a ghost instruction that
-+       stores $28 to the stack, but it handles the split form of
-+       the ghost instruction as an ordinary store.
-+
-+   Note that the ghost instructions must have a zero length for three reasons:
-+
-+   - Giving the length of the underlying $gp sequence might cause
-+     us to use long branches in cases where they aren't really needed.
-+
-+   - They would perturb things like alignment calculations.
-+
-+   - More importantly, the hazard detection in md_reorg relies on
-+     empty instructions having a zero length.
-+
-+   If we find a long branch and split the ghost instructions at the
-+   end of md_reorg, the split could introduce more long branches.
-+   That isn't a problem though, because we still do the split before
-+   the final shorten_branches pass.
-+
-+   This is extremely ugly, but it seems like the best compromise between
-+   correctness and efficiency.  */
-+
-+bool
-+mips_must_initialize_gp_p (void)
-+{
-+  return cfun->machine->must_initialize_gp_p;
-+}
-+
 +/* Return true if the current function must save register REGNO.  */
 +
 +static bool
@@ -6441,7 +5994,6 @@ index 0000000..a4d85c4
 +  bool call_saved = !global_regs[regno] && !call_really_used_regs[regno];
 +  bool might_clobber = crtl->saves_all_registers
 +                     || df_regs_ever_live_p (regno)
-+                     || cfun->machine->global_pointer == regno
 +                     || (regno == HARD_FRAME_POINTER_REGNUM
 +                         && frame_pointer_needed);
 +
@@ -6449,29 +6001,6 @@ index 0000000..a4d85c4
 +       || (regno == RETURN_ADDR_REGNUM && crtl->calls_eh_return);
 +}
 +
-+/* Return the register that should be used as the global pointer
-+   within this function.  Return INVALID_REGNUM if the function
-+   doesn't need a global pointer.  */
-+
-+static unsigned int
-+mips_global_pointer (void)
-+{
-+  /* $gp is always available unless we're using a GOT.  */
-+  if (!TARGET_USE_GOT)
-+    return GLOBAL_POINTER_REGNUM;
-+
-+  /* If there are no current references to $gp, then the only uses
-+     we can introduce later are those involved in long branches.  */
-+  if (!mips_cfun_has_flexible_gp_ref_p ())
-+    return INVALID_REGNUM;
-+
-+  /* For non-leaf functions, use a saved register. */
-+  if (!current_function_is_leaf)
-+    return GLOBAL_POINTER_REGNUM_NONLEAF;
-+
-+  return GLOBAL_POINTER_REGNUM;
-+}
-+
 +/* Populate the current function's mips_frame_info structure.
 +
 +   MIPS stack frames look like:
@@ -6536,8 +6065,6 @@ index 0000000..a4d85c4
 +  frame = &cfun->machine->frame;
 +  memset (frame, 0, sizeof (*frame));
 +
-+  cfun->machine->global_pointer = mips_global_pointer ();
-+
 +  /* Find out which GPRs we need to save.  */
 +  for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
 +    if (mips_save_reg_p (regno))
@@ -6587,21 +6114,6 @@ index 0000000..a4d85c4
 +  /* Next points the incoming stack pointer and any incoming arguments. */
 +}
 +
-+/* Return the style of GP load sequence that is being used for the
-+   current function.  */
-+
-+enum mips_loadgp_style
-+mips_current_loadgp_style (void)
-+{
-+  if (!TARGET_USE_GOT || cfun->machine->global_pointer == INVALID_REGNUM)
-+    return LOADGP_NONE;
-+
-+  if (TARGET_ABICALLS && !flag_pic)
-+    return LOADGP_ABSOLUTE;
-+
-+  return LOADGP_NEWABI;
-+}
-+
 +/* Make sure that we're not trying to eliminate to the wrong hard frame
 +   pointer.  */
 +
@@ -6646,11 +6158,6 @@ index 0000000..a4d85c4
 +{
 +  if (TARGET_USE_GOT)
 +    {
-+      /* PIC_FUNCTION_ADDR_REGNUM is live if we need it to set up
-+       the global pointer.   */
-+      if (flag_pic)
-+      bitmap_set_bit (regs, PIC_FUNCTION_ADDR_REGNUM);
-+
 +      /* See the comment above load_call<mode> for details.  */
 +      bitmap_set_bit (regs, GOT_VERSION_REGNUM);
 +    }
@@ -6712,31 +6219,22 @@ index 0000000..a4d85c4
 +  HOST_WIDE_INT offset;
 +  int regno;
 +
-+  /* Save the return address at the top of the frame. */
++  /* Save the link register and s-registers. */
 +  offset = cfun->machine->frame.gp_sp_offset - sp_offset;
-+  if (BITSET_P (cfun->machine->frame.mask, LINK_REG))
-+    {
-+      mips_save_restore_reg (word_mode, LINK_REG + GP_REG_FIRST, offset, fn);
-+      offset -= UNITS_PER_WORD;
-+    }
-+
-+  /* Save the s-registers in reverse order. */
-+  for (regno = GP_REG_NUM-1; regno >= 0; regno--, regno -= (regno == LINK_REG))
-+    {
-+      if (BITSET_P (cfun->machine->frame.mask, regno))
-+        {
-+          mips_save_restore_reg (word_mode, regno + GP_REG_FIRST, offset, fn);
-+          offset -= UNITS_PER_WORD;
-+        }
-+    }
++  for (regno = GP_REG_FIRST; regno <= GP_REG_LAST-1; regno++)
++    if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
++      {
++        mips_save_restore_reg (word_mode, regno, offset, fn);
++        offset -= UNITS_PER_WORD;
++      }
 +
 +  /* This loop must iterate over the same space as its companion in
 +     mips_compute_frame_info.  */
 +  offset = cfun->machine->frame.fp_sp_offset - sp_offset;
-+  for (regno = FP_REG_NUM-1; regno >= 0; regno--)
-+    if (BITSET_P (cfun->machine->frame.fmask, regno))
++  for (regno = FP_REG_FIRST; regno <= FP_REG_LAST; regno++)
++    if (BITSET_P (cfun->machine->frame.fmask, regno - FP_REG_FIRST))
 +      {
-+      mips_save_restore_reg (DFmode, regno + FP_REG_FIRST, offset, fn);
++      mips_save_restore_reg (DFmode, regno, offset, fn);
 +      offset -= GET_MODE_SIZE (DFmode);
 +      }
 +}
@@ -6773,18 +6271,6 @@ index 0000000..a4d85c4
 +      mem = src;
 +    }
 +
-+  if (regno == cfun->machine->global_pointer && !mips_must_initialize_gp_p ())
-+    {
-+      /* We don't yet know whether we'll need this instruction or not.
-+       Postpone the decision by emitting a ghost move.  This move
-+       is specifically not frame-related; only the split version is.  */
-+      if (TARGET_64BIT)
-+      emit_insn (gen_move_gpdi (dest, src));
-+      else
-+      emit_insn (gen_move_gpsi (dest, src));
-+      return;
-+    }
-+
 +  if (mips_direct_save_slot_move_p (regno, mem, mem == src))
 +    mips_emit_move (dest, src);
 +  else
@@ -6815,16 +6301,6 @@ index 0000000..a4d85c4
 +  fputs (":\n", asm_out_file);
 +}
 +
-+/* Implement TARGET_OUTPUT_FUNCTION_EPILOGUE.  */
-+
-+static void
-+mips_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED,
-+                             HOST_WIDE_INT size ATTRIBUTE_UNUSED)
-+{
-+  /* Reinstate the normal $gp.  */
-+  SET_REGNO (pic_offset_table_rtx, GLOBAL_POINTER_REGNUM);
-+}
-+
 +/* Save register REG to MEM.  Make the instruction frame-related.  */
 +
 +static void
@@ -6833,45 +6309,6 @@ index 0000000..a4d85c4
 +  mips_emit_save_slot_move (mem, reg, MIPS_PROLOGUE_TEMP (GET_MODE (reg)));
 +}
 +
-+/* The __gnu_local_gp symbol.  */
-+
-+static GTY(()) rtx mips_gnu_local_gp;
-+
-+/* If we're generating n32 or n64 abicalls, emit instructions
-+   to set up the global pointer.  */
-+
-+static void
-+mips_emit_loadgp (void)
-+{
-+  rtx addr, offset, incoming_address, pic_reg;
-+
-+  pic_reg = pic_offset_table_rtx;
-+  switch (mips_current_loadgp_style ())
-+    {
-+    case LOADGP_ABSOLUTE:
-+      if (mips_gnu_local_gp == NULL)
-+      {
-+        mips_gnu_local_gp = gen_rtx_SYMBOL_REF (Pmode, "__gnu_local_gp");
-+        SYMBOL_REF_FLAGS (mips_gnu_local_gp) |= SYMBOL_FLAG_LOCAL;
-+      }
-+      emit_insn (Pmode == SImode
-+               ? gen_loadgp_absolute_si (pic_reg, mips_gnu_local_gp)
-+               : gen_loadgp_absolute_di (pic_reg, mips_gnu_local_gp));
-+      break;
-+
-+    case LOADGP_NEWABI:
-+      addr = XEXP (DECL_RTL (current_function_decl), 0);
-+      offset = mips_unspec_address (addr, SYMBOL_GOTOFF_LOADGP);
-+      incoming_address = gen_rtx_REG (Pmode, PIC_FUNCTION_ADDR_REGNUM);
-+      emit_insn (Pmode == SImode
-+               ? gen_loadgp_newabi_si (pic_reg, offset, incoming_address)
-+               : gen_loadgp_newabi_di (pic_reg, offset, incoming_address));
-+      break;
-+
-+    default:
-+      return;
-+    }
-+}
 +
 +/* Expand the "prologue" pattern.  */
 +
@@ -6882,17 +6319,6 @@ index 0000000..a4d85c4
 +  HOST_WIDE_INT size;
 +  rtx insn;
 +
-+  if (cfun->machine->global_pointer != INVALID_REGNUM)
-+    {
-+      /* Check whether an insn uses pic_offset_table_rtx, either explicitly
-+       or implicitly.  If so, we can commit to using a global pointer
-+       straight away, otherwise we need to defer the decision.  */
-+      if (mips_cfun_has_flexible_gp_ref_p ())
-+      cfun->machine->must_initialize_gp_p = true;
-+
-+      SET_REGNO (pic_offset_table_rtx, cfun->machine->global_pointer);
-+    }
-+
 +  frame = &cfun->machine->frame;
 +  size = frame->total_size;
 +
@@ -6943,8 +6369,6 @@ index 0000000..a4d85c4
 +                        plus_constant (stack_pointer_rtx, -size)));
 +      }
 +    }
-+
-+  mips_emit_loadgp ();
 +}
 +\f
 +/* Emit instructions to restore register REG from slot MEM.  */
@@ -6952,7 +6376,13 @@ index 0000000..a4d85c4
 +static void
 +mips_restore_reg (rtx reg, rtx mem)
 +{
-+  mips_emit_save_slot_move (reg, mem, MIPS_EPILOGUE_TEMP (GET_MODE (reg)));
++  mips_emit_save_slot_move (reg, mem, MIPS_EPILOGUE_TEMP (GET_MODE (reg), false));
++}
++
++static void
++mips_restore_reg_sibcall (rtx reg, rtx mem)
++{
++  mips_emit_save_slot_move (reg, mem, MIPS_EPILOGUE_TEMP (GET_MODE (reg), true));
 +}
 +
 +/* Expand an "epilogue" or "sibcall_epilogue" pattern; SIBCALL_P
@@ -6990,8 +6420,8 @@ index 0000000..a4d85c4
 +      rtx adjust = GEN_INT (-frame->hard_frame_pointer_offset);
 +      if (!SMALL_INT (adjust))
 +      {
-+        mips_emit_move (MIPS_EPILOGUE_TEMP (Pmode), adjust);
-+        adjust = MIPS_EPILOGUE_TEMP (Pmode);
++        mips_emit_move (MIPS_EPILOGUE_TEMP (Pmode, sibcall_p), adjust);
++        adjust = MIPS_EPILOGUE_TEMP (Pmode, sibcall_p);
 +      }
 +
 +      emit_insn (gen_add3_insn (stack_pointer_rtx, hard_frame_pointer_rtx, adjust));
@@ -7012,15 +6442,16 @@ index 0000000..a4d85c4
 +      rtx adjust = GEN_INT (step1);
 +      if (!SMALL_OPERAND (step1))
 +      {
-+        mips_emit_move (MIPS_EPILOGUE_TEMP (Pmode), adjust);
-+        adjust = MIPS_EPILOGUE_TEMP (Pmode);
++        mips_emit_move (MIPS_EPILOGUE_TEMP (Pmode, sibcall_p), adjust);
++        adjust = MIPS_EPILOGUE_TEMP (Pmode, sibcall_p);
 +      }
 +
 +      emit_insn (gen_add3_insn (stack_pointer_rtx, stack_pointer_rtx, adjust));
 +    }
 +
 +  /* Restore the registers.  */
-+  mips_for_each_saved_gpr_and_fpr (frame->total_size - step2, mips_restore_reg);
++  mips_for_each_saved_gpr_and_fpr (frame->total_size - step2, 
++    sibcall_p ? mips_restore_reg_sibcall : mips_restore_reg);
 +
 +  /* Deallocate the final bit of the frame.  */
 +  if (step2 > 0)
@@ -8076,17 +7507,6 @@ index 0000000..a4d85c4
 +  fnaddr = XEXP (DECL_RTL (function), 0);
 +  use_sibcall_p = const_call_insn_operand (fnaddr, Pmode);
 +
-+  /* Determine if we need to load FNADDR from the GOT.  */
-+  if (!use_sibcall_p && mips_classify_symbol (fnaddr) == SYMBOL_GOT_DISP)
-+    {
-+      cfun->machine->global_pointer = GLOBAL_POINTER_REGNUM - GP_REG_FIRST;
-+      cfun->machine->must_initialize_gp_p = true;
-+      SET_REGNO (pic_offset_table_rtx, cfun->machine->global_pointer);
-+
-+      /* Set up the global pointer for n32 or n64 abicalls.  */
-+      mips_emit_loadgp ();
-+    }
-+
 +  /* We need two temporary registers in some cases.  */
 +  temp1 = gen_rtx_REG (Pmode, 2);
 +  temp2 = gen_rtx_REG (Pmode, 3);
@@ -8134,9 +7554,7 @@ index 0000000..a4d85c4
 +    }
 +  else
 +    {
-+      if (TARGET_ABICALLS)
-+      temp1 = gen_rtx_REG (Pmode, PIC_FUNCTION_ADDR_REGNUM);
-+      mips_load_call_address (MIPS_CALL_SIBCALL, temp1, fnaddr);
++      mips_emit_move(temp1, fnaddr);
 +      emit_jump_insn (gen_indirect_jump (temp1));
 +    }
 +
@@ -8199,15 +7617,6 @@ index 0000000..a4d85c4
 +{
 +  switch (code)
 +    {
-+    case OPT_mabi_:
-+      if (strcmp (arg, "32") == 0)
-+      mips_abi = ABI_32;
-+      else if (strcmp (arg, "64") == 0)
-+      mips_abi = ABI_64;
-+      else
-+      return false;
-+      return true;
-+
 +    case OPT_mtune_:
 +      return mips_parse_cpu (arg) != 0;
 +
@@ -8337,8 +7746,8 @@ index 0000000..a4d85c4
 +      call_really_used_regs[regno] = 1;
 +    }
 +
-+    call_used_regs[GP_REG_FIRST + LINK_REG] = 1;
-+    call_really_used_regs[GP_REG_FIRST + LINK_REG] = 1;
++    call_used_regs[RETURN_ADDR_REGNUM] = 1;
++    call_really_used_regs[RETURN_ADDR_REGNUM] = 1;
 +
 +    for (regno = CALLEE_SAVED_FP_REG_FIRST;
 +         regno <= CALLEE_SAVED_FP_REG_LAST; regno++)
@@ -8358,8 +7767,8 @@ index 0000000..a4d85c4
 +
 +    call_used_regs[GP_REG_FIRST + 28] = 1;
 +
-+    call_used_regs[GP_REG_FIRST + LINK_REG] = 0;
-+    call_really_used_regs[GP_REG_FIRST + LINK_REG] = 0;
++    call_used_regs[RETURN_ADDR_REGNUM] = 0;
++    call_really_used_regs[RETURN_ADDR_REGNUM] = 0;
 +
 +    for (regno = CALLEE_SAVED_FP_REG_FIRST;
 +         regno <= CALLEE_SAVED_FP_REG_LAST; regno++)
@@ -8420,7 +7829,7 @@ index 0000000..a4d85c4
 +{
 +  rtx addr, end_addr, mem;
 +  rtx trampoline[8];
-+  unsigned int i, j, gp;
++  unsigned int i, j;
 +  HOST_WIDE_INT static_chain_offset, target_function_offset;
 +
 +  /* Work out the offsets of the pointers from the start of the
@@ -8435,24 +7844,19 @@ index 0000000..a4d85c4
 +#define OP(X) gen_int_mode (X, SImode)
 +#define MATCH_LREG ((Pmode) == DImode ? MATCH_LD : MATCH_LW)
 +
-+  /* We want:
-+
-+        rdnpc   t6
-+     1: l[wd]   t7, target_function_offset - 4(t6)
-+      l[wd]   $static_chain, static_chain_offset - 4(t6)
-+      jr      t7
-+
-+     where 4 is the offset of "1:" from the start of the code block.  */
-+
++  /* auipc   v0, 0x0
++     l[wd]   v1, target_function_offset(v0)
++     l[wd]   $static_chain, static_chain_offset(v0)
++     jr      v1
++  */
 +  i = 0;
-+  gp = GLOBAL_POINTER_REGNUM - GP_REG_FIRST;
 +
-+  trampoline[i++] = OP (RISCV_ITYPE (RDNPC, gp, 0, 0));
-+  trampoline[i++] = OP (RISCV_ITYPE (LREG, PIC_FUNCTION_ADDR_REGNUM,
-+                                 gp, target_function_offset - 4));
++  trampoline[i++] = OP (RISCV_LTYPE (AUIPC, STATIC_CHAIN_REGNUM, 0));
++  trampoline[i++] = OP (RISCV_ITYPE (LREG, MIPS_PROLOGUE_TEMP_REGNUM,
++                        STATIC_CHAIN_REGNUM, target_function_offset));
 +  trampoline[i++] = OP (RISCV_ITYPE (LREG, STATIC_CHAIN_REGNUM,
-+                                 gp, static_chain_offset - 4));
-+  trampoline[i++] = OP (RISCV_ITYPE (JALR_J, 0, PIC_FUNCTION_ADDR_REGNUM, 0));
++                        STATIC_CHAIN_REGNUM, static_chain_offset));
++  trampoline[i++] = OP (RISCV_ITYPE (JALR_J, 0, MIPS_PROLOGUE_TEMP_REGNUM, 0));
 +
 +  gcc_assert (i * 4 == TRAMPOLINE_CODE_SIZE);
 +
@@ -8554,6 +7958,43 @@ index 0000000..a4d85c4
 +  gcc_unreachable();
 +}
 +
++/* Implement TARGET_ASM_FUNCTION_RODATA_SECTION.
++
++   The complication here is that, with the combination TARGET_ABICALLS
++   && !TARGET_ABSOLUTE_ABICALLS && !TARGET_GPWORD, jump tables will use
++   absolute addresses, and should therefore not be included in the
++   read-only part of a DSO.  Handle such cases by selecting a normal
++   data section instead of a read-only one.  The logic apes that in
++   default_function_rodata_section.  */
++
++static section *
++mips_function_rodata_section (tree decl)
++{
++  if (!TARGET_ABICALLS)
++    return default_function_rodata_section (decl);
++
++  if (decl && DECL_SECTION_NAME (decl))
++    {
++      const char *name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
++      if (DECL_ONE_ONLY (decl) && strncmp (name, ".gnu.linkonce.t.", 16) == 0)
++      {
++        char *rname = ASTRDUP (name);
++        rname[14] = 'd';
++        return get_section (rname, SECTION_LINKONCE | SECTION_WRITE, decl);
++      }
++      else if (flag_function_sections
++             && flag_data_sections
++             && strncmp (name, ".text.", 6) == 0)
++      {
++        char *rname = ASTRDUP (name);
++        memcpy (rname + 1, "data", 4);
++        return get_section (rname, SECTION_WRITE, decl);
++      }
++    }
++  return data_section;
++}
++
++
 +\f
 +/* Initialize the GCC target structure.  */
 +#undef TARGET_ASM_ALIGNED_HI_OP
@@ -8573,8 +8014,8 @@ index 0000000..a4d85c4
 +
 +#undef TARGET_ASM_FUNCTION_PROLOGUE
 +#define TARGET_ASM_FUNCTION_PROLOGUE mips_output_function_prologue
-+#undef TARGET_ASM_FUNCTION_EPILOGUE
-+#define TARGET_ASM_FUNCTION_EPILOGUE mips_output_function_epilogue
++#undef TARGET_ASM_FUNCTION_RODATA_SECTION
++#define TARGET_ASM_FUNCTION_RODATA_SECTION mips_function_rodata_section
 +
 +#undef TARGET_SCHED_ADJUST_COST
 +#define TARGET_SCHED_ADJUST_COST mips_adjust_cost
@@ -8585,6 +8026,7 @@ index 0000000..a4d85c4
 +#define TARGET_DEFAULT_TARGET_FLAGS           \
 +  (TARGET_DEFAULT                             \
 +   | TARGET_CPU_DEFAULT                               \
++   | (TARGET_64BIT_DEFAULT ? 0 : MASK_32BIT)  \
 +   | TARGET_ENDIAN_DEFAULT)
 +#undef TARGET_HANDLE_OPTION
 +#define TARGET_HANDLE_OPTION mips_handle_option
@@ -8612,8 +8054,6 @@ index 0000000..a4d85c4
 +#undef  TARGET_PREFERRED_RELOAD_CLASS
 +#define TARGET_PREFERRED_RELOAD_CLASS mips_preferred_reload_class
 +
-+#undef TARGET_ASM_FILE_START
-+#define TARGET_ASM_FILE_START mips_file_start
 +#undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
 +#define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
 +
@@ -8735,10 +8175,10 @@ index 0000000..a4d85c4
 +#include "gt-riscv.h"
 diff --git a/gcc-4.6.1/gcc/config/riscv/riscv.h b/gcc-4.6.1/gcc/config/riscv/riscv.h
 new file mode 100644
-index 0000000..2c52f88
+index 0000000..e20faad
 --- /dev/null
 +++ gcc-4.6.1/gcc/config/riscv/riscv.h
-@@ -0,0 +1,1721 @@
+@@ -0,0 +1,1666 @@
 +/* Definitions of target machine for GNU compiler.  MIPS version.
 +   Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998
 +   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011
@@ -8778,7 +8218,7 @@ index 0000000..2c52f88
 +/* Which ABI to use. */
 +
 +#define ABI_32  1
-+#define ABI_64  2
++#define ABI_64  3
 +
 +/* Information about one recognized processor.  Defined here for the
 +   benefit of TARGET_CPU_CPP_BUILTINS.  */
@@ -8807,9 +8247,6 @@ index 0000000..2c52f88
 +/* True if we need to use a global offset table to access some symbols.  */
 +#define TARGET_USE_GOT TARGET_ABICALLS
 +
-+/* True if .gpword or .gpdword should be used for switch tables. */
-+#define TARGET_GPWORD (TARGET_ABICALLS && flag_pic)
-+
 +/* True if the output must have a writable .eh_frame.
 +   See ASM_PREFERRED_EH_DATA_FORMAT for details.  */
 +#ifdef HAVE_LD_PERSONALITY_RELAXATION
@@ -8837,21 +8274,16 @@ index 0000000..2c52f88
 +      builtin_define ("_riscv");                                      \
 +                                                                      \
 +      if (TARGET_64BIT)                                                       \
-+      builtin_define ("__riscv64");                                   \
++      {                                                               \
++        builtin_define ("__riscv64");                                 \
++        builtin_define ("_RISCV_SIM=_ABI64");                         \
++      }                                                               \
++      else                                                            \
++      builtin_define ("_RISCV_SIM=_ABI32");                           \
 +                                                                      \
 +      builtin_define ("_ABI32=1");                                    \
-+      builtin_define ("_ABI64=2");                                    \
-+                                                                      \
-+      switch (mips_abi)                                                       \
-+      {                                                               \
-+      case ABI_32:                                                    \
-+        builtin_define ("_RISCV_SIM=_ABI32");                         \
-+        break;                                                        \
++      builtin_define ("_ABI64=3");                                    \
 +                                                                      \
-+      case ABI_64:                                                    \
-+        builtin_define ("_RISCV_SIM=_ABI64");                         \
-+        break;                                                        \
-+      }                                                               \
 +                                                                      \
 +      builtin_define_with_int_value ("_RISCV_SZINT", INT_TYPE_SIZE);  \
 +      builtin_define_with_int_value ("_RISCV_SZLONG", LONG_TYPE_SIZE);        \
@@ -8875,11 +8307,6 @@ index 0000000..2c52f88
 +        builtin_define_std ("RISCVEL");                               \
 +        builtin_define ("_RISCVEL");                                  \
 +      }                                                               \
-+                                                                        \
-+      /* Whether calls should go through $25.  The separate __PIC__   \
-+       macro indicates whether abicalls code might use a GOT.  */     \
-+      if (TARGET_ABICALLS)                                            \
-+      builtin_define ("__mips_abicalls");                             \
 +                                                                      \
 +      /* Macros dependent on the C dialect.  */                               \
 +      if (preprocessing_asm_p ())                                     \
@@ -8927,8 +8354,6 @@ index 0000000..2c52f88
 +#define MIPS_CPU_STRING_DEFAULT "rocket"
 +#endif
 +
-+#define TARGET_LIBGCC_SDATA_SECTION ".sdata"
-+
 +#ifndef MULTILIB_ENDIAN_DEFAULT
 +#if TARGET_ENDIAN_DEFAULT == 0
 +#define MULTILIB_ENDIAN_DEFAULT "EL"
@@ -8937,23 +8362,23 @@ index 0000000..2c52f88
 +#endif
 +#endif
 +
-+#ifndef MIPS_ABI_DEFAULT
-+#define MIPS_ABI_DEFAULT ABI_64
-+#endif
-+
-+#if MIPS_ABI_DEFAULT == ABI_32
-+#define MULTILIB_ABI_DEFAULT "mabi=32"
-+#define MULTILIB_ISA_DEFAULT "rv32"
++#ifndef TARGET_64BIT_DEFAULT
++#define TARGET_64BIT_DEFAULT 1
 +#endif
 +
-+#if MIPS_ABI_DEFAULT == ABI_64
-+#define MULTILIB_ABI_DEFAULT "mabi=64"
-+#define MULTILIB_ISA_DEFAULT "rv64"
++#if TARGET_64BIT_DEFAULT
++# define MULTILIB_ARCH_DEFAULT "m64"
++# define OPT_ARCH64 "!m32"
++# define OPT_ARCH32 "m32"
++#else
++# define MULTILIB_ARCH_DEFAULT "m32"
++# define OPT_ARCH64 "m64"
++# define OPT_ARCH32 "!m64"
 +#endif
 +
 +#ifndef MULTILIB_DEFAULTS
 +#define MULTILIB_DEFAULTS \
-+    { MULTILIB_ENDIAN_DEFAULT, MULTILIB_ISA_DEFAULT, MULTILIB_ABI_DEFAULT }
++    { MULTILIB_ENDIAN_DEFAULT, MULTILIB_ARCH_DEFAULT }
 +#endif
 +
 +/* We must pass -EL to the linker by default for little endian embedded
@@ -8979,24 +8404,6 @@ index 0000000..2c52f88
 +#define MIPS_ARCH_OPTION_SPEC \
 +  MIPS_ISA_LEVEL_OPTION_SPEC "|march=*"
 +
-+/* A spec that infers a -mips argument from an -march argument,
-+   or injects the default if no architecture is specified.  */
-+
-+#define MIPS_ISA_LEVEL_SPEC \
-+  "%{" MIPS_ISA_LEVEL_OPTION_SPEC ":;: \
-+     %{march=mips1|march=r2000|march=r3000|march=r3900:-mips1} \
-+     %{march=mips2|march=r6000:-mips2} \
-+     %{march=mips3|march=r4*|march=vr4*|march=orion|march=loongson2*:-mips3} \
-+     %{march=mips4|march=r8000|march=vr5*|march=rm7000|march=rm9000 \
-+       |march=r10000|march=r12000|march=r14000|march=r16000:-mips4} \
-+     %{march=mips32|march=4kc|march=4km|march=4kp|march=4ksc:-mips32} \
-+     %{march=mips32r2|march=m4k|march=4ke*|march=4ksd|march=24k* \
-+       |march=34k*|march=74k*|march=1004k*: -mips32r2} \
-+     %{march=mips64|march=5k*|march=20k*|march=sb1*|march=sr71000 \
-+       |march=xlr|march=loongson3a: -mips64} \
-+     %{march=mips64r2|march=octeon: -mips64r2} \
-+     %{!march=*: -" MULTILIB_ISA_DEFAULT "}}"
-+
 +/* A spec that infers a -mhard-float or -msoft-float setting from an
 +   -march argument.  Note that soft-float and hard-float code are not
 +   link-compatible.  */
@@ -9008,33 +8415,26 @@ index 0000000..2c52f88
 +     |march=octeon|march=xlr: -msoft-float;             \
 +     march=*: -mhard-float}"
 +
-+#define OPT_ARCH64 "mabi=32:;"
-+#define OPT_ARCH32 "mabi=32"
-+
 +/* Support for a compile-time default CPU, et cetera.  The rules are:
 +   --with-arch is ignored if -march is specified or a -mips is specified
 +     (other than -mips16); likewise --with-arch-32 and --with-arch-64.
 +   --with-tune is ignored if -mtune is specified; likewise
 +     --with-tune-32 and --with-tune-64.
-+   --with-abi is ignored if -mabi is specified.
 +   --with-float is ignored if -mhard-float or -msoft-float are
 +     specified.
 +   --with-divide is ignored if -mdivide-traps or -mdivide-breaks are
 +     specified. */
 +#define OPTION_DEFAULT_SPECS \
 +  {"arch", "%{" MIPS_ARCH_OPTION_SPEC ":;: -march=%(VALUE)}" }, \
-+  {"arch_32", "%{" OPT_ARCH32 ":%{" MIPS_ARCH_OPTION_SPEC ":;: -march=%(VALUE)}}" }, \
-+  {"arch_64", "%{" OPT_ARCH64 ":%{" MIPS_ARCH_OPTION_SPEC ":;: -march=%(VALUE)}}" }, \
++  {"arch_32", "%{" OPT_ARCH32 ":%{m32}}" }, \
++  {"arch_64", "%{" OPT_ARCH64 ":%{m64}}" }, \
 +  {"tune", "%{!mtune=*:-mtune=%(VALUE)}" }, \
 +  {"tune_32", "%{" OPT_ARCH32 ":%{!mtune=*:-mtune=%(VALUE)}}" }, \
 +  {"tune_64", "%{" OPT_ARCH64 ":%{!mtune=*:-mtune=%(VALUE)}}" }, \
-+  {"abi", "%{!mabi=*:-mabi=%(VALUE)}" }, \
 +  {"float", "%{!msoft-float:%{!mhard-float:-m%(VALUE)-float}}" }, \
 +
 +#define DRIVER_SELF_SPECS ""
 +
-+#define TARGET_64BIT  (mips_abi == ABI_64)
-+
 +#ifdef IN_LIBGCC2
 +#undef TARGET_64BIT
 +/* Make this compile time constant for libgcc2 */
@@ -9074,12 +8474,10 @@ index 0000000..2c52f88
 +#undef ASM_SPEC
 +#define ASM_SPEC "\
 +%{G*} %(endian_spec) \
-+%(subtarget_asm_optimizing_spec) \
 +%(subtarget_asm_debugging_spec) \
-+%{mabi=*} %{!mabi=*: %(asm_abi_default_spec)} \
++%{m32} %{m64} %{!m32:%{!m64: %(asm_abi_default_spec)}} \
++%{fPIC|fpic|fPIE|fpie:-fpic} \
 +%{march=*} \
-+%{mshared} %{mno-shared} \
-+%{mtune=*} \
 +%(subtarget_asm_spec)"
 +
 +/* Extra switches sometimes passed to the linker.  */
@@ -9088,8 +8486,8 @@ index 0000000..2c52f88
 +#define LINK_SPEC "\
 +%{!T:-dT riscv.ld} \
 +%(endian_spec) \
-+%{mabi=64:-melf64%{EB:b}%{!EB:l}riscv} \
-+%{mabi=32:-melf32%{EB:b}%{!EB:l}riscv} \
++%{m64:-melf64%{EB:b}%{!EB:l}riscv} \
++%{m32:-melf32%{EB:b}%{!EB:l}riscv} \
 +%{G*} %{mips1} %{mips2} %{mips3} %{mips4} %{mips32*} %{mips64*} \
 +%{shared}"
 +#endif  /* LINK_SPEC defined */
@@ -9135,7 +8533,7 @@ index 0000000..2c52f88
 +  { "subtarget_cpp_spec", SUBTARGET_CPP_SPEC },                               \
 +  { "subtarget_asm_debugging_spec", SUBTARGET_ASM_DEBUGGING_SPEC },   \
 +  { "subtarget_asm_spec", SUBTARGET_ASM_SPEC },                               \
-+  { "asm_abi_default_spec", "-" MULTILIB_ABI_DEFAULT },                       \
++  { "asm_abi_default_spec", "-" MULTILIB_ARCH_DEFAULT },              \
 +  { "endian_spec", ENDIAN_SPEC },                                     \
 +  SUBTARGET_EXTRA_SPECS
 +
@@ -9183,7 +8581,7 @@ index 0000000..2c52f88
 +#define EH_RETURN_DATA_REGNO(N) \
 +  ((N) < 4 ? (N) + GP_ARG_FIRST : INVALID_REGNUM)
 +
-+#define EH_RETURN_STACKADJ_RTX  gen_rtx_REG (Pmode, GP_REG_FIRST + 3)
++#define EH_RETURN_STACKADJ_RTX  gen_rtx_REG (Pmode, GP_ARG_FIRST + 4)
 +
 +/* Offsets recorded in opcodes are a multiple of this alignment factor.
 +   The default for this in 64-bit mode is 8, which causes problems with
@@ -9423,8 +8821,8 @@ index 0000000..2c52f88
 +
 +#define FIXED_REGISTERS                                                       \
 +{ /* General registers.  */                                             \
-+  1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                     \
-+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1,                     \
++  1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,                     \
++  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                     \
 +  /* Floating-point registers.  */                                      \
 +  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                     \
 +  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                     \
@@ -9452,11 +8850,11 @@ index 0000000..2c52f88
 +
 +#define CALL_USED_REGISTERS                                           \
 +{ /* General registers.  */                                             \
-+  1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,                     \
-+  1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1,                     \
++  1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,                     \
++  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,                     \
 +  /* Floating-point registers.  */                                      \
++  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                     \
 +  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,                     \
-+  1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,                     \
 +  /* Vector General registers.  */                                      \
 +  1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,                     \
 +  1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,                     \
@@ -9469,11 +8867,11 @@ index 0000000..2c52f88
 +
 +#define CALL_REALLY_USED_REGISTERS                                      \
 +{ /* General registers.  */                                             \
-+  1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,                       \
-+  1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,                       \
++  1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,                     \
++  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,                     \
 +  /* Floating-point registers.  */                                      \
++  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                     \
 +  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,                     \
-+  1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,                     \
 +  /* Vector General registers.  */                                      \
 +  1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,                       \
 +  1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,                       \
@@ -9498,11 +8896,11 @@ index 0000000..2c52f88
 +#define FP_REG_NUM   (FP_REG_LAST - FP_REG_FIRST + 1)
 +#define FP_DBX_FIRST ((write_symbols == DBX_DEBUG) ? 38 : 32)
 +
-+#define CALLEE_SAVED_GP_REG_FIRST 20
-+#define CALLEE_SAVED_GP_REG_LAST (CALLEE_SAVED_GP_REG_FIRST + 10 - 1)
++#define CALLEE_SAVED_GP_REG_FIRST (GP_REG_FIRST + 2)
++#define CALLEE_SAVED_GP_REG_LAST (CALLEE_SAVED_GP_REG_FIRST + 12 - 1)
 +
-+#define CALLEE_SAVED_FP_REG_FIRST 52
-+#define CALLEE_SAVED_FP_REG_LAST (CALLEE_SAVED_FP_REG_FIRST + 12 - 1)
++#define CALLEE_SAVED_FP_REG_FIRST (FP_REG_FIRST + 0)
++#define CALLEE_SAVED_FP_REG_LAST (CALLEE_SAVED_FP_REG_FIRST + 16 - 1)
 +
 +#define VEC_GP_REG_FIRST 64
 +#define VEC_GP_REG_LAST  95
@@ -9544,12 +8942,10 @@ index 0000000..2c52f88
 +#define MODES_TIEABLE_P mips_modes_tieable_p
 +
 +/* Register to use for pushing function arguments.  */
-+#define STACK_POINTER_REGNUM (GP_REG_FIRST + 30)
-+#define HARD_FRAME_POINTER_REGNUM (GP_REG_FIRST + 29)
++#define STACK_POINTER_REGNUM (GP_REG_FIRST + 14)
++#define HARD_FRAME_POINTER_REGNUM (GP_REG_FIRST + 3)
 +
-+#define THREAD_POINTER_REGNUM (GP_REG_FIRST + 31)
-+
-+#define LINK_REGNUM (GP_REG_FIRST + 1) /* Return address, $ra */
++#define THREAD_POINTER_REGNUM (GP_REG_FIRST + 15)
 +
 +/* These two registers don't really exist: they get eliminated to either
 +   the stack or hard frame pointer.  */
@@ -9560,30 +8956,22 @@ index 0000000..2c52f88
 +#define HARD_FRAME_POINTER_IS_ARG_POINTER 0
 +
 +/* Register in which static-chain is passed to a function.  */
-+#define STATIC_CHAIN_REGNUM (GP_REG_FIRST + 15)
-+
-+/* Registers used as temporaries in prologue/epilogue code:
++#define STATIC_CHAIN_REGNUM GP_RETURN
 +
-+   - The prologue can use MIPS_PROLOGUE_TEMP as a general temporary
-+     register.
-+
-+   - The epilogue can use MIPS_EPILOGUE_TEMP as a general temporary
-+     register.
++/* Registers used as temporaries in prologue/epilogue code.
 +
 +   The prologue registers mustn't conflict with any
 +   incoming arguments, the static chain pointer, or the frame pointer.
 +   The epilogue temporary mustn't conflict with the return registers,
-+   the PIC call register ($25), the frame pointer, the EH stack adjustment,
-+   or the EH data registers.
-+
-+   If we're generating interrupt handlers, we use K0 as a temporary register
-+   in prologue/epilogue code.  */
++   the frame pointer, the EH stack adjustment, or the EH data registers. */
 +
-+#define MIPS_PROLOGUE_TEMP_REGNUM (GP_REG_FIRST + 3)
-+#define MIPS_EPILOGUE_TEMP_REGNUM (GP_REG_FIRST + 8)
++#define MIPS_PROLOGUE_TEMP_REGNUM (GP_RETURN + 1)
++#define MIPS_EPILOGUE_TEMP_REGNUM(SIBCALL_P) \
++  ((SIBCALL_P) ? MIPS_PROLOGUE_TEMP_REGNUM : (GP_ARG_FIRST + 5))
 +
 +#define MIPS_PROLOGUE_TEMP(MODE) gen_rtx_REG (MODE, MIPS_PROLOGUE_TEMP_REGNUM)
-+#define MIPS_EPILOGUE_TEMP(MODE) gen_rtx_REG (MODE, MIPS_EPILOGUE_TEMP_REGNUM)
++#define MIPS_EPILOGUE_TEMP(MODE, SIBCALL_P) \
++  gen_rtx_REG (MODE, MIPS_EPILOGUE_TEMP_REGNUM (SIBCALL_P))
 +
 +#define FUNCTION_PROFILER(STREAM, LABELNO)    \
 +{                                             \
@@ -9594,15 +8982,6 @@ index 0000000..2c52f88
 +   function address than to call an address kept in a register.  */
 +#define NO_FUNCTION_CSE 1
 +
-+/* The ABI-defined global pointer.  Sometimes we use a different
-+   register in leaf functions: see PIC_OFFSET_TABLE_REGNUM.  */
-+#define GLOBAL_POINTER_REGNUM (GP_REG_FIRST + 18)
-+#define GLOBAL_POINTER_REGNUM_NONLEAF (GP_REG_FIRST + 28)
-+
-+#define PIC_OFFSET_TABLE_REGNUM GLOBAL_POINTER_REGNUM
-+
-+#define PIC_FUNCTION_ADDR_REGNUM (GP_REG_FIRST + 19)
-+\f
 +/* Define the classes of registers for register constraints in the
 +   machine description.  Also define ranges of constants.
 +
@@ -9626,9 +9005,7 @@ index 0000000..2c52f88
 +enum reg_class
 +{
 +  NO_REGS,                    /* no registers in set */
-+  PIC_FN_ADDR_REG,            /* SVR4 PIC function address register */
-+  V1_REG,                     /* Register $v1 ($3) used for TLS access.  */
-+  LEA_REGS,                   /* Every GPR except $25 */
++  V1_REG,                     /* register used by indirect sibcalls */
 +  GR_REGS,                    /* integer registers */
 +  FP_REGS,                    /* floating point registers */
 +  VEC_GR_REGS,                        /* vector integer registers */
@@ -9649,9 +9026,7 @@ index 0000000..2c52f88
 +#define REG_CLASS_NAMES                                                       \
 +{                                                                     \
 +  "NO_REGS",                                                          \
-+  "PIC_FN_ADDR_REG",                                                  \
 +  "V1_REG",                                                           \
-+  "LEA_REGS",                                                         \
 +  "GR_REGS",                                                          \
 +  "FP_REGS",                                                          \
 +  "VEC_GR_REGS",                                                      \
@@ -9674,9 +9049,7 @@ index 0000000..2c52f88
 +#define REG_CLASS_CONTENTS                                                                    \
 +{                                                                                             \
 +  { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },     /* NO_REGS */           \
-+  { 0x00080000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },     /* PIC_FN_ADDR_REG */   \
-+  { 0x00000008, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },     /* V1_REG */            \
-+  { 0xfff7ffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },     /* LEA_REGS */          \
++  { 0x00020000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },     /* V1_REG */            \
 +  { 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },     /* GR_REGS */           \
 +  { 0x00000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000 },     /* FP_REGS */           \
 +  { 0x00000000, 0x00000000, 0xffffffff, 0x00000000, 0x00000000 },     /* VEC_GR_REGS */       \
@@ -9712,27 +9085,15 @@ index 0000000..2c52f88
 +#define REG_ALLOC_ORDER                                                       \
 +{ \
 +  /* Call-clobbered GPRs.  */                                         \
-+  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,              \
-+  16, 17, 18, 19, 1,                                                  \
++  16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 1,  \
 +  /* Call-saved GPRs.  */                                             \
-+  20, 21, 22, 23, 24, 25, 26, 27, 29,                                 \
-+  /* The global pointer.  This is call-clobbered for o32 and o64      \
-+     abicalls, call-saved for n32 and n64 abicalls, and a program     \
-+     invariant otherwise.  Putting it between the call-clobbered      \
-+     and call-saved registers should cope with all eventualities.  */ \
-+  28,                                                                 \
++  2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,                             \
 +  /* GPRs that can never be exposed to the register allocator.  */    \
-+  0,  30, 31,                                                         \
++  0,  14, 15,                                                         \
 +  /* Call-clobbered FPRs.  */                                         \
-+  34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,     \
-+  50, 51, 32, 33,                                                     \
-+  /* FPRs that are usually call-saved.  The odd ones are actually     \
-+     call-clobbered for n32, but listing them ahead of the even               \
-+     registers might encourage the register allocator to fragment     \
-+     the available FPR pairs.  We need paired FPRs to store long      \
-+     doubles, so it isn't clear that using a different order          \
-+     for n32 would be a win.  */                                      \
-+  52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,                     \
++  48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,     \
++  /* Call-saved FPRs.  */                                             \
++  32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,     \
 +  /* Vector GPRs  */                                                  \
 +  64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,     \
 +  80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,     \
@@ -9826,16 +9187,16 @@ index 0000000..2c52f88
 +/* Symbolic macros for the registers used to return integer and floating
 +   point values.  */
 +
-+#define GP_RETURN (GP_REG_FIRST + 2)
-+#define FP_RETURN ((TARGET_SOFT_FLOAT) ? GP_RETURN : (FP_REG_FIRST + 2))
++#define GP_RETURN (GP_REG_FIRST + 16)
++#define FP_RETURN ((TARGET_SOFT_FLOAT) ? GP_RETURN : (FP_REG_FIRST + 16))
 +
-+#define MAX_ARGS_IN_REGISTERS 8
++#define MAX_ARGS_IN_REGISTERS 14
 +
 +/* Symbolic macros for the first/last argument registers.  */
 +
-+#define GP_ARG_FIRST (GP_REG_FIRST + 4)
++#define GP_ARG_FIRST (GP_REG_FIRST + 18)
 +#define GP_ARG_LAST  (GP_ARG_FIRST + MAX_ARGS_IN_REGISTERS - 1)
-+#define FP_ARG_FIRST (FP_REG_FIRST + 12)
++#define FP_ARG_FIRST (FP_REG_FIRST + 18)
 +#define FP_ARG_LAST  (FP_ARG_FIRST + MAX_ARGS_IN_REGISTERS - 1)
 +
 +#define LIBCALL_VALUE(MODE) \
@@ -9850,7 +9211,7 @@ index 0000000..2c52f88
 +
 +#define FUNCTION_VALUE_REGNO_P(N) ((N) == GP_RETURN || (N) == FP_RETURN \
 +  || (LONG_DOUBLE_TYPE_SIZE == 128 && FP_RETURN != GP_RETURN \
-+      && (N) == FP_RETURN + 2))
++      && (N) == FP_RETURN + 1))
 +
 +/* 1 if N is a possible register number for function argument passing.
 +   We have no FP argument registers when soft-float.  When FP registers
@@ -10113,38 +9474,68 @@ index 0000000..2c52f88
 +{                                                                     \
 +  { "zero",    0 + GP_REG_FIRST },                                    \
 +  { "ra",      1 + GP_REG_FIRST },                                    \
-+  { "v0",      2 + GP_REG_FIRST },                                    \
-+  { "v1",      3 + GP_REG_FIRST },                                    \
-+  { "a0",      4 + GP_REG_FIRST },                                    \
-+  { "a1",      5 + GP_REG_FIRST },                                    \
-+  { "a2",      6 + GP_REG_FIRST },                                    \
-+  { "a3",      7 + GP_REG_FIRST },                                    \
-+  { "a4",      8 + GP_REG_FIRST },                                    \
-+  { "a5",      9 + GP_REG_FIRST },                                    \
-+  { "a6",     10 + GP_REG_FIRST },                                    \
-+  { "a7",     11 + GP_REG_FIRST },                                    \
-+  { "t0",     12 + GP_REG_FIRST },                                    \
-+  { "t1",     13 + GP_REG_FIRST },                                    \
-+  { "t2",     14 + GP_REG_FIRST },                                    \
-+  { "t3",     15 + GP_REG_FIRST },                                    \
-+  { "t4",     16 + GP_REG_FIRST },                                    \
-+  { "t5",     17 + GP_REG_FIRST },                                    \
-+  { "t6",     18 + GP_REG_FIRST },                                    \
-+  { "t7",     19 + GP_REG_FIRST },                                    \
-+  { "s0",     20 + GP_REG_FIRST },                                    \
-+  { "s1",     21 + GP_REG_FIRST },                                    \
-+  { "s2",     22 + GP_REG_FIRST },                                    \
-+  { "s3",     23 + GP_REG_FIRST },                                    \
-+  { "s4",     24 + GP_REG_FIRST },                                    \
-+  { "s5",     25 + GP_REG_FIRST },                                    \
-+  { "s6",     26 + GP_REG_FIRST },                                    \
-+  { "s7",     27 + GP_REG_FIRST },                                    \
-+  { "gp",     28 + GP_REG_FIRST },                                    \
-+  { "s8",     28 + GP_REG_FIRST },                                    \
-+  { "fp",     29 + GP_REG_FIRST },                                    \
-+  { "s9",     29 + GP_REG_FIRST },                                    \
-+  { "sp",     30 + GP_REG_FIRST },                                    \
-+  { "tp",     31 + GP_REG_FIRST },                                    \
++  { "s0",      2 + GP_REG_FIRST },                                    \
++  { "s1",      3 + GP_REG_FIRST },                                    \
++  { "s2",      4 + GP_REG_FIRST },                                    \
++  { "s3",      5 + GP_REG_FIRST },                                    \
++  { "s4",      6 + GP_REG_FIRST },                                    \
++  { "s5",      7 + GP_REG_FIRST },                                    \
++  { "s6",      8 + GP_REG_FIRST },                                    \
++  { "s7",      9 + GP_REG_FIRST },                                    \
++  { "s8",     10 + GP_REG_FIRST },                                    \
++  { "s9",     11 + GP_REG_FIRST },                                    \
++  { "s10",    12 + GP_REG_FIRST },                                    \
++  { "s11",    13 + GP_REG_FIRST },                                    \
++  { "sp",     14 + GP_REG_FIRST },                                    \
++  { "tp",     15 + GP_REG_FIRST },                                    \
++  { "v0",     16 + GP_REG_FIRST },                                    \
++  { "v1",     17 + GP_REG_FIRST },                                    \
++  { "a0",     18 + GP_REG_FIRST },                                    \
++  { "a1",     19 + GP_REG_FIRST },                                    \
++  { "a2",     20 + GP_REG_FIRST },                                    \
++  { "a3",     21 + GP_REG_FIRST },                                    \
++  { "a4",     22 + GP_REG_FIRST },                                    \
++  { "a5",     23 + GP_REG_FIRST },                                    \
++  { "a6",     24 + GP_REG_FIRST },                                    \
++  { "a7",     25 + GP_REG_FIRST },                                    \
++  { "a8",     26 + GP_REG_FIRST },                                    \
++  { "a9",     27 + GP_REG_FIRST },                                    \
++  { "a10",    28 + GP_REG_FIRST },                                    \
++  { "a11",    29 + GP_REG_FIRST },                                    \
++  { "a12",    30 + GP_REG_FIRST },                                    \
++  { "a13",    31 + GP_REG_FIRST },                                    \
++  { "fs0",     0 + FP_REG_FIRST },                                    \
++  { "fs1",     1 + FP_REG_FIRST },                                    \
++  { "fs2",     2 + FP_REG_FIRST },                                    \
++  { "fs3",     3 + FP_REG_FIRST },                                    \
++  { "fs4",     4 + FP_REG_FIRST },                                    \
++  { "fs5",     5 + FP_REG_FIRST },                                    \
++  { "fs6",     6 + FP_REG_FIRST },                                    \
++  { "fs7",     7 + FP_REG_FIRST },                                    \
++  { "fs8",     8 + FP_REG_FIRST },                                    \
++  { "fs9",     9 + FP_REG_FIRST },                                    \
++  { "fs10",   10 + FP_REG_FIRST },                                    \
++  { "fs11",   11 + FP_REG_FIRST },                                    \
++  { "fs12",   12 + FP_REG_FIRST },                                    \
++  { "fs13",   13 + FP_REG_FIRST },                                    \
++  { "fs14",   14 + FP_REG_FIRST },                                    \
++  { "fs15",   15 + FP_REG_FIRST },                                    \
++  { "fv0",    16 + FP_REG_FIRST },                                    \
++  { "fv1",    17 + FP_REG_FIRST },                                    \
++  { "fa0",    18 + FP_REG_FIRST },                                    \
++  { "fa1",    19 + FP_REG_FIRST },                                    \
++  { "fa2",    20 + FP_REG_FIRST },                                    \
++  { "fa3",    21 + FP_REG_FIRST },                                    \
++  { "fa4",    22 + FP_REG_FIRST },                                    \
++  { "fa5",    23 + FP_REG_FIRST },                                    \
++  { "fa6",    24 + FP_REG_FIRST },                                    \
++  { "fa7",    25 + FP_REG_FIRST },                                    \
++  { "fa8",    26 + FP_REG_FIRST },                                    \
++  { "fa9",    27 + FP_REG_FIRST },                                    \
++  { "fa10",   28 + FP_REG_FIRST },                                    \
++  { "fa11",   29 + FP_REG_FIRST },                                    \
++  { "fa12",   30 + FP_REG_FIRST },                                    \
++  { "fa13",   31 + FP_REG_FIRST },                                    \
 +}
 +
 +/* This is meant to be redefined in the host dependent files.  It is a
@@ -10253,14 +9644,9 @@ index 0000000..2c52f88
 +
 +#define ASM_OUTPUT_ADDR_DIFF_ELT(STREAM, BODY, VALUE, REL)            \
 +do {                                                                  \
-+  if (TARGET_GPWORD)                                          \
-+    fprintf (STREAM, "\t%s\t%sL%d\n",                                 \
-+           ptr_mode == DImode ? ".gpdword" : ".gpword",               \
-+           LOCAL_LABEL_PREFIX, VALUE);                                \
-+  else                                                                        \
-+    fprintf (STREAM, "\t%s\t%sL%d\n",                                 \
-+           ptr_mode == DImode ? ".dword" : ".word",                   \
-+           LOCAL_LABEL_PREFIX, VALUE);                                \
++  fprintf (STREAM, "\t%s\t%sL%d\n",                                   \
++         ptr_mode == DImode ? ".dword" : ".word",                     \
++         LOCAL_LABEL_PREFIX, VALUE);                                  \
 +} while (0)
 +
 +/* This is how to output an assembler line
@@ -10427,7 +9813,6 @@ index 0000000..2c52f88
 +extern bool mips_split_p[];
 +extern enum processor mips_arch;        /* which cpu to codegen for */
 +extern enum processor mips_tune;        /* which cpu to schedule for */
-+extern int mips_abi;                  /* which ABI to use */
 +extern GTY(()) struct target_globals *mips16_globals;
 +#endif
 +
@@ -10462,10 +9847,10 @@ index 0000000..2c52f88
 +#define SWITCHABLE_TARGET 1
 diff --git a/gcc-4.6.1/gcc/config/riscv/riscv.md b/gcc-4.6.1/gcc/config/riscv/riscv.md
 new file mode 100644
-index 0000000..bc2a772
+index 0000000..6277f57
 --- /dev/null
 +++ gcc-4.6.1/gcc/config/riscv/riscv.md
-@@ -0,0 +1,3045 @@
+@@ -0,0 +1,2888 @@
 +;;  Mips.md        Machine Description for MIPS based processors
 +;;  Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
 +;;  1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
@@ -10515,10 +9900,6 @@ index 0000000..bc2a772
 +  UNSPEC_SET_HILO
 +
 +  ;; GP manipulation.
-+  UNSPEC_LOADGP
-+  UNSPEC_COPYGP
-+  UNSPEC_MOVE_GP
-+  UNSPEC_RESTORE_GP
 +  UNSPEC_EH_RETURN
 +  UNSPEC_SET_GOT_VERSION
 +  UNSPEC_UPDATE_GOT_VERSION
@@ -10526,7 +9907,8 @@ index 0000000..bc2a772
 +  ;; Symbolic accesses.
 +  UNSPEC_LOAD_CALL
 +  UNSPEC_LOAD_GOT
-+  UNSPEC_TLS_LDM
++  UNSPEC_TLS_GD
++  UNSPEC_TLS_IE
 +
 +  ;; MIPS16 constant pools.
 +  UNSPEC_ALIGN
@@ -10802,10 +10184,7 @@ index 0000000..bc2a772
 +        (eq_attr "type" "ghost")
 +        (const_int 0)
 +
-+        (eq_attr "got" "load")
-+              (const_int 4)
-+        (eq_attr "got" "xgot_high")
-+        (const_int 8)
++        (eq_attr "got" "load") (const_int 8)
 +
 +        ;; SHIFT_SHIFTs are decomposed into two separate instructions.
 +        ;; They are extended instructions on MIPS16 targets.
@@ -12289,65 +11668,30 @@ index 0000000..bc2a772
 +;;
 +;;  ....................
 +
-+;; Insns to fetch a symbol from a big GOT.
-+
-+(define_insn_and_split "*xgot_hi<mode>"
-+  [(set (match_operand:P 0 "register_operand" "=d")
-+      (high:P (match_operand:P 1 "got_disp_operand" "")))]
-+  ""
-+  "#"
-+  "&& reload_completed"
-+  [(set (match_dup 0) (high:P (match_dup 2)))
-+   (set (match_dup 0) (plus:P (match_dup 0) (match_dup 3)))]
-+{
-+  operands[2] = mips_unspec_address (operands[1], SYMBOL_GOTOFF_DISP);
-+  operands[3] = pic_offset_table_rtx;
-+}
-+  [(set_attr "got" "xgot_high")
-+   (set_attr "mode" "<MODE>")])
-+
-+(define_insn_and_split "*xgot_lo<mode>"
++(define_insn "got_load<mode>"
 +  [(set (match_operand:P 0 "register_operand" "=d")
-+      (lo_sum:P (match_operand:P 1 "register_operand" "d")
-+                (match_operand:P 2 "got_disp_operand" "")))]
-+  ""
-+  "#"
-+  "&& reload_completed"
-+  [(set (match_dup 0)
-+      (unspec:P [(match_dup 1) (match_dup 3)] UNSPEC_LOAD_GOT))]
-+  { operands[3] = mips_unspec_address (operands[2], SYMBOL_GOTOFF_DISP); }
++       (unspec:P [(match_operand:P 1 "symbolic_operand" "")]
++                 UNSPEC_LOAD_GOT))]
++  "TARGET_USE_GOT"
++  "la\t%0,%1"
 +  [(set_attr "got" "load")
 +   (set_attr "mode" "<MODE>")])
 +
-+;; Insns to fetch a symbol from a normal GOT.
-+
-+(define_insn_and_split "*got_disp<mode>"
++(define_insn "got_load_tls_gd<mode>"
 +  [(set (match_operand:P 0 "register_operand" "=d")
-+      (match_operand:P 1 "got_disp_operand" ""))]
-+  "!mips_split_p[SYMBOL_GOT_DISP]"
-+  "#"
-+  "&& reload_completed"
-+  [(set (match_dup 0) (match_dup 2))]
-+  { operands[2] = mips_got_load (NULL, operands[1], SYMBOL_GOTOFF_DISP); }
++       (unspec:P [(match_operand:P 1 "symbolic_operand" "")]
++                 UNSPEC_TLS_GD))]
++  "TARGET_USE_GOT"
++  "la.tls.gd\t%0,%1"
 +  [(set_attr "got" "load")
 +   (set_attr "mode" "<MODE>")])
 +
-+;; Convenience expander that generates the rhs of a load_got<mode> insn.
-+(define_expand "unspec_got<mode>"
-+  [(unspec:P [(match_operand:P 0)
-+            (match_operand:P 1)] UNSPEC_LOAD_GOT)])
-+
-+;; Lower-level instructions for loading an address from the GOT.
-+;; We could use MEMs, but an unspec gives more optimization
-+;; opportunities.
-+
-+(define_insn "load_got<mode>"
++(define_insn "got_load_tls_ie<mode>"
 +  [(set (match_operand:P 0 "register_operand" "=d")
-+      (unspec:P [(match_operand:P 1 "register_operand" "d")
-+                 (match_operand:P 2 "immediate_operand" "")]
-+                UNSPEC_LOAD_GOT))]
-+  ""
-+  "<load>\t%0,%R2(%1)"
++       (unspec:P [(match_operand:P 1 "symbolic_operand" "")]
++                 UNSPEC_TLS_IE))]
++  "TARGET_USE_GOT"
++  "la.tls.ie\t%0,%1"
 +  [(set_attr "got" "load")
 +   (set_attr "mode" "<MODE>")])
 +
@@ -12657,50 +12001,6 @@ index 0000000..bc2a772
 +  [(set_attr "move_type" "mfc,fpstore")
 +   (set_attr "mode" "<HALFMODE>")])
 +
-+;; Insn to initialize $gp for n32/n64 abicalls.  Operand 0 is the offset
-+;; of _gp from the start of this function.  Operand 1 is the incoming
-+;; function address.
-+(define_insn_and_split "loadgp_newabi_<mode>"
-+  [(set (match_operand:P 0 "register_operand" "=d")
-+      (unspec:P [(match_operand:P 1)
-+                 (match_operand:P 2 "register_operand" "d")]
-+                UNSPEC_LOADGP))]
-+  "mips_current_loadgp_style () == LOADGP_NEWABI"
-+  { return mips_must_initialize_gp_p () ? "#" : ""; }
-+  "&& mips_must_initialize_gp_p ()"
-+  [(set (match_dup 0) (match_dup 3))
-+   (set (match_dup 0) (match_dup 4))
-+   (set (match_dup 0) (match_dup 5))]
-+{
-+  operands[3] = gen_rtx_HIGH (Pmode, operands[1]);
-+  operands[4] = gen_rtx_PLUS (Pmode, operands[0], operands[2]);
-+  operands[5] = gen_rtx_LO_SUM (Pmode, operands[0], operands[1]);
-+}
-+  [(set_attr "type" "ghost")])
-+
-+;; Likewise, for -mno-shared code.  Operand 0 is the __gnu_local_gp symbol.
-+(define_insn_and_split "loadgp_absolute_<mode>"
-+  [(set (match_operand:P 0 "register_operand" "=d")
-+      (unspec:P [(match_operand:P 1)] UNSPEC_LOADGP))]
-+  "mips_current_loadgp_style () == LOADGP_ABSOLUTE"
-+  { return mips_must_initialize_gp_p () ? "#" : ""; }
-+  "&& mips_must_initialize_gp_p ()"
-+  [(const_int 0)]
-+{
-+  mips_emit_move (operands[0], operands[1]);
-+  DONE;
-+}
-+  [(set_attr "type" "ghost")])
-+
-+;; This blockage instruction prevents the gp load from being
-+;; scheduled after an implicit use of gp.  It also prevents
-+;; the load from being deleted as dead.
-+(define_insn "loadgp_blockage"
-+  [(unspec_volatile [(reg:SI 28)] UNSPEC_BLOCKAGE)]
-+  ""
-+  ""
-+  [(set_attr "type" "ghost")])
-+
 +;; Expand in-line code to clear the instruction cache between operand[0] and
 +;; operand[1].
 +(define_expand "clear_cache"
@@ -13039,10 +12339,6 @@ index 0000000..bc2a772
 +   (use (label_ref (match_operand 1 "")))]
 +  ""
 +{
-+  if (TARGET_GPWORD)
-+    operands[0] = expand_binop (Pmode, add_optab, operands[0],
-+                              pic_offset_table_rtx, 0, 0, OPTAB_WIDEN);
-+
 +  if (Pmode == SImode)
 +    emit_jump_insn (gen_tablejumpsi (operands[0], operands[1]));
 +  else
@@ -13059,55 +12355,6 @@ index 0000000..bc2a772
 +  [(set_attr "type" "jump")
 +   (set_attr "mode" "none")])
 +
-+;; For TARGET_USE_GOT, we save the gp in the jmp_buf as well.
-+;; While it is possible to either pull it off the stack (in the
-+;; o32 case) or recalculate it given t9 and our target label,
-+;; it takes 3 or 4 insns to do so.
-+
-+(define_expand "builtin_setjmp_setup"
-+  [(use (match_operand 0 "register_operand"))]
-+  "TARGET_USE_GOT"
-+{
-+  rtx addr;
-+
-+  addr = plus_constant (operands[0], GET_MODE_SIZE (Pmode) * 3);
-+  mips_emit_move (gen_rtx_MEM (Pmode, addr), pic_offset_table_rtx);
-+  DONE;
-+})
-+
-+;; Restore the gp that we saved above.  Despite the earlier comment, it seems
-+;; that older code did recalculate the gp from $25.  Continue to jump through
-+;; $25 for compatibility (we lose nothing by doing so).
-+
-+(define_expand "builtin_longjmp"
-+  [(use (match_operand 0 "register_operand"))]
-+  "TARGET_USE_GOT"
-+{
-+  /* The elements of the buffer are, in order:  */
-+  int W = GET_MODE_SIZE (Pmode);
-+  rtx fp = gen_rtx_MEM (Pmode, operands[0]);
-+  rtx lab = gen_rtx_MEM (Pmode, plus_constant (operands[0], 1*W));
-+  rtx stack = gen_rtx_MEM (Pmode, plus_constant (operands[0], 2*W));
-+  rtx gpv = gen_rtx_MEM (Pmode, plus_constant (operands[0], 3*W));
-+  rtx pv = gen_rtx_REG (Pmode, PIC_FUNCTION_ADDR_REGNUM);
-+  /* Use gen_raw_REG to avoid being given pic_offset_table_rtx.
-+     The target is bound to be using $28 as the global pointer
-+     but the current function might not be.  */
-+  rtx gp = gen_raw_REG (Pmode, GLOBAL_POINTER_REGNUM);
-+
-+  /* This bit is similar to expand_builtin_longjmp except that it
-+     restores $gp as well.  */
-+  mips_emit_move (hard_frame_pointer_rtx, fp);
-+  mips_emit_move (pv, lab);
-+  emit_stack_restore (SAVE_NONLOCAL, stack);
-+  mips_emit_move (gp, gpv);
-+  emit_use (hard_frame_pointer_rtx);
-+  emit_use (stack_pointer_rtx);
-+  emit_use (gp);
-+  emit_indirect_jump (pv);
-+  DONE;
-+})
-+\f
 +;;
 +;;  ....................
 +;;
@@ -13228,21 +12475,6 @@ index 0000000..bc2a772
 +  DONE;
 +})
 +
-+;; Move between $gp and its register save slot.
-+(define_insn_and_split "move_gp<mode>"
-+  [(set (match_operand:GPR 0 "nonimmediate_operand" "=d,m")
-+      (unspec:GPR [(match_operand:GPR 1 "move_operand" "m,d")]
-+                  UNSPEC_MOVE_GP))]
-+  ""
-+  { return mips_must_initialize_gp_p () ? "#" : ""; }
-+  "mips_must_initialize_gp_p ()"
-+  [(const_int 0)]
-+{
-+  mips_emit_move (operands[0], operands[1]);
-+  DONE;
-+}
-+  [(set_attr "type" "ghost")])
-+\f
 +;;
 +;;  ....................
 +;;
@@ -13337,8 +12569,7 @@ index 0000000..bc2a772
 +            (use (match_operand 3 ""))])]     ;; struct_value_size_rtx
 +  ""
 +{
-+  mips_expand_call (MIPS_CALL_SIBCALL, NULL_RTX, XEXP (operands[0], 0),
-+                  operands[1], operands[2], false);
++  mips_expand_call (true, NULL_RTX, XEXP (operands[0], 0), operands[1]);
 +  DONE;
 +})
 +
@@ -13356,8 +12587,7 @@ index 0000000..bc2a772
 +            (use (match_operand 3 ""))])]             ;; next_arg_reg
 +  ""
 +{
-+  mips_expand_call (MIPS_CALL_SIBCALL, operands[0], XEXP (operands[1], 0),
-+                  operands[2], operands[3], false);
++  mips_expand_call (true, operands[0], XEXP (operands[1], 0), operands[2]);
 +  DONE;
 +})
 +
@@ -13387,13 +12617,12 @@ index 0000000..bc2a772
 +            (use (match_operand 3 ""))])]     ;; struct_value_size_rtx
 +  ""
 +{
-+  mips_expand_call (MIPS_CALL_NORMAL, NULL_RTX, XEXP (operands[0], 0),
-+                  operands[1], operands[2], false);
++  mips_expand_call (false, NULL_RTX, XEXP (operands[0], 0), operands[1]);
 +  DONE;
 +})
 +
 +(define_insn "call_internal"
-+  [(call (mem:SI (match_operand 0 "call_insn_operand" "c,S"))
++  [(call (mem:SI (match_operand 0 "call_insn_operand" "r,S"))
 +       (match_operand 1 "" ""))
 +   (clobber (reg:SI RETURN_ADDR_REGNUM))]
 +  ""
@@ -13420,15 +12649,14 @@ index 0000000..bc2a772
 +            (use (match_operand 3 ""))])]             ;; next_arg_reg
 +  ""
 +{
-+  mips_expand_call (MIPS_CALL_NORMAL, operands[0], XEXP (operands[1], 0),
-+                  operands[2], operands[3], false);
++  mips_expand_call (false, operands[0], XEXP (operands[1], 0), operands[2]);
 +  DONE;
 +})
 +
 +;; See comment for call_internal.
 +(define_insn "call_value_internal"
 +  [(set (match_operand 0 "register_operand" "")
-+        (call (mem:SI (match_operand 1 "call_insn_operand" "c,S"))
++        (call (mem:SI (match_operand 1 "call_insn_operand" "r,S"))
 +              (match_operand 2 "" "")))
 +   (clobber (reg:SI RETURN_ADDR_REGNUM))]
 +  ""
@@ -13449,7 +12677,7 @@ index 0000000..bc2a772
 +;; See comment for call_internal.
 +(define_insn "call_value_multiple_internal"
 +  [(set (match_operand 0 "register_operand" "")
-+        (call (mem:SI (match_operand 1 "call_insn_operand" "c,S"))
++        (call (mem:SI (match_operand 1 "call_insn_operand" "r,S"))
 +              (match_operand 2 "" "")))
 +   (set (match_operand 3 "register_operand" "")
 +      (call (mem:SI (match_dup 1))
@@ -13513,10 +12741,10 @@ index 0000000..bc2a772
 +])
 diff --git a/gcc-4.6.1/gcc/config/riscv/riscv.opt b/gcc-4.6.1/gcc/config/riscv/riscv.opt
 new file mode 100644
-index 0000000..291fe75
+index 0000000..edcc03e
 --- /dev/null
 +++ gcc-4.6.1/gcc/config/riscv/riscv.opt
-@@ -0,0 +1,69 @@
+@@ -0,0 +1,73 @@
 +; Options for the MIPS port of the compiler
 +;
 +; Copyright (C) 2005, 2007, 2008, 2010, 2011 Free Software Foundation, Inc.
@@ -13543,9 +12771,13 @@ index 0000000..291fe75
 +EL
 +Driver
 +
-+mabi=
-+Target RejectNegative Joined
-+-mabi=ABI     Generate code that conforms to the given ABI
++m32
++Target RejectNegative Mask(32BIT)
++Generate RV32 code
++
++m64
++Target RejectNegative InverseMask(32BIT, 64BIT)
++Generate RV64 code
 +
 +mabicalls
 +Target Report Mask(ABICALLS)
@@ -13616,7 +12848,7 @@ index 0000000..bf19839
 +#define LINUX_DYNAMIC_LINKER64 GLIBC_DYNAMIC_LINKER64
 diff --git a/gcc-4.6.1/gcc/config/riscv/sync.md b/gcc-4.6.1/gcc/config/riscv/sync.md
 new file mode 100644
-index 0000000..3455bd1
+index 0000000..adad259
 --- /dev/null
 +++ gcc-4.6.1/gcc/config/riscv/sync.md
 @@ -0,0 +1,92 @@
@@ -13708,13 +12940,13 @@ index 0000000..3455bd1
 +      (unspec_volatile:GPR [(match_operand:GPR 2 "reg_or_0_operand" "d")
 +                            (match_operand:GPR 3 "reg_or_0_operand" "d")]
 +       UNSPEC_COMPARE_AND_SWAP))
-+   (clobber (match_scratch:GPR 4 "=d"))]
++   (clobber (match_scratch:GPR 4 "=&d"))]
 +  ""
 +  "1: lr.<amo> %0,%1; bne %0,%2,1f; sc.<amo> %4,%3,%1; bnez %4,1b; 1:"
 +  [(set (attr "length") (const_int 16))])
 diff --git a/gcc-4.6.1/gcc/config/riscv/t-elf b/gcc-4.6.1/gcc/config/riscv/t-elf
 new file mode 100644
-index 0000000..4664de3
+index 0000000..02da707
 --- /dev/null
 +++ gcc-4.6.1/gcc/config/riscv/t-elf
 @@ -0,0 +1,36 @@
@@ -13748,7 +12980,7 @@ index 0000000..4664de3
 +
 +# Build the libraries for both hard and soft floating point
 +
-+MULTILIB_OPTIONS = mabi=64/mabi=32
++MULTILIB_OPTIONS = m64/m32
 +MULTILIB_DIRNAMES = 64 32
 +EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o crti.o crtn.o
 +
@@ -13756,7 +12988,7 @@ index 0000000..4664de3
 +INSTALL_LIBGCC = install-multilib
 diff --git a/gcc-4.6.1/gcc/config/riscv/t-linux64 b/gcc-4.6.1/gcc/config/riscv/t-linux64
 new file mode 100644
-index 0000000..7c45312
+index 0000000..5f54dc0
 --- /dev/null
 +++ gcc-4.6.1/gcc/config/riscv/t-linux64
 @@ -0,0 +1,35 @@
@@ -13778,7 +13010,7 @@ index 0000000..7c45312
 +# along with GCC; see the file COPYING3.  If not see
 +# <http://www.gnu.org/licenses/>.
 +
-+MULTILIB_OPTIONS = mabi=64/mabi=32
++MULTILIB_OPTIONS = m64/m32
 +MULTILIB_DIRNAMES = 64 32
 +MULTILIB_OSDIRNAMES = ../lib ../lib32
 +
diff --git a/tools/compilers/gcc-glibc/gcc-4.6.1-ros.patch b/tools/compilers/gcc-glibc/gcc-4.6.1-ros.patch
new file mode 100644 (file)
index 0000000..7d77a1d
--- /dev/null
@@ -0,0 +1,8260 @@
+diff -ruN orig-src/gcc-4.6.1/config.sub gcc-4.6.1/config.sub
+--- orig-src/gcc-4.6.1/config.sub      2010-05-25 06:22:07.000000000 -0700
++++ gcc-4.6.1/config.sub       2013-04-16 02:23:02.132195010 -0700
+@@ -1297,7 +1297,7 @@
+             | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
+             | -sym* | -kopensolaris* \
+             | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+-            | -aos* | -aros* \
++            | -aos* | -aros* | -ros* \
+             | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+             | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+             | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+diff -ruN orig-src/gcc-4.6.1/gcc/config/i386/ros.h gcc-4.6.1/gcc/config/i386/ros.h
+--- orig-src/gcc-4.6.1/gcc/config/i386/ros.h   1969-12-31 16:00:00.000000000 -0800
++++ gcc-4.6.1/gcc/config/i386/ros.h    2013-04-16 02:22:56.720144332 -0700
+@@ -0,0 +1,213 @@
++/* Definitions for Intel 386 running Linux-based GNU systems with ELF format.
++   Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2001, 2002, 2004, 2005,
++   2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
++   Contributed by Eric Youngdale.
++   Modified for stabs-in-ELF by H.J. Lu.
++
++This file is part of GCC.
++
++GCC is free software; you can redistribute it and/or modify
++it under the terms of the GNU General Public License as published by
++the Free Software Foundation; either version 3, or (at your option)
++any later version.
++
++GCC is distributed in the hope that it will be useful,
++but WITHOUT ANY WARRANTY; without even the implied warranty of
++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++GNU General Public License for more details.
++
++You should have received a copy of the GNU General Public License
++along with GCC; see the file COPYING3.  If not see
++<http://www.gnu.org/licenses/>.  */
++
++/* Output at beginning of assembler file.  */
++/* The .file command should always begin the output.  */
++#define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
++
++#define TARGET_VERSION fprintf (stderr, " (i386 ROS/ELF)");
++
++/* The svr4 ABI for the i386 says that records and unions are returned
++   in memory.  */
++#undef DEFAULT_PCC_STRUCT_RETURN
++#define DEFAULT_PCC_STRUCT_RETURN 1
++
++/* We arrange for the whole %gs segment to map the tls area.  */
++#undef TARGET_TLS_DIRECT_SEG_REFS_DEFAULT
++#define TARGET_TLS_DIRECT_SEG_REFS_DEFAULT MASK_TLS_DIRECT_SEG_REFS
++
++#undef ASM_COMMENT_START
++#define ASM_COMMENT_START "#"
++
++#undef DBX_REGISTER_NUMBER
++#define DBX_REGISTER_NUMBER(n) \
++  (TARGET_64BIT ? dbx64_register_map[n] : svr4_dbx_register_map[n])
++
++/* Output assembler code to FILE to call the profiler.
++   To the best of my knowledge, no Linux libc has required the label
++   argument to mcount.  */
++
++#define NO_PROFILE_COUNTERS   1
++
++#undef MCOUNT_NAME
++#define MCOUNT_NAME "mcount"
++
++/* The GLIBC version of mcount for the x86 assumes that there is a
++   frame, so we cannot allow profiling without a frame pointer.  */
++
++#undef SUBTARGET_FRAME_POINTER_REQUIRED
++#define SUBTARGET_FRAME_POINTER_REQUIRED crtl->profile
++
++#undef SIZE_TYPE
++#define SIZE_TYPE "unsigned int"
++ 
++#undef PTRDIFF_TYPE
++#define PTRDIFF_TYPE "int"
++  
++#undef WCHAR_TYPE
++#define WCHAR_TYPE "long int"
++   
++#undef WCHAR_TYPE_SIZE
++#define WCHAR_TYPE_SIZE BITS_PER_WORD
++    
++#define TARGET_OS_CPP_BUILTINS()              \
++  do                                          \
++    {                                         \
++      LINUX_TARGET_OS_CPP_BUILTINS();         \
++    }                                         \
++  while (0)
++
++#undef CPP_SPEC
++#define CPP_SPEC "%{posix:-D_POSIX_SOURCE} %{pthread:-D_REENTRANT}"
++
++#undef CC1_SPEC
++#define CC1_SPEC "%(cc1_cpu) %{profile:-p}"
++
++/* Provide a LINK_SPEC appropriate for Linux.  Here we provide support
++   for the special GCC options -static and -shared, which allow us to
++   link things in one of these three modes by applying the appropriate
++   combinations of options at link-time.
++
++   When the -shared link option is used a final link is not being
++   done.  */
++
++/* These macros may be overridden in k*bsd-gnu.h and i386/k*bsd-gnu.h. */
++#define LINK_EMULATION "elf_i386"
++#define GLIBC_DYNAMIC_LINKER "/lib/ld.so.1"
++
++#undef  ASM_SPEC
++#define ASM_SPEC \
++  "--32 %{!mno-sse2avx:%{mavx:-msse2avx}} %{msse2avx:%{!mavx:-msse2avx}}"
++
++#undef  SUBTARGET_EXTRA_SPECS
++#define SUBTARGET_EXTRA_SPECS \
++  { "link_emulation", LINK_EMULATION },\
++  { "dynamic_linker", GLIBC_DYNAMIC_LINKER }
++
++#undef        LINK_SPEC
++#define LINK_SPEC "-m %(link_emulation) %{shared:-shared} \
++  %{!shared: \
++    %{!static: \
++      %{rdynamic:-export-dynamic} \
++      -dynamic-linker %(dynamic_linker)} \
++      %{static:-static}}"
++
++/* Similar to standard Linux, but adding -ffast-math support.  */
++#undef  ENDFILE_SPEC
++#define ENDFILE_SPEC \
++  "%{ffast-math|funsafe-math-optimizations:crtfastmath.o%s} \
++   %{mpc32:crtprec32.o%s} \
++   %{mpc64:crtprec64.o%s} \
++   %{mpc80:crtprec80.o%s} \
++   %{shared|pie:crtendS.o%s;:crtend.o%s} crtn.o%s"
++
++/* A C statement (sans semicolon) to output to the stdio stream
++   FILE the assembler definition of uninitialized global DECL named
++   NAME whose size is SIZE bytes and alignment is ALIGN bytes.
++   Try to use asm_output_aligned_bss to implement this macro.  */
++
++#define ASM_OUTPUT_ALIGNED_BSS(FILE, DECL, NAME, SIZE, ALIGN) \
++  asm_output_aligned_bss (FILE, DECL, NAME, SIZE, ALIGN)
++
++/* A C statement to output to the stdio stream FILE an assembler
++   command to advance the location counter to a multiple of 1<<LOG
++   bytes if it is within MAX_SKIP bytes.
++
++   This is used to align code labels according to Intel recommendations.  */
++
++#ifdef HAVE_GAS_MAX_SKIP_P2ALIGN
++#define ASM_OUTPUT_MAX_SKIP_ALIGN(FILE,LOG,MAX_SKIP)                  \
++  do {                                                                        \
++    if ((LOG) != 0) {                                                 \
++      if ((MAX_SKIP) == 0) fprintf ((FILE), "\t.p2align %d\n", (LOG));        \
++      else {                                                          \
++      fprintf ((FILE), "\t.p2align %d,,%d\n", (LOG), (MAX_SKIP));     \
++      /* Make sure that we have at least 8 byte alignment if > 8 byte \
++         alignment is preferred.  */                                  \
++      if ((LOG) > 3                                                   \
++          && (1 << (LOG)) > ((MAX_SKIP) + 1)                          \
++          && (MAX_SKIP) >= 7)                                         \
++        fputs ("\t.p2align 3\n", (FILE));                             \
++      }                                                                       \
++    }                                                                 \
++  } while (0)
++#endif
++
++/* Handle special EH pointer encodings.  Absolute, pc-relative, and
++   indirect are handled automatically.  */
++#define ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX(FILE, ENCODING, SIZE, ADDR, DONE) \
++  do {                                                                        \
++    if ((SIZE) == 4 && ((ENCODING) & 0x70) == DW_EH_PE_datarel)               \
++      {                                                                       \
++        fputs (ASM_LONG, FILE);                       \
++        assemble_name (FILE, XSTR (ADDR, 0));                         \
++      fputs (((ENCODING) & DW_EH_PE_indirect ? "@GOT" : "@GOTOFF"), FILE); \
++        goto DONE;                                                    \
++      }                                                                       \
++  } while (0)
++
++/* Used by crtstuff.c to initialize the base of data-relative relocations.
++   These are GOT relative on x86, so return the pic register.  */
++#ifdef __PIC__
++#define CRT_GET_RFIB_DATA(BASE)                       \
++  {                                           \
++    register void *ebx_ __asm__("ebx");               \
++    BASE = ebx_;                              \
++  }
++#else
++#define CRT_GET_RFIB_DATA(BASE)                                               \
++  __asm__ ("call\t.LPR%=\n"                                           \
++         ".LPR%=:\n\t"                                                \
++         "pop{l}\t%0\n\t"                                             \
++         /* Due to a GAS bug, this cannot use EAX.  That encodes      \
++            smaller than the traditional EBX, which results in the    \
++            offset being off by one.  */                              \
++         "add{l}\t{$_GLOBAL_OFFSET_TABLE_+[.-.LPR%=],%0"              \
++                 "|%0,_GLOBAL_OFFSET_TABLE_+(.-.LPR%=)}"              \
++         : "=d"(BASE))
++#endif
++
++/* Put all *tf routines in libgcc.  */
++#undef LIBGCC2_HAS_TF_MODE
++#define LIBGCC2_HAS_TF_MODE 1
++#define LIBGCC2_TF_CEXT q
++#define TF_SIZE 113
++
++#define TARGET_ASM_FILE_END file_end_indicate_exec_stack
++
++/* The stack pointer needs to be moved while checking the stack.  */
++#define STACK_CHECK_MOVING_SP 1
++
++/* Static stack checking is supported by means of probes.  */
++#define STACK_CHECK_STATIC_BUILTIN 1
++
++/* This macro may be overridden in i386/k*bsd-gnu.h.  */
++#define REG_NAME(reg) reg
++
++#ifdef TARGET_LIBC_PROVIDES_SSP
++/* i386 glibc provides __stack_chk_guard in %gs:0x14.  */
++#define TARGET_THREAD_SSP_OFFSET      0x14
++
++/* We steal the last transactional memory word.  */
++#define TARGET_CAN_SPLIT_STACK
++#define TARGET_THREAD_SPLIT_STACK_OFFSET 0x30
++#endif
+diff -ruN orig-src/gcc-4.6.1/gcc/config/ros.h gcc-4.6.1/gcc/config/ros.h
+--- orig-src/gcc-4.6.1/gcc/config/ros.h        1969-12-31 16:00:00.000000000 -0800
++++ gcc-4.6.1/gcc/config/ros.h 2013-04-16 02:22:56.728144405 -0700
+@@ -0,0 +1,44 @@
++/* Definitions for systems using the Linux kernel, with or without
++   MMU, using ELF at the compiler level but possibly FLT for final
++   linked executables and shared libraries in some no-MMU cases, and
++   possibly with a choice of libc implementations.
++   Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2003, 2004, 2005, 2006,
++   2007, 2009, 2010, 2011 Free Software Foundation, Inc.
++   Contributed by Eric Youngdale.
++   Modified for stabs-in-ELF by H.J. Lu (hjl@lucon.org).
++
++This file is part of GCC.
++
++GCC is free software; you can redistribute it and/or modify
++it under the terms of the GNU General Public License as published by
++the Free Software Foundation; either version 3, or (at your option)
++any later version.
++
++GCC is distributed in the hope that it will be useful,
++but WITHOUT ANY WARRANTY; without even the implied warranty of
++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++GNU General Public License for more details.
++
++Under Section 7 of GPL version 3, you are granted additional
++permissions described in the GCC Runtime Library Exception, version
++3.1, as published by the Free Software Foundation.
++
++You should have received a copy of the GNU General Public License and
++a copy of the GCC Runtime Library Exception along with this program;
++see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
++<http://www.gnu.org/licenses/>.  */
++
++#define LINUX_TARGET_OS_CPP_BUILTINS()                                \
++    do {                                                      \
++      builtin_define ("__gnu_ros__");                 \
++      builtin_define_std ("ros");                             \
++      builtin_define_std ("unix");                            \
++      builtin_assert ("system=ros");                  \
++      builtin_assert ("system=unix");                         \
++      builtin_assert ("system=posix");                        \
++    } while (0)
++
++#undef LINK_GCC_C_SEQUENCE_SPEC
++#define LINK_GCC_C_SEQUENCE_SPEC \
++  "--whole-archive -lparlib --no-whole-archive " \
++  "%{static:--start-group} %G %L %{static:--end-group}%{!static:%G}"
+diff -ruN orig-src/gcc-4.6.1/gcc/config.gcc gcc-4.6.1/gcc/config.gcc
+--- orig-src/gcc-4.6.1/gcc/config.gcc  2011-05-22 13:03:43.000000000 -0700
++++ gcc-4.6.1/gcc/config.gcc   2013-04-16 02:23:02.132195010 -0700
+@@ -699,6 +699,14 @@
+   default_use_cxa_atexit=yes
+   use_gcc_stdint=wrap
+   ;;
++*-*-ros*)
++  tm_defines="$tm_defines DEFAULT_LIBC=LIBC_GLIBC"
++  extra_parts="crtbegin.o crtbeginS.o crtbeginT.o crtend.o crtendS.o"
++  default_use_cxa_atexit=yes
++  use_gcc_stdint=wrap
++  gas=yes
++  gnu_ld=yes
++  ;;
+ esac
+ case ${target} in
+@@ -1206,6 +1214,15 @@
+       tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h newlib-stdint.h i386/i386elf.h"
+       tmake_file="${tmake_file} i386/t-i386elf t-svr4"
+       ;;
++i[34567]86-*-ros*)
++      tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h gnu-user.h ros.h i386/ros.h glibc-stdint.h"
++      tmake_file="${tmake_file} i386/t-crtstuff i386/t-crtpc i386/t-crtfm t-dfprules"
++      tmake_file="${tmake_file} t-slibgcc-elf-ver t-linux i386/t-fprules-softfp soft-fp/t-softfp i386/t-linux"
++      ;;
++riscv*-*-ros*)
++      tm_file="dbxelf.h elfos.h gnu-user.h ros.h ${tm_file} riscv/ros.h riscv/ros64.h glibc-stdint.h"
++      tmake_file="${tmake_file} t-slibgcc-elf-ver t-linux"
++      ;;
+ x86_64-*-elf*)
+       tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h newlib-stdint.h i386/i386elf.h i386/x86-64.h"
+       tmake_file="${tmake_file} i386/t-i386elf t-svr4"
+diff -ruN orig-src/gcc-4.6.1/libgcc/config.host gcc-4.6.1/libgcc/config.host
+--- orig-src/gcc-4.6.1/libgcc/config.host      2011-03-13 23:06:23.000000000 -0700
++++ gcc-4.6.1/libgcc/config.host       2013-04-16 02:23:02.260196208 -0700
+@@ -162,6 +162,9 @@
+ *-*-linux* | frv-*-*linux* | *-*-kfreebsd*-gnu | *-*-knetbsd*-gnu | *-*-gnu*)
+   extra_parts="crtbegin.o crtbeginS.o crtbeginT.o crtend.o crtendS.o"
+   ;;
++*-*-ros*)
++  extra_parts="crtbegin.o crtbeginS.o crtbeginT.o crtend.o crtendS.o"
++  ;;
+ *-*-netbsd*)
+   ;;
+ *-*-openbsd*)
+@@ -297,7 +300,9 @@
+       ;;
+ i[34567]86-*-openbsd*)
+       ;;
+-i[34567]86-*-linux* | i[34567]86-*-kfreebsd*-gnu | i[34567]86-*-knetbsd*-gnu | i[34567]86-*-gnu*)
++riscv*-*-ros*)
++      ;;
++i[34567]86-*-ros* | i[34567]86-*-linux* | i[34567]86-*-kfreebsd*-gnu | i[34567]86-*-knetbsd*-gnu | i[34567]86-*-gnu*)
+       extra_parts="$extra_parts crtprec32.o crtprec64.o crtprec80.o crtfastmath.o"
+       tmake_file="${tmake_file} i386/t-crtpc i386/t-crtfm"
+       ;;
+@@ -621,6 +626,7 @@
+   i[34567]86-*-kfreebsd*-gnu | x86_64-*-kfreebsd*-gnu | \
+   i[34567]86-*-linux* | x86_64-*-linux* | \
+   i[34567]86-*-gnu* | \
++  i[34567]86-*-ros* | \
+   i[34567]86-*-solaris2* | \
+   i[34567]86-*-cygwin* | i[34567]86-*-mingw* | x86_64-*-mingw* | \
+   i[34567]86-*-freebsd* | x86_64-*-freebsd*)
+diff -ruN orig-src/gcc-4.6.1/libgo/aclocal.m4 gcc-4.6.1/libgo/aclocal.m4
+--- orig-src/gcc-4.6.1/libgo/aclocal.m4        2010-11-12 12:52:54.000000000 -0800
++++ gcc-4.6.1/libgo/aclocal.m4 2013-04-16 02:22:56.768144781 -0700
+@@ -1,7 +1,8 @@
+-# generated automatically by aclocal 1.11.1 -*- Autoconf -*-
++# generated automatically by aclocal 1.11.3 -*- Autoconf -*-
+ # Copyright (C) 1996, 1997, 1998, 1999, 2000, 200