diff options
author | Marcus Comstedt <marcus@mc.pp.se> | 2021-01-05 22:50:32 +0100 |
---|---|---|
committer | Nelson Chu <nelson.chu@sifive.com> | 2021-01-06 17:57:52 +0800 |
commit | fbc09e7af715f19f6e5c700a9df6d13cdd05e1e5 (patch) | |
tree | b7cfb144e27508c018d5ea332e56d36548216e9b /gas | |
parent | 865288236d881acecdcf0aaa636fd28fd811d862 (diff) | |
download | binutils-gdb-fbc09e7af715f19f6e5c700a9df6d13cdd05e1e5.tar.gz |
RISC-V: Implement support for big endian targets.
RISC-V instruction/code is always little endian, but data might be
big-endian. Therefore, we can not use the original bfd_get/bfd_put
to get/put the code for big endian targets. Add new riscv_get_insn
and riscv_put_insn to always get/put code as little endian can resolve
the problem. Just remember to update them once we have supported
the 48-bit/128-bit instructions in the future patches.
bfd/
* config.bfd: Added targets riscv64be*-*-*, riscv32be*-*-* and
riscvbe*-*-*. Also added riscv_elf[32|64]_be_vec.
* configure.ac: Handle riscv_elf[32|64]_be_vec.
* configure: Regenerate.
* elfnn-riscv.c: Include <limits.h> and define CHAR_BIT for
riscv_is_insn_reloc.
(riscv_get_insn): RISC-V instructions are always little endian, but
bfd_get may be used for big-endian, so add new riscv_get_insn to handle
the insturctions.
(riscv_put_insn): Likewsie.
(riscv_is_insn_reloc): Check if we are relocaing an instruction.
(perform_relocation): Call riscv_is_insn_reloc to decide if we should
use riscv_[get|put]_insn or bfd_[get|put].
(riscv_zero_pcrel_hi_reloc): Use riscv_[get|put]_insn, bfd_[get|put]l32
or bfd_[get|put]l16 for code.
(riscv_elf_relocate_section): Likewise.
(riscv_elf_finish_dynamic_symbol): Likewise.
(riscv_elf_finish_dynamic_sections): Likewise.
(_bfd_riscv_relax_call): Likewise.
(_bfd_riscv_relax_lui): Likewise.
(_bfd_riscv_relax_align): Likewise.
(_bfd_riscv_relax_pc): Likewise.
(riscv_elf_object_p): Handled for big endian.
(TARGET_BIG_SYM, TARGET_BIG_NAME): Defined.
* targets.c: Add riscv_elf[32|64]_be_vec.
(_bfd_target_vector): Likewise.
gas/
* config/tc-riscv.c (riscv_target_format): Add elf64-bigriscv and
elf32-bigriscv.
(install_insn): Always write instructions as little endian.
(riscv_make_nops): Likewise.
(md_convert_frag_branch): Likewise.
(md_number_to_chars): Write data in target endianness.
(options, md_longopts): Add -mbig-endian and -mlittle-endian options.
(md_parse_option): Handle the endian options.
* config/tc-riscv.h: Only define TARGET_BYTES_BIG_ENDIAN if not
already defined.
* configure.tgt: Added riscv64be*, riscv32be*, riscvbe*.
ld/
* configure.tgt: Added riscvbe-*-*, riscv32be*-*-*, riscv64be*-*-*,
riscv32be*-*-linux*, and riscv64be*-*-linux*.
* Makefile.am: Added eelf32briscv.c, eelf32briscv_ilp32f.c and
eelf32briscv_ilp32.c.
* Makefile.in: Regenerate.
* emulparams/elf32briscv.sh: Added.
* emulparams/elf32briscv_ilp32.sh: Likewise.
* emulparams/elf32briscv_ilp32f.sh: Likewise.
* emulparams/elf64briscv.sh: Likewise.
* emulparams/elf64briscv_lp64.sh: Likewise.
* emulparams/elf64briscv_lp64f.sh: Likewise.
Diffstat (limited to 'gas')
-rw-r--r-- | gas/ChangeLog | 14 | ||||
-rw-r--r-- | gas/config/tc-riscv.c | 32 | ||||
-rw-r--r-- | gas/config/tc-riscv.h | 2 | ||||
-rw-r--r-- | gas/configure.tgt | 4 |
4 files changed, 44 insertions, 8 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog index 03ea1a1c9c3..57bc038a563 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,17 @@ +2021-01-06 Marcus Comstedt <marcus@mc.pp.se> + + * config/tc-riscv.c (riscv_target_format): Add elf64-bigriscv and + elf32-bigriscv. + (install_insn): Always write instructions as little endian. + (riscv_make_nops): Likewise. + (md_convert_frag_branch): Likewise. + (md_number_to_chars): Write data in target endianness. + (options, md_longopts): Add -mbig-endian and -mlittle-endian options. + (md_parse_option): Handle the endian options. + * config/tc-riscv.h: Only define TARGET_BYTES_BIG_ENDIAN if not + already defined. + * configure.tgt: Added riscv64be*, riscv32be*, riscvbe*. + 2021-01-04 H.J. Lu <hongjiu.lu@intel.com> PR ld/26256 diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c index e938a8812d9..55d5f1b50d9 100644 --- a/gas/config/tc-riscv.c +++ b/gas/config/tc-riscv.c @@ -445,7 +445,10 @@ static char *expr_end; const char * riscv_target_format (void) { - return xlen == 64 ? "elf64-littleriscv" : "elf32-littleriscv"; + if (target_big_endian) + return xlen == 64 ? "elf64-bigriscv" : "elf32-bigriscv"; + else + return xlen == 64 ? "elf64-littleriscv" : "elf32-littleriscv"; } /* Return the length of instruction INSN. */ @@ -474,7 +477,7 @@ static void install_insn (const struct riscv_cl_insn *insn) { char *f = insn->frag->fr_literal + insn->where; - md_number_to_chars (f, insn->insn_opcode, insn_length (insn)); + number_to_chars_littleendian (f, insn->insn_opcode, insn_length (insn)); } /* Move INSN to offset WHERE in FRAG. Adjust the fixups accordingly @@ -2662,7 +2665,10 @@ md_atof (int type, char *litP, int *sizeP) void md_number_to_chars (char *buf, valueT val, int n) { - number_to_chars_littleendian (buf, val, n); + if (target_big_endian) + number_to_chars_bigendian (buf, val, n); + else + number_to_chars_littleendian (buf, val, n); } const char *md_shortopts = "O::g::G:"; @@ -2681,6 +2687,8 @@ enum options OPTION_NO_CSR_CHECK, OPTION_MISA_SPEC, OPTION_MPRIV_SPEC, + OPTION_BIG_ENDIAN, + OPTION_LITTLE_ENDIAN, OPTION_END_OF_ENUM }; @@ -2699,6 +2707,8 @@ struct option md_longopts[] = {"mno-csr-check", no_argument, NULL, OPTION_NO_CSR_CHECK}, {"misa-spec", required_argument, NULL, OPTION_MISA_SPEC}, {"mpriv-spec", required_argument, NULL, OPTION_MPRIV_SPEC}, + {"mbig-endian", no_argument, NULL, OPTION_BIG_ENDIAN}, + {"mlittle-endian", no_argument, NULL, OPTION_LITTLE_ENDIAN}, {NULL, no_argument, NULL, 0} }; @@ -2777,6 +2787,14 @@ md_parse_option (int c, const char *arg) case OPTION_MPRIV_SPEC: return riscv_set_default_priv_spec (arg); + case OPTION_BIG_ENDIAN: + target_big_endian = 1; + break; + + case OPTION_LITTLE_ENDIAN: + target_big_endian = 0; + break; + default: return 0; } @@ -3258,13 +3276,13 @@ riscv_make_nops (char *buf, bfd_vma bytes) /* Use at most one 2-byte NOP. */ if ((bytes - i) % 4 == 2) { - md_number_to_chars (buf + i, RVC_NOP, 2); + number_to_chars_littleendian (buf + i, RVC_NOP, 2); i += 2; } /* Fill the remainder with 4-byte NOPs. */ for ( ; i < bytes; i += 4) - md_number_to_chars (buf + i, RISCV_NOP, 4); + number_to_chars_littleendian (buf + i, RISCV_NOP, 4); } /* Called from md_do_align. Used to create an alignment frag in a @@ -3468,14 +3486,14 @@ md_convert_frag_branch (fragS *fragp) insn = bfd_getl32 (buf); insn ^= MATCH_BEQ ^ MATCH_BNE; insn |= ENCODE_SBTYPE_IMM (8); - md_number_to_chars ((char *) buf, insn, 4); + bfd_putl32 (insn, buf); buf += 4; jump: /* Jump to the target. */ fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal, 4, &exp, FALSE, BFD_RELOC_RISCV_JMP); - md_number_to_chars ((char *) buf, MATCH_JAL, 4); + bfd_putl32 (MATCH_JAL, buf); buf += 4; break; diff --git a/gas/config/tc-riscv.h b/gas/config/tc-riscv.h index a503fc52437..6f202887b29 100644 --- a/gas/config/tc-riscv.h +++ b/gas/config/tc-riscv.h @@ -28,7 +28,9 @@ struct frag; struct expressionS; +#ifndef TARGET_BYTES_BIG_ENDIAN #define TARGET_BYTES_BIG_ENDIAN 0 +#endif #define TARGET_ARCH bfd_arch_riscv diff --git a/gas/configure.tgt b/gas/configure.tgt index b17336bfa4f..6f46e0a6329 100644 --- a/gas/configure.tgt +++ b/gas/configure.tgt @@ -89,7 +89,9 @@ case ${cpu} in pj*) cpu_type=pj endian=big ;; powerpc*le*) cpu_type=ppc endian=little ;; powerpc*) cpu_type=ppc endian=big ;; + riscv64be*) cpu_type=riscv endian=big arch=riscv64 ;; riscv64*) cpu_type=riscv endian=little arch=riscv64 ;; + riscv32be*|riscvbe*) cpu_type=riscv endian=big arch=riscv32 ;; riscv32* | riscv*) cpu_type=riscv endian=little arch=riscv32 ;; rs6000*) cpu_type=ppc ;; rl78*) cpu_type=rl78 ;; @@ -357,7 +359,7 @@ case ${generic_target} in pru-*-*) fmt=elf ;; - riscv*-*-*) fmt=elf endian=little ;; + riscv*-*-*) fmt=elf ;; rx-*-linux*) fmt=elf em=linux ;; |