From f3b1d520e47415544742a379f2236671e96cc80e Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Thu, 8 Oct 2015 16:06:15 -0700 Subject: binutils: relax LUI to C.LUI --- binutils/bfd/elfnn-riscv.c | 50 ++++++++++++++++++++++++++++++++--------- binutils/bfd/elfxx-riscv.c | 16 +++++++++++++ binutils/include/elf/riscv.h | 1 + binutils/include/opcode/riscv.h | 5 +++++ patches/binutils | 3 ++- 5 files changed, 64 insertions(+), 11 deletions(-) diff --git a/binutils/bfd/elfnn-riscv.c b/binutils/bfd/elfnn-riscv.c index 67f0d87..bd086d6 100644 --- a/binutils/bfd/elfnn-riscv.c +++ b/binutils/bfd/elfnn-riscv.c @@ -1531,6 +1531,12 @@ perform_relocation (const reloc_howto_type *howto, value = ENCODE_RVC_J_IMM (value); break; + case R_RISCV_RVC_LUI: + if (!VALID_RVC_LUI_IMM (RISCV_CONST_HIGH_PART (value))) + return bfd_reloc_overflow; + value = ENCODE_RVC_LUI_IMM (RISCV_CONST_HIGH_PART (value)); + break; + case R_RISCV_32: case R_RISCV_64: case R_RISCV_ADD8: @@ -1800,9 +1806,10 @@ riscv_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, /* These require nothing of us at all. */ continue; + case R_RISCV_HI20: case R_RISCV_BRANCH: case R_RISCV_RVC_BRANCH: - case R_RISCV_HI20: + case R_RISCV_RVC_LUI: /* These require no special handling beyond perform_relocation. */ break; @@ -2712,19 +2719,42 @@ _bfd_riscv_relax_lui (bfd *abfd, asection *sec, bfd_vma symval, bfd_boolean *again) { + bfd_byte *contents = elf_section_data (sec)->this_hdr.contents; bfd_vma gp = riscv_global_pointer_value (link_info); + int use_rvc = elf_elfheader (abfd)->e_flags & EF_RISCV_RVC; - /* Bail out if this symbol isn't in range of either gp or x0. */ - if (!VALID_ITYPE_IMM (symval - gp) && !(symval < RISCV_IMM_REACH/2)) - return TRUE; - - /* We can delete the unnecessary AUIPC. The corresponding LO12 reloc - will be converted to GPREL during relocation. */ BFD_ASSERT (rel->r_offset + 4 <= sec->size); - rel->r_info = ELFNN_R_INFO (0, R_RISCV_NONE); - *again = TRUE; - return riscv_relax_delete_bytes (abfd, sec, rel->r_offset, 4); + /* Is the reference in range of x0 or gp? */ + if (VALID_ITYPE_IMM (symval - gp) || (symval < RISCV_IMM_REACH/2)) + { + /* We can delete the unnecessary AUIPC. The corresponding LO12 reloc + will be converted to gp- or x0-relative during relocation. */ + rel->r_info = ELFNN_R_INFO (0, R_RISCV_NONE); + + *again = TRUE; + return riscv_relax_delete_bytes (abfd, sec, rel->r_offset, 4); + } + + /* Can we relax LUI to C.LUI? Alignment might move the section forward; + account for this assuming page alignment at worst. */ + if (use_rvc + && VALID_RVC_LUI_IMM (RISCV_CONST_HIGH_PART (symval)) + && VALID_RVC_LUI_IMM (RISCV_CONST_HIGH_PART (symval + ELF_MAXPAGESIZE))) + { + /* Replace LUI with C.LUI. */ + bfd_vma lui = bfd_get_32 (abfd, contents + rel->r_offset); + lui = (lui & (OP_MASK_RD << OP_SH_RD)) | MATCH_C_LUI; + bfd_put_32 (abfd, lui, contents + rel->r_offset); + + /* Replace the R_RISCV_HI20 reloc. */ + rel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (rel->r_info), R_RISCV_RVC_LUI); + + *again = TRUE; + return riscv_relax_delete_bytes (abfd, sec, rel->r_offset + 2, 2); + } + + return TRUE; } /* Relax non-PIC TLS references. */ diff --git a/binutils/bfd/elfxx-riscv.c b/binutils/bfd/elfxx-riscv.c index 6053a74..447b791 100644 --- a/binutils/bfd/elfxx-riscv.c +++ b/binutils/bfd/elfxx-riscv.c @@ -674,6 +674,21 @@ static reloc_howto_type howto_table[] = 0, /* src_mask */ ENCODE_RVC_J_IMM (-1U), /* dst_mask */ TRUE), /* pcrel_offset */ + + /* High 6 bits of 18-bit absolute address. */ + HOWTO (R_RISCV_RVC_LUI, /* type */ + 0, /* rightshift */ + 2, /* size */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_RISCV_RVC_LUI", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + ENCODE_RVC_IMM (-1U), /* dst_mask */ + FALSE), /* pcrel_offset */ }; /* A mapping from BFD reloc types to RISC-V ELF reloc types. */ @@ -723,6 +738,7 @@ static const struct elf_reloc_map riscv_reloc_map[] = { BFD_RELOC_RISCV_ALIGN, R_RISCV_ALIGN }, { BFD_RELOC_RISCV_RVC_BRANCH, R_RISCV_RVC_BRANCH }, { BFD_RELOC_RISCV_RVC_JUMP, R_RISCV_RVC_JUMP }, + { BFD_RELOC_RISCV_RVC_LUI, R_RISCV_RVC_LUI }, }; /* Given a BFD reloc type, return a howto structure. */ diff --git a/binutils/include/elf/riscv.h b/binutils/include/elf/riscv.h index b066951..c250b65 100644 --- a/binutils/include/elf/riscv.h +++ b/binutils/include/elf/riscv.h @@ -76,6 +76,7 @@ START_RELOC_NUMBERS (elf_riscv_reloc_type) RELOC_NUMBER (R_RISCV_ALIGN, 43) RELOC_NUMBER (R_RISCV_RVC_BRANCH, 44) RELOC_NUMBER (R_RISCV_RVC_JUMP, 45) + RELOC_NUMBER (R_RISCV_RVC_LUI, 46) END_RELOC_NUMBERS (R_RISCV_max) /* Processor specific flags for the ELF header e_flags field. */ diff --git a/binutils/include/opcode/riscv.h b/binutils/include/opcode/riscv.h index 5e13826..dd30c64 100644 --- a/binutils/include/opcode/riscv.h +++ b/binutils/include/opcode/riscv.h @@ -71,6 +71,8 @@ static const char * const riscv_pred_succ[16] = { ((RV_X(x, 21, 10) << 1) | (RV_X(x, 20, 1) << 11) | (RV_X(x, 12, 8) << 12) | (RV_IMM_SIGN(x) << 20)) #define EXTRACT_RVC_IMM(x) \ (RV_X(x, 2, 5) | (-RV_X(x, 12, 1) << 5)) +#define EXTRACT_RVC_LUI_IMM(x) \ + (EXTRACT_RVC_IMM (x) << RISCV_IMM_BITS) #define EXTRACT_RVC_SIMM3(x) \ (RV_X(x, 10, 2) | (-RV_X(x, 12, 1) << 2)) #define EXTRACT_RVC_ADDI4SPN_IMM(x) \ @@ -106,6 +108,8 @@ static const char * const riscv_pred_succ[16] = { ((RV_X(x, 1, 10) << 21) | (RV_X(x, 11, 1) << 20) | (RV_X(x, 12, 8) << 12) | (RV_X(x, 20, 1) << 31)) #define ENCODE_RVC_IMM(x) \ ((RV_X(x, 0, 5) << 2) | (RV_X(x, 5, 1) << 12)) +#define ENCODE_RVC_LUI_IMM(x) \ + ENCODE_RVC_IMM ((x) >> RISCV_IMM_BITS) #define ENCODE_RVC_SIMM3(x) \ (RV_X(x, 0, 3) << 10) #define ENCODE_RVC_ADDI4SPN_IMM(x) \ @@ -135,6 +139,7 @@ static const char * const riscv_pred_succ[16] = { #define VALID_UTYPE_IMM(x) (EXTRACT_UTYPE_IMM(ENCODE_UTYPE_IMM(x)) == (x)) #define VALID_UJTYPE_IMM(x) (EXTRACT_UJTYPE_IMM(ENCODE_UJTYPE_IMM(x)) == (x)) #define VALID_RVC_IMM(x) (EXTRACT_RVC_IMM(ENCODE_RVC_IMM(x)) == (x)) +#define VALID_RVC_LUI_IMM(x) (EXTRACT_RVC_LUI_IMM(ENCODE_RVC_LUI_IMM(x)) == (x)) #define VALID_RVC_SIMM3(x) (EXTRACT_RVC_SIMM3(ENCODE_RVC_SIMM3(x)) == (x)) #define VALID_RVC_ADDI4SPN_IMM(x) (EXTRACT_RVC_ADDI4SPN_IMM(ENCODE_RVC_ADDI4SPN_IMM(x)) == (x)) #define VALID_RVC_ADDI16SP_IMM(x) (EXTRACT_RVC_ADDI16SP_IMM(ENCODE_RVC_ADDI16SP_IMM(x)) == (x)) diff --git a/patches/binutils b/patches/binutils index 24ac4c6..1d0f99b 100644 --- a/patches/binutils +++ b/patches/binutils @@ -28,7 +28,7 @@ bfd_arch_rs6000, /* IBM RS/6000 */ #define bfd_mach_rs6k 6000 #define bfd_mach_rs6k_rs1 6001 -@@ -5531,6 +5534,43 @@ relative offset from _GLOBAL_OFFSET_TABL +@@ -5531,6 +5534,44 @@ relative offset from _GLOBAL_OFFSET_TABL value in a word. The relocation is relative offset from */ BFD_RELOC_MICROBLAZE_32_GOTOFF, @@ -68,6 +68,7 @@ + BFD_RELOC_RISCV_ALIGN, + BFD_RELOC_RISCV_RVC_BRANCH, + BFD_RELOC_RISCV_RVC_JUMP, ++ BFD_RELOC_RISCV_RVC_LUI, + /* This is used to tell the dynamic linker to copy the value out of the dynamic object into the runtime process image. */ -- cgit v1.1