From 04b865dc2ede2b8ca8c60f0487a179eb97895fee Mon Sep 17 00:00:00 2001 From: Jim Wilson Date: Mon, 24 Jun 2019 13:50:10 -0700 Subject: [PATCH] RISC-V: Enable lui relaxation for CODE and MERGE sections. 2019-06-24 Ilia Diachkov bfd/ * elfnn-riscv.c (_bfd_riscv_relax_lui): Delete early exit when SEC_MERGE or SEC_CODE flags are set. (_bfd_riscv_relax_section): New local symtype. Set sym_sec and symtype consistently. Don't include sec_addr (sym_sec) in symval. Add check for SEC_INFO_TYPE_MERGE and call _bfd_merged_section_offset. Add sec_addr (sym_sec) after handling merge sections. --- bfd/ChangeLog | 9 +++++++++ bfd/elfnn-riscv.c | 56 +++++++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 55 insertions(+), 10 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index ec272a8..d8cbef1 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,12 @@ +2019-06-24 Ilia Diachkov + + * elfnn-riscv.c (_bfd_riscv_relax_lui): Delete early exit when + SEC_MERGE or SEC_CODE flags are set. + (_bfd_riscv_relax_section): New local symtype. Set sym_sec and + symtype consistently. Don't include sec_addr (sym_sec) in symval. + Add check for SEC_INFO_TYPE_MERGE and call _bfd_merged_section_offset. + Add sec_addr (sym_sec) after handling merge sections. + 2019-06-24 H.J. Lu PR ld/24721 diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c index 1bddbca..003b4f8 100644 --- a/bfd/elfnn-riscv.c +++ b/bfd/elfnn-riscv.c @@ -3517,10 +3517,6 @@ _bfd_riscv_relax_lui (bfd *abfd, bfd_vma gp = riscv_global_pointer_value (link_info); int use_rvc = elf_elfheader (abfd)->e_flags & EF_RISCV_RVC; - /* Mergeable symbols and code might later move out of range. */ - if (sym_sec->flags & (SEC_MERGE | SEC_CODE)) - return TRUE; - BFD_ASSERT (rel->r_offset + 4 <= sec->size); if (gp) @@ -3881,6 +3877,7 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec, relax_func_t relax_func; int type = ELFNN_R_TYPE (rel->r_info); bfd_vma symval; + char symtype; relax_func = NULL; if (info->relax_pass == 0) @@ -3946,7 +3943,7 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec, ? 0 : isym->st_size - rel->r_addend; if (isym->st_shndx == SHN_UNDEF) - sym_sec = sec, symval = sec_addr (sec) + rel->r_offset; + sym_sec = sec, symval = rel->r_offset; else { BFD_ASSERT (isym->st_shndx < elf_numsections (abfd)); @@ -3959,8 +3956,9 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec, if (sec_addr (sym_sec) == 0) continue; #endif - symval = sec_addr (sym_sec) + isym->st_value; + symval = isym->st_value; } + symtype = ELF_ST_TYPE (isym->st_info); } else { @@ -3975,21 +3973,59 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec, h = (struct elf_link_hash_entry *) h->root.u.i.link; if (h->plt.offset != MINUS_ONE) - symval = sec_addr (htab->elf.splt) + h->plt.offset; + { + sym_sec = htab->elf.splt; + symval = h->plt.offset; + } else if (h->root.u.def.section->output_section == NULL || (h->root.type != bfd_link_hash_defined && h->root.type != bfd_link_hash_defweak)) continue; else - symval = sec_addr (h->root.u.def.section) + h->root.u.def.value; + { + symval = h->root.u.def.value; + sym_sec = h->root.u.def.section; + } if (h->type != STT_FUNC) reserve_size = (h->size - rel->r_addend) > h->size ? 0 : h->size - rel->r_addend; - sym_sec = h->root.u.def.section; + symtype = h->type; } - symval += rel->r_addend; + if (sym_sec->sec_info_type == SEC_INFO_TYPE_MERGE + && (sym_sec->flags & SEC_MERGE)) + { + /* At this stage in linking, no SEC_MERGE symbol has been + adjusted, so all references to such symbols need to be + passed through _bfd_merged_section_offset. (Later, in + relocate_section, all SEC_MERGE symbols *except* for + section symbols have been adjusted.) + + gas may reduce relocations against symbols in SEC_MERGE + sections to a relocation against the section symbol when + the original addend was zero. When the reloc is against + a section symbol we should include the addend in the + offset passed to _bfd_merged_section_offset, since the + location of interest is the original symbol. On the + other hand, an access to "sym+addend" where "sym" is not + a section symbol should not include the addend; Such an + access is presumed to be an offset from "sym"; The + location of interest is just "sym". */ + if (symtype == STT_SECTION) + symval += rel->r_addend; + + symval = _bfd_merged_section_offset (abfd, &sym_sec, + elf_section_data (sym_sec)->sec_info, + symval); + + if (symtype != STT_SECTION) + symval += rel->r_addend; + } + else + symval += rel->r_addend; + + symval += sec_addr (sym_sec); if (!relax_func (abfd, sec, sym_sec, info, rel, symval, max_alignment, reserve_size, again, -- 2.7.4