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