[linux-unicore] [PATCH binutils] add ldw reg, label support and .word relocation

  • From: LIU Zhiyou <liuzhiyou.cs@xxxxxxxxx>
  • To: gxt@xxxxxxxxxxxxxxx
  • Date: Fri, 15 Feb 2013 14:08:50 +0800

Signed-off-by: LIU Zhiyou <liuzhiyou.cs@xxxxxxxxx>
---
 bfd/bfd-in2.h                  |   4 ++
 bfd/elf32-unicore32.c          | 100 ++++++++++++++++++++++++++--
 bfd/libbfd.h                   |   2 +
 bfd/reloc.c                    |   7 +-
 gas/config/tc-unicore32.c      | 148 +++++++++++++++++++++++++++++++++++++----
 include/elf/unicore32.h        |  33 +++++++++
 include/opcode/unicore32-opc.h |  14 ++++
 include/opcode/unicore32.h     |   5 ++
 8 files changed, 295 insertions(+), 18 deletions(-)
 create mode 100644 include/elf/unicore32.h

diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 8db0901..898a280 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -5506,6 +5506,10 @@ giving a 16 bit signed byte offset.  */
 
 /* Adapteva EPIPHANY - 8 bit immediate for 16 bit mov instruction.  */
   BFD_RELOC_EPIPHANY_IMM8,
+
+/* UniCore32 Relocations.  */
+  BFD_RELOC_UNICORE32_ABS32,
+  BFD_RELOC_UNICORE32_IMM14,
   BFD_RELOC_UNUSED };
 typedef enum bfd_reloc_code_real bfd_reloc_code_real_type;
 reloc_howto_type *bfd_reloc_type_lookup
diff --git a/bfd/elf32-unicore32.c b/bfd/elf32-unicore32.c
index 40c30c6..5dd499b 100644
--- a/bfd/elf32-unicore32.c
+++ b/bfd/elf32-unicore32.c
@@ -10,20 +10,109 @@
 #include "elf-bfd.h"
 #include "libiberty.h"
 
+#include "elf/unicore32.h"
+
+/* unicore32_reloc_map array maps BFD relocation
+   enum into a UniCore32 GAS relocation type.  */
+
+struct unicore32_reloc_map
+{
+  bfd_reloc_code_real_type bfd_reloc_enum; /* BFD relocation enum.  */
+  unsigned short unicore32_reloc_type;     /* UniCore32 relocation type. */
+};
+
+#define MAP_RELOC(name) {BFD_RELOC_UNICORE32_##name, R_UNICORE32_##name},
+
+static const struct unicore32_reloc_map unicore32_reloc_map[R_UNICORE32_MAX] =
+{
+    {BFD_RELOC_NONE,           R_UNICORE32_NONE},
+    MAP_RELOC(ABS32)
+    MAP_RELOC(IMM14)
+};
+
+static reloc_howto_type unicore32_elf_howto_table[] =
+{
+  HOWTO (R_UNICORE32_NONE,         /* type */
+         0,                        /* rightshift */
+         4,                        /* size */
+         32,                       /* bitsize */
+         FALSE,                    /* pc_relative */
+         0,                        /* bitpos */
+         complain_overflow_dont,   /* complain_on_overflow */
+         bfd_elf_generic_reloc,    /* special_function */
+         "R_UNICORE32_NONE",       /* name */
+         FALSE,                    /* partial_inplace */
+         0,                        /* src_mask */
+         0,                        /* dst_mask */
+         FALSE),                   /* pcrel_offset */
+
+  HOWTO (R_UNICORE32_ABS32,        /* type */
+         0,                        /* rightshift */
+         4,                        /* size */
+         32,                        /* bitsize */
+         FALSE,                    /* pc_relative */
+         0,                        /* bitpos */
+         complain_overflow_bitfield,/* complain_on_overflow */
+         bfd_elf_generic_reloc,    /* special_function */
+         "R_UNICORE32_ABS32",      /* name */
+         FALSE,                    /* partial_inplace */
+         0x0,                      /* src_mask */
+         0xffffffff,               /* dst_mask */
+         FALSE),                   /* pcrel_offset */
+
+  HOWTO (R_UNICORE32_IMM14,        /* type */
+         0,                        /* rightshift */
+         4,                        /* size */
+         14,                        /* bitsize */
+         TRUE,                    /* pc_relative */
+         0,                        /* bitpos */
+         complain_overflow_bitfield,/* complain_on_overflow */
+         bfd_elf_generic_reloc,    /* special_function */
+         "R_UNICORE32_IMM14",      /* name */
+         FALSE,                    /* partial_inplace */
+         0x0,                      /* src_mask */
+         0x3fff,                     /* dst_mask */
+         FALSE),                   /* pcrel_offset */
+};
 
 /* Stub */
 static reloc_howto_type *
 elf_unicore32_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
-                            bfd_reloc_code_real_type code ATTRIBUTE_UNUSED) {
-    return NULL;
+                            bfd_reloc_code_real_type code) {
+  unsigned int i;
+
+  for (i = 0; i < R_UNICORE32_MAX; i++)
+    if (code == unicore32_reloc_map[i].bfd_reloc_enum)
+      return 
&unicore32_elf_howto_table[unicore32_reloc_map[i].unicore32_reloc_type];
+
+  _bfd_error_handler ("Unsupported UniCore32 relocation type: 0x%x\n", code);
+  return NULL;
 }
 
 /* Stub */
 static reloc_howto_type *
 elf_unicore32_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
-                            const char *r_name ATTRIBUTE_UNUSED)
+                            const char *r_name)
 {
-    return NULL;
+  unsigned int i;
+
+  for (i = 0; ARRAY_SIZE (unicore32_elf_howto_table); i++)
+    if (unicore32_elf_howto_table[i].name != NULL
+        && strcasecmp (unicore32_elf_howto_table[i].name, r_name) == 0)
+      return unicore32_elf_howto_table + i;
+
+  return NULL;
+}
+
+/* Retrieve a howto ptr using an internal relocation entry.  */
+static void
+elf_unicore32_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr,
+                        Elf_Internal_Rela *dst)
+{
+  unsigned int r_type = ELF32_R_TYPE (dst->r_info);
+
+  BFD_ASSERT (r_type < (unsigned int) R_UNICORE32_MAX);
+  cache_ptr->howto = unicore32_elf_howto_table + r_type;
 }
 
 #define ELF_ARCH                       bfd_arch_unicore32
@@ -36,4 +125,7 @@ elf_unicore32_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
 #define bfd_elf32_bfd_reloc_type_lookup   elf_unicore32_reloc_type_lookup
 #define bfd_elf32_bfd_reloc_name_lookup   elf_unicore32_reloc_name_lookup
 
+#define elf_info_to_howto                 elf_unicore32_info_to_howto
+#define elf_info_to_howto_rel             0
+
 #include "elf32-target.h"
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index 0458e39..10e8be1 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -2673,6 +2673,8 @@ static const char *const bfd_reloc_code_real_names[] = { 
"@@uninitialized@@",
   "BFD_RELOC_EPIPHANY_SIMM11",
   "BFD_RELOC_EPIPHANY_IMM11",
   "BFD_RELOC_EPIPHANY_IMM8",
+  "BFD_RELOC_UNICORE32_ABS32",
+  "BFD_RELOC_UNICORE32_IMM14",
  "@@overflow: BFD_RELOC_UNUSED@@",
 };
 #endif
diff --git a/bfd/reloc.c b/bfd/reloc.c
index e097887..19401a4 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -6571,7 +6571,12 @@ ENUM
   BFD_RELOC_EPIPHANY_IMM8
 ENUMDOC
   Adapteva EPIPHANY - 8 bit immediate for 16 bit mov instruction.
-
+ENUM
+  BFD_RELOC_UNICORE32_ABS32
+ENUMX
+  BFD_RELOC_UNICORE32_IMM14
+ENUMDOC
+  UniCore32 Relocations.
 
 ENDSENUM
   BFD_RELOC_UNUSED
diff --git a/gas/config/tc-unicore32.c b/gas/config/tc-unicore32.c
index 9ccc396..570549e 100644
--- a/gas/config/tc-unicore32.c
+++ b/gas/config/tc-unicore32.c
@@ -24,6 +24,7 @@
 #include "safe-ctype.h"
 #include "dwarf2dbg.h"
 #include "opcode/unicore32.h"
+#include "elf/unicore32.h"
 
 /* Word is considered here as a 16-bit unsigned short int.  */
 #define WORD_SHIFT  32
@@ -37,7 +38,7 @@
 /* Maximum bits which may be set in a `mask16' operand.  */
 #define MAX_REGS_IN_MASK16  16
 
-const char comment_chars[]        = ";";
+const char comment_chars[]        = "@";
 const char line_comment_chars[]   = ";";
 const char line_separator_chars[] = ";";
 /* Don't know what they are yet */
@@ -51,8 +52,28 @@ struct option md_longopts[] =
 size_t md_longopts_size = sizeof (md_longopts);
 const pseudo_typeS md_pseudo_table[] =
 {
-  {0, 0, 0}
+  {"word", cons,  4 },
+  {0, 0, 0},
 };
+static int ATTRIBUTE_PRINTF_1
+debug (const char *string, ...)
+{
+  if (flag_debug)
+    {
+      char str[256];
+
+      VA_OPEN (argptr, string);
+      VA_FIXEDARG (argptr, const char *, string);
+      vsnprintf (str, 256, string, argptr);
+      VA_CLOSE (argptr);
+      if (str[0] == '\0')
+       return (0);
+      fputs (str, stderr);
+      return strlen (str);
+    }
+  else
+    return 0;
+}
 
 static unsigned long get_inst_field(inst const *ainst, inst_fields field);
 static void set_inst_field(inst *ainst, inst_fields field, unsigned long 
value);
@@ -79,9 +100,9 @@ static int handle_arguments(inst* ainst,
         if (!this->args[i].from_str(ainst,
                                     ainst->args+i,
                                     i,
-                                    ops))
+                                    ops)) {
             return 0;
-        else {
+        } else {
             ainst->args[i].type = this->args+i;
             this->args[i].set_field(ainst, ainst->args+i);
         }
@@ -89,11 +110,18 @@ static int handle_arguments(inst* ainst,
     return 1;
 }
 
-static int assemble_inst_arith(inst *ainst,const inst_type* this, char **ops) {
+static int assemble_inst_default(inst *ainst, const inst_type* this, char** 
ops)
+{
     ainst->raw = 0;
     if (!handle_arguments(ainst, this, ops))
         return 0;
     ainst->raw |= this->expect;
+    return 1;
+}
+
+static int assemble_inst_arith(inst *ainst,const inst_type* this, char **ops) {
+    if (!assemble_inst_default(ainst, this, ops))
+        return 0;
     if (endwith(ops[0], ".a"))
         ainst->raw |= inst_mask[InstField_S];
     return 1;
@@ -102,10 +130,8 @@ static int assemble_inst_arith(inst *ainst,const 
inst_type* this, char **ops) {
 static int assemble_inst_ldst(inst *ainst,
                               const inst_type* this ATTRIBUTE_UNUSED,
                               char **ops) {
-    ainst->raw = 0;
-    if (!handle_arguments(ainst, this, ops))
+    if (!assemble_inst_default(ainst, this, ops))
         return 0;
-    ainst->raw |= this->expect;
     unsigned long is_post = get_inst_field(ainst, InstField_P);
     unsigned long w_map[][2] = {
         {1, 0}, // !is_post
@@ -151,7 +177,8 @@ static int argfrom_str_r(inst* ainst ATTRIBUTE_UNUSED,
         arg->ucontent.areg = first_gpreg + reg_idx;
         if (is_gpreg(arg->ucontent.areg))
             return 1;
-        else return 0;
+        else
+            return 0;
     }
 }
 
@@ -262,6 +289,28 @@ static int argfrom_str_rbase(inst* ainst,
     arg->ucontent.areg = reg_idx;
     return 1;
 }
+
+static int argfrom_str_ldst_symbol(inst* ainst,
+                              argument* arg,
+                              int index,
+                             char** ops) {
+    // always using pc as base register
+    set_inst_field(ainst, InstField_Rn, r31);
+
+    char *saved_input_line_pointer = input_line_pointer;
+    input_line_pointer = ops[index+1];
+    expression (&ainst->exp);
+    input_line_pointer = saved_input_line_pointer;
+    debug("In argfrom_str_ldst_symbol, ainst->exp.X_op = %d\n",
+           ainst->exp.X_op);
+    if (ainst->exp.X_op != O_symbol)
+        return 0;
+    // set offset to zero, fixup will fix it for us.
+    arg->ucontent.uimm = 0;
+    ainst->rtype = BFD_RELOC_UNICORE32_IMM14;
+    return 1;
+}
+
 #include "opcode/unicore32-opc.h"
 
 int
@@ -325,12 +374,20 @@ md_assemble (char * str)
     outplace_split_params(ops, str);
     inst ainst;
     for (i = 0; i < NUMINST; i++) {
+        ainst.rtype = BFD_RELOC_NONE;
         if (start_with(ops[0], inst_types[i].prefix) &&
             inst_types[i].assemble(&ainst, inst_types+i, ops))
         {
-            dwarf2_emit_insn (0);
             char *this_frag = frag_more(4);
             md_number_to_chars (this_frag, (valueT) ainst.raw, 4);
+            int pc_relative = bfd_reloc_type_lookup
+                (stdoutput, ainst.rtype)->pc_relative;
+            if (ainst.rtype != BFD_RELOC_NONE) {
+                fix_new_exp (frag_now, this_frag - frag_now->fr_literal,
+                             4, &ainst.exp, pc_relative, ainst.rtype);
+            }
+            dwarf2_emit_insn (0);
+            debug("pick inst type %s\n", inst_types[i].name);
             return ;
         }
     }
@@ -381,18 +438,83 @@ arelent *
 tc_gen_reloc (asection *section ATTRIBUTE_UNUSED,
               fixS * fixP ATTRIBUTE_UNUSED)
 {
-    return NULL;
+    debug("entering tc_gen_reloc with symbol:%s\n",
+          S_GET_NAME(fixP->fx_addsy));
+    reloc_howto_type *reloc_howto;
+    reloc_howto = bfd_reloc_type_lookup(stdoutput, fixP->fx_r_type);
+    debug("reloc type:%s\n", reloc_howto->name);
+    arelent * reloc;
+    reloc = xmalloc (sizeof (arelent));
+    reloc->sym_ptr_ptr  = xmalloc (sizeof (asymbol *));
+    *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
+    reloc->address = fixP->fx_frag->fr_address + fixP->fx_where;
+    reloc->addend = fixP->fx_offset;
+    if (fixP->fx_subsy != NULL)
+        reloc->addend += S_GET_VALUE (fixP->fx_addsy) -
+            S_GET_VALUE (fixP->fx_subsy);
+
+    gas_assert ((int) fixP->fx_r_type > 0);
+    reloc->howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
+
+    if (reloc->howto == NULL)
+    {
+        as_bad_where (fixP->fx_file, fixP->fx_line,
+            _("internal error: reloc %d (`%s')"
+                " not supported by object file format"),
+            fixP->fx_r_type,
+            bfd_get_reloc_code_name (fixP->fx_r_type));
+        return NULL;
+    }
+    gas_assert (!fixP->fx_pcrel == !reloc->howto->pc_relative);
+
+    return reloc;
 }
 
 long
 md_pcrel_from (fixS *fixp)
 {
-  return fixp->fx_frag->fr_address + fixp->fx_where;
+  return fixp->fx_frag->fr_address + fixp->fx_where+4;
+}
+
+
+static void
+apply_fix_by_rtype (fixS *fixP,
+              valueT *valP,
+                    segT seg ATTRIBUTE_UNUSED) {
+        reloc_howto_type *reloc_howto;
+        reloc_howto = bfd_reloc_type_lookup(stdoutput, fixP->fx_r_type);
+        char *buf = fixP->fx_frag->fr_literal + fixP->fx_where;
+        valueT value = 0;
+        int i;
+        for (i = 0; i < 4; i++) {
+            value <<= 8;
+            value += (unsigned char)buf[3-i];
+        }
+        value &= ~reloc_howto->dst_mask;
+        value |= (*valP & reloc_howto->dst_mask) << reloc_howto->bitpos;
+        md_number_to_chars(buf, (valueT)value, 4);
+        fixP->fx_done = 1;
+        fixP->fx_offset = 0;
 }
 
 void
-md_apply_fix (fixS *fixP ATTRIBUTE_UNUSED,
+md_apply_fix (fixS *fixP,
               valueT *valP ATTRIBUTE_UNUSED,
               segT seg ATTRIBUTE_UNUSED)
 {
+    if (fixP->fx_r_type == BFD_RELOC_UNICORE32_IMM14) {
+        if (fixP->fx_pcrel || fixP->fx_addsy != NULL) {
+            as_bad("R_UNICORE32_IMM14 PCREL doesn't adjusted\n");
+            fixP->fx_done = 0;
+        }
+        apply_fix_by_rtype(fixP, valP, seg);
+        return;
+    } else if (fixP->fx_r_type == BFD_RELOC_32){
+        fixP->fx_r_type = BFD_RELOC_UNICORE32_ABS32;
+        if (fixP->fx_addsy || fixP->fx_subsy)
+            fixP->fx_done = 0;
+        else
+            apply_fix_by_rtype(fixP, valP, seg);
+    }
+
 }
diff --git a/include/elf/unicore32.h b/include/elf/unicore32.h
new file mode 100644
index 0000000..ce1b9f4
--- /dev/null
+++ b/include/elf/unicore32.h
@@ -0,0 +1,33 @@
+/* UniCore32 ELF support for BFD.
+   Copyright 2013 Free Software Foundation, Inc.
+   Contributed by LIU Zhiyou.
+
+   This file is part of BFD, the Binary File Descriptor library.
+
+   This program 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 of the License, or
+   (at your option) any later version.
+
+   This program 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 this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#ifndef _ELF_UNICORE32_H
+#define _ELF_UNICORE32_H
+
+#include "elf/reloc-macros.h"
+
+/* Creating indices for reloc_map_index array.  */
+START_RELOC_NUMBERS(elf_unicore32_reloc_type)
+RELOC_NUMBER (R_UNICORE32_NONE,           0)
+RELOC_NUMBER (R_UNICORE32_ABS32,          1)
+RELOC_NUMBER (R_UNICORE32_IMM14,          2)
+END_RELOC_NUMBERS(R_UNICORE32_MAX)
+
+#endif /* _ELF_UNICORE32_H */
diff --git a/include/opcode/unicore32-opc.h b/include/opcode/unicore32-opc.h
index f958b53..c87cdfd 100644
--- a/include/opcode/unicore32-opc.h
+++ b/include/opcode/unicore32-opc.h
@@ -281,6 +281,7 @@ static void print_inst_ldst(inst *ainst, struct 
disassemble_info *info) {
  * and use it in inst_types[].
  * Check the head of this file to see why */
 #ifndef TC_UNICORE32_H
+#define assemble_inst_default NULL
 #define assemble_inst_arith NULL
 #define assemble_inst_ldst NULL
 #define argfrom_str_r NULL
@@ -288,6 +289,7 @@ static void print_inst_ldst(inst *ainst, struct 
disassemble_info *info) {
 #define argfrom_str_shiftr NULL
 #define argfrom_str_uimm NULL
 #define argfrom_str_rbase NULL
+#define argfrom_str_ldst_symbol NULL
 #endif
 
 /* Macro for binary literal support */
@@ -380,6 +382,7 @@ static const inst_type inst_types[] = {
     ARITH_INS("mov", 11101),
     ARITH_INS("andn", 11110),
     ARITH_INS("not", 11111),
+
     {"", "ldst-imm14",
      B32(11100000, 00000000, 00000000, 00000000),
      B32(01100000, 00000000, 00000000, 00000000),
@@ -391,6 +394,17 @@ static const inst_type inst_types[] = {
       NO_ARG
      }
     },
+
+    {"ldw", "ldst-pc-imm14-symbol",
+     B32(11111111, 00000000, 00000000, 00000000),
+     B32(01111001, 00000000, 00000000, 00000000),
+     NULL, // never use this for disassemble ldst-imm14 will do
+     assemble_inst_default,
+     {ARG_SingleUField(InstField_Rd, NULL, argfrom_str_r),
+      ARG_SingleUField(InstField_Imm14, NULL, argfrom_str_ldst_symbol),
+      NO_ARG,
+      NO_ARG}
+    },
 };
 static const long NUMINST = ARRAY_SIZE(inst_types);
 
diff --git a/include/opcode/unicore32.h b/include/opcode/unicore32.h
index a108269..eb7f960 100644
--- a/include/opcode/unicore32.h
+++ b/include/opcode/unicore32.h
@@ -220,6 +220,11 @@ struct _inst{
     unsigned long raw; /* Binary representation of instruction */
     const inst_type  *type;
     argument args[MAX_ARG];
+#ifdef TC_UNICORE32_H
+    /* Expression used for setting the fixups (if any).  */
+    expressionS exp;
+    bfd_reloc_code_real_type rtype;
+#endif /* TC_UNICORE32_H */
 };
 
 #define PRINT_BUFFER_SIZE 256
-- 
1.8.1.1


Other related posts:

  • » [linux-unicore] [PATCH binutils] add ldw reg, label support and .word relocation - LIU Zhiyou