This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH} Fix PIC bugs for Score


Hi all,

I fixed some PIC bugs for Score.
Please see changelog or attachment.

   gas/
   * config/tc-score.c (build_lw_pic): Rename as build_lwst_pic.
   Delete the code handling large constant for PIC.
   Modify some comments.
   (score_relax_frag): Decrease insn_addr in certain situation.
   (s_score_cprestore): Change .cprestore syntax from ".cprestore offset" 
   to ".cprestore reg, offset".
 
   bfd/
   * elf32-score.c (score_elf_got_lo16_reloc): Change some variables type 
from
   unsigned to signed.
   (score_elf_final_link_relocate): Fix bugs of handling relocation type 
R_SCORE_GOT15,
   R_SCORE_GOT_LO16, and R_SCORE_REL32.
   (_bfd_score_elf_relocate_section): Handle R_SCORE_GOT_LO16 specially.


Index: bfd/elf32-score.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-score.c,v
retrieving revision 1.5
diff -p -u -r1.5 elf32-score.c
--- bfd/elf32-score.c   23 Oct 2006 02:41:11 -0000      1.5
+++ bfd/elf32-score.c   25 Dec 2006 08:40:47 -0000
@@ -532,8 +532,8 @@ score_elf_got_lo16_reloc (bfd *abfd,
                          char **error_message ATTRIBUTE_UNUSED)
 {
   bfd_vma addend = 0, offset = 0;
-  unsigned long val;
-  unsigned long hi16_offset, hi16_value, uvalue;
+  signed long val;
+  signed long hi16_offset, hi16_value, uvalue;
 
   hi16_value = bfd_get_32 (abfd, hi16_rel_addr);
   hi16_offset = ((((hi16_value >> 16) & 0x3) << 15) | (hi16_value & 
0x7fff)) >> 1;
@@ -543,7 +543,10 @@ score_elf_got_lo16_reloc (bfd *abfd,
   if (reloc_entry->address > input_section->size)
     return bfd_reloc_outofrange;
   uvalue = ((hi16_offset << 16) | (offset & 0xffff)) + val;
-  hi16_offset = (uvalue >> 16) & 0x7fff;
+  if ((uvalue > -0x8000) && (uvalue < 0x7fff))
+    hi16_offset = 0;
+  else
+    hi16_offset = (uvalue >> 16) & 0x7fff;
   hi16_value = (hi16_value & ~0x37fff) | (hi16_offset & 0x7fff) | 
((hi16_offset << 1) & 0x30000);
   bfd_put_32 (abfd, hi16_value, hi16_rel_addr);
   offset = (uvalue & 0xffff) << 1;
@@ -1897,6 +1900,7 @@ score_elf_final_link_relocate (reloc_how
   r_symndx = ELF32_R_SYM (rel->r_info);
   r_type = ELF32_R_TYPE (rel->r_info);
   rel_addr = (input_section->output_section->vma + 
input_section->output_offset + rel->r_offset);
+  local_p = score_elf_local_relocation_p (input_bfd, rel, local_sections, 
TRUE);
 
   if (r_type == R_SCORE_GOT15)
     {
@@ -1905,25 +1909,22 @@ score_elf_final_link_relocate (reloc_how
       const struct elf_backend_data *bed;
       bfd_vma lo_value = 0;
 
-      addend = (bfd_get_32 (input_bfd, hit_data) >> howto->bitpos) & 
howto->src_mask;
-
       bed = get_elf_backend_data (output_bfd);
       relend = relocs + input_section->reloc_count * 
bed->s->int_rels_per_ext_rel;
       lo16_rel = score_elf_next_relocation (input_bfd, R_SCORE_GOT_LO16, 
rel, relend);
-      if (lo16_rel != NULL)
+      if ((local_p) && (lo16_rel != NULL))
        {
-          lo_value = (bfd_get_32 (input_bfd, contents + 
lo16_rel->r_offset) >> howto->bitpos)
-                      & howto->src_mask;
+         bfd_vma tmp = 0;
+         tmp = bfd_get_32 (input_bfd, contents + lo16_rel->r_offset);
+         lo_value = (((tmp >> 16) & 0x3) << 14) | ((tmp & 0x7fff) >> 1);
        }
-      addend = (addend << 16) + lo_value;
+      addend = lo_value;
     }
   else
     {
       addend = (bfd_get_32 (input_bfd, hit_data) >> howto->bitpos) & 
howto->src_mask;
     }
 
-  local_p = score_elf_local_relocation_p (input_bfd, rel, local_sections, 
TRUE);
-
   /* If we haven't already determined the GOT offset, or the GP value,
      and we're going to need it, get it now.  */
   switch (r_type)
@@ -1932,9 +1933,21 @@ score_elf_final_link_relocate (reloc_how
     case R_SCORE_GOT15:
       if (!local_p)
         {
-         g = score_elf_global_got_index (elf_hash_table (info)->dynobj,
-                                         (struct elf_link_hash_entry *) 
h);
-       }
+          g = score_elf_global_got_index (elf_hash_table (info)->dynobj,
+                                          (struct elf_link_hash_entry *) 
h);
+          if ((! elf_hash_table(info)->dynamic_sections_created
+               || (info->shared
+                   && (info->symbolic || h->root.dynindx == -1)
+                   && h->root.def_regular)))
+            {
+              /* This is a static link or a -Bsymbolic link.  The
+                 symbol is defined locally, or was forced to be local.
+                 We must initialize this entry in the GOT.  */
+              bfd *tmpbfd = elf_hash_table (info)->dynobj;
+              asection *sgot = score_elf_got_section (tmpbfd, FALSE);
+              bfd_put_32 (tmpbfd, value, sgot->contents + g);
+            }
+        }
       else if (r_type == R_SCORE_GOT15 || r_type == R_SCORE_CALL15)
         {
          /* There's no need to create a local GOT entry here; the
@@ -1993,6 +2006,11 @@ score_elf_final_link_relocate (reloc_how
                                                    input_section))
            return bfd_reloc_undefined;
        }
+      else if (r_symndx == 0)
+        /* r_symndx will be zero only for relocs against symbols
+           from removed linkonce sections, or sections discarded by
+           a linker script.  */
+        value = 0;
       else
        {
          if (r_type != R_SCORE_REL32)
@@ -2122,7 +2140,10 @@ score_elf_final_link_relocate (reloc_how
 
       if ((long) value > 0x3fff || (long) value < -0x4000)
         return bfd_reloc_overflow;
-      bfd_put_16 (input_bfd, value, hit_data + 2);
+
+      addend = bfd_get_32 (input_bfd, hit_data);
+      value = (addend & ~howto->dst_mask) | (value & howto->dst_mask);
+      bfd_put_32 (input_bfd, value, hit_data);
       return bfd_reloc_ok;
 
     case R_SCORE_GPREL32:
@@ -2133,10 +2154,10 @@ score_elf_final_link_relocate (reloc_how
 
     case R_SCORE_GOT_LO16:
       addend = bfd_get_32 (input_bfd, hit_data);
-      value = ((((addend >> 16) & 0x3) << 15) | (addend & 0x7fff)) >> 1;
+      value = (((addend >> 16) & 0x3) << 14) | ((addend & 0x7fff) >> 1);
       value += symbol;
-      offset = (value & 0xffff) << 1;
-      value = (addend & (~(howto->dst_mask))) | (offset & 0x7fff) | 
((offset << 1) & 0x30000);
+      value = (addend & (~(howto->dst_mask))) | ((value & 0x3fff) << 1) 
+               | (((value >> 14) & 0x3) << 16);
 
       bfd_put_32 (input_bfd, value, hit_data);
       return bfd_reloc_ok;
@@ -2303,6 +2324,17 @@ _bfd_score_elf_relocate_section (bfd *ou
                     | (offset & 0x7fff) | ((offset << 1) & 0x30000);
                   bfd_put_32 (input_bfd, value, contents + 
rel->r_offset);
                   break;
+                case R_SCORE_GOT_LO16:
+                  value = bfd_get_32 (input_bfd, contents + 
rel->r_offset);
+                  addend = (((value >> 16) & 0x3) << 14) | ((value & 
0x7fff) >> 1);
+                  msec = sec;
+                  addend = _bfd_elf_rel_local_sym (output_bfd, sym, 
&msec, addend) - relocation;
+                  addend += msec->output_section->vma + 
msec->output_offset;
+                  value = (value & (~(howto->dst_mask))) | ((addend & 
0x3fff) << 1)
+                           | (((addend >> 14) & 0x3) << 16);
+
+                  bfd_put_32 (input_bfd, value, contents + 
rel->r_offset);
+                  break;
                 default:
                   value = bfd_get_32 (input_bfd, contents + 
rel->r_offset);
                   /* Get the (signed) value from the instruction.  */
Index: gas/config/tc-score.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-score.c,v
retrieving revision 1.6
diff -p -u -r1.6 tc-score.c
--- gas/config/tc-score.c       16 Nov 2006 04:36:25 -0000      1.6
+++ gas/config/tc-score.c       25 Dec 2006 08:40:50 -0000
@@ -783,7 +783,7 @@ static const struct asm_opcode score_ins
   {"ldis_pic",  0x0a0c0000, 0x3e0e0000, 0x5000,     Insn_internal, 
do_rdi16_pic},
   {"addi_s_pic",0x02000000, 0x3e0e0001, 0x8000,     Insn_internal, 
do_addi_s_pic},
   {"addi_u_pic",0x02000000, 0x3e0e0001, 0x8000,     Insn_internal, 
do_addi_u_pic},
-  {"lw_pic",    0x20000000, 0x3e000000, 0x2008,     Insn_internal, 
do_lw_pic},
+  {"lw_pic",    0x20000000, 0x3e000000, 0x8000,     Insn_internal, 
do_lw_pic},
 };
 
 /* Next free entry in the pool.  */
@@ -3747,9 +3747,10 @@ build_la_pic (int reg_rd, expressionS ex
       fix_num = 1;
       var_num = 2;
 
-      /* Insn 1 and Insn 2  */
+      /* For an external symbol, only one insn is generated; 
+         For a local symbol, two insns are generated.  */
       /* Fix part
-        For an external symbol: lw rD, <sym>($gp)
+         For an external symbol: lw rD, <sym>($gp)
                                  (BFD_RELOC_SCORE_GOT15 or 
BFD_RELOC_SCORE_CALL15)  */
       sprintf (tmp, "lw_pic r%d, %s", reg_rd, add_symbol->bsym->name);
       if (append_insn (tmp, FALSE) == (int) FAIL)
@@ -4149,11 +4150,11 @@ nopic_need_relax (symbolS * sym, int bef
     return 1;
 }
 
-/* Build a relax frag for lw instruction when generating PIC,
+/* Build a relax frag for lw/st instruction when generating PIC,
    external symbol first and local symbol second.  */
 
 static void
-build_lw_pic (int reg_rd, expressionS exp)
+build_lwst_pic (int reg_rd, expressionS exp, const char *insn_name)
 {
   symbolS *add_symbol = exp.X_add_symbol;
   int add_number = exp.X_add_number;
@@ -4172,13 +4173,14 @@ build_lw_pic (int reg_rd, expressionS ex
       fix_num = 1;
       var_num = 2;
 
-      /* Insn 1 and Insn 2  */
+      /* For an external symbol, two insns are generated;
+         For a local symbol, three insns are generated.  */
       /* Fix part
-        For an external symbol: lw rD, <sym>($gp)
+         For an external symbol: lw rD, <sym>($gp)
                                  (BFD_RELOC_SCORE_GOT15)  */
-      sprintf (tmp, "lw_pic r%d, %s", reg_rd, add_symbol->bsym->name);
+      sprintf (tmp, "lw_pic %s, %s", "r1", add_symbol->bsym->name);
       if (append_insn (tmp, FALSE) == (int) FAIL)
-       return;
+        return;
 
       memcpy (&fix_insts[0], &inst, sizeof (struct score_it));
 
@@ -4188,91 +4190,25 @@ build_lw_pic (int reg_rd, expressionS ex
         addi rD, <sym>       (BFD_RELOC_GOT_LO16) */
       inst.reloc.type = BFD_RELOC_SCORE_GOT15;
       memcpy (&var_insts[0], &inst, sizeof (struct score_it));
-      sprintf (tmp, "addi_s_pic r%d, %s", reg_rd, 
add_symbol->bsym->name);
+      sprintf (tmp, "addi_s_pic %s, %s", "r1", add_symbol->bsym->name);
       if (append_insn (tmp, FALSE) == (int) FAIL)
-       return;
+        return;
 
       memcpy (&var_insts[1], &inst, sizeof (struct score_it));
       build_relax_frag (fix_insts, fix_num, var_insts, var_num, 
add_symbol);
 
-      /* Insn 2: lw rD, [rD, constant]  */
-      sprintf (tmp, "lw r%d, [r%d, %d]", reg_rd, reg_rd, add_number);
+      /* Insn 2 or Insn 3: lw/st rD, [r1, constant]  */
+      sprintf (tmp, "%s r%d, [%s, %d]", insn_name, reg_rd, "r1", 
add_number);
       if (append_insn (tmp, TRUE) == (int) FAIL)
-       return;
+        return;
 
-     /* Set bwarn as -1, so macro instruction itself will not be 
generated frag.  */
-     inst.bwarn = -1;
+      /* Set bwarn as -1, so macro instruction itself will not be 
generated frag.  */
+      inst.bwarn = -1;
     }
   else
     {
-      int hi = (add_number >> 16) & 0x0000FFFF;
-      int lo = add_number & 0x0000FFFF;
-
-      /* Insn 1: lw rD, <sym>($gp)    (BFD_RELOC_SCORE_GOT15)  */
-      sprintf (tmp, "lw_pic r%d, %s", reg_rd, add_symbol->bsym->name);
-      if (append_insn (tmp, TRUE) == (int) FAIL)
-       return;
-
-      /* Insn 2  */
-      fix_num = 1;
-      var_num = 1;
-      /* Fix part
-        For an external symbol: ldis r1, HI%<constant>  */
-      sprintf (tmp, "ldis %s, %d", "r1", hi);
-      if (append_insn (tmp, FALSE) == (int) FAIL)
-       return;
-
-      memcpy (&fix_insts[0], &inst, sizeof (struct score_it));
-
-      /* Var part
-        For a local symbol: ldis r1, HI%<constant>
-         but, if lo is outof 16 bit, make hi plus 1  */
-      if ((lo < -0x8000) || (lo > 0x7fff))
-       {
-         hi += 1;
-       }
-      sprintf (tmp, "ldis_pic %s, %d", "r1", hi);
-      if (append_insn (tmp, FALSE) == (int) FAIL)
-       return;
-
-      memcpy (&var_insts[0], &inst, sizeof (struct score_it));
-      build_relax_frag (fix_insts, fix_num, var_insts, var_num, 
add_symbol);
-
-      /* Insn 3  */
-      fix_num = 1;
-      var_num = 1;
-      /* Fix part
-        For an external symbol: ori r1, LO%<constant>  */
-      sprintf (tmp, "ori %s, %d", "r1", lo);
-      if (append_insn (tmp, FALSE) == (int) FAIL)
-       return;
-
-      memcpy (&fix_insts[0], &inst, sizeof (struct score_it));
-
-      /* Var part
-        For a local symbol: addi r1, <sym>+LO%<constant> 
(BFD_RELOC_GOT_LO16)  */
-      sprintf (tmp, "addi_u_pic %s, %s + %d", "r1", 
add_symbol->bsym->name, lo);
-      if (append_insn (tmp, FALSE) == (int) FAIL)
-       return;
-
-      memcpy (&var_insts[0], &inst, sizeof (struct score_it));
-      build_relax_frag (fix_insts, fix_num, var_insts, var_num, 
add_symbol);
-
-      /* Insn 4: add rD, rD, r1  */
-      sprintf (tmp, "add r%d, r%d, %s", reg_rd, reg_rd, "r1");
-      if (append_insn (tmp, TRUE) == (int) FAIL)
-       return;
-
-     /* Set bwarn as -1, so macro instruction itself will not be 
generated frag.  */
-     inst.bwarn = -1;
-
-      /* Insn 5: lw rD, [rD, 0]  */
-      sprintf (tmp, "lw r%d, [r%d, 0]", reg_rd, reg_rd);
-      if (append_insn (tmp, TRUE) == (int) FAIL)
-       return;
-
-     /* Set bwarn as -1, so macro instruction itself will not be 
generated frag.  */
-     inst.bwarn = -1;
+      inst.error = _("PIC code offset overflow (max 16 signed bits)");
+      return;
     }
 
   nor1 = r1_bak;
@@ -4354,8 +4290,10 @@ do_macro_ldst_label (char *str)
 
       if (score_pic == PIC)
         {
-         build_lw_pic (reg_rd, inst.reloc.exp);
-         return;
+          int ldst_idx = 0;
+          ldst_idx = inst.instruction & OPC_PSEUDOLDST_MASK;
+          build_lwst_pic (reg_rd, inst.reloc.exp, 
score_ldst_insns[ldst_idx * 3 + 0].template);
+          return;
         }
       else
        {
@@ -5006,9 +4944,17 @@ score_relax_frag (asection * sec ATTRIBU
     {
       if (!word_align_p)
         {
-          fragp->insn_addr += 2;
-          grows += 2;
-       }
+          if (fragp->insn_addr < 2)
+            {
+              fragp->insn_addr += 2;
+              grows += 2;
+            }
+          else
+            {
+              fragp->insn_addr -= 2;
+              grows -= 2;
+            }
+        }
 
       if (fragp->fr_opcode)
        fragp->fr_fix = RELAX_NEW (fragp->fr_subtype) + fragp->insn_addr;
@@ -6291,7 +6237,7 @@ s_score_cpload (int ignore ATTRIBUTE_UNU
 static void
 s_score_cprestore (int ignore ATTRIBUTE_UNUSED)
 {
-#define SCORE_BP_REG  2
+  int reg;
   int cprestore_offset;
   char insn_str[MAX_LITERAL_POOL_SIZE];
 
@@ -6302,11 +6248,43 @@ s_score_cprestore (int ignore ATTRIBUTE_
       return;
     }
 
+  if ((reg = reg_required_here (&input_line_pointer, -1, REG_TYPE_SCORE)) 
== (int) FAIL
+      || skip_past_comma (&input_line_pointer) == (int) FAIL)
+    {
+      return;
+    }
+
   cprestore_offset = get_absolute_expression ();
 
-  sprintf (insn_str, "sw r%d, [r%d, %d]", GP, SCORE_BP_REG, 
cprestore_offset);
-  if (append_insn (insn_str, TRUE) == (int) FAIL)
-    return;
+  if (cprestore_offset <= 0x3fff)
+    {
+      sprintf (insn_str, "sw r%d, [r%d, %d]", GP, reg, cprestore_offset);
+      if (append_insn (insn_str, TRUE) == (int) FAIL)
+        return;
+    }
+  else
+    {
+      int r1_bak;
+
+      r1_bak = nor1;
+      nor1 = 0;
+
+      sprintf (insn_str, "li r1, %d", cprestore_offset);
+      if (append_insn (insn_str, TRUE) == (int) FAIL)
+        return;
+
+      sprintf (insn_str, "add r1, r1, r%d", reg);
+      if (append_insn (insn_str, TRUE) == (int) FAIL)
+        return;
+
+      sprintf (insn_str, "sw r%d, [r1]", GP);
+      if (append_insn (insn_str, TRUE) == (int) FAIL)
+        return;
+
+      nor1 = r1_bak;
+    }
+
+  demand_empty_rest_of_line ();
 }
 
 /* Handle the .gpword pseudo-op.  This is used when generating PIC



Best regards
                     Ligang

Attachment: diffs.tar.bz2
Description: Binary data


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]