Jim Wilson
2018-09-25 20:15:04 UTC
The standard PLT instruction sequence uses 4 temporary registers, but the RVE
base architecture only has 3, so this can't work. However, there is no
expectation that Linux or shared libraries will ever support RVE, so we should
just give an error for this. This is patterned after a similar error in the
ARM port for Thumb-1 PLTs.
Tested with rv32i and rv32e newlib and linux toolchain builds. The rv32e linux
build produces the expected error, after I hacked up glibc so it would build
for RVE. The other ones continue to work without error. Also tested with the
usual sanity check of riscv{32,64}-{elf,linux} binutils make check, with no
regressions.
Committed.
Jim
bfd/
* elfnn-riscv.c (riscv_make_plt_header): New arg output_bfd. Change
return type to bfd_boolean. If EF_RISCV_RVE call _bfd_error_handler
and return FALSE. Return TRUE at end.
(riscv_make_plt_entry): Likewise.
(riscv_elf_finish_dynamic_symbol): Update call to riscv_make_plt_entry.
(riscv_elf_finish_dynamic_sections): Update call to
riscv_make_plt_header.
---
bfd/elfnn-riscv.c | 44 ++++++++++++++++++++++++++++++++++++--------
1 file changed, 36 insertions(+), 8 deletions(-)
diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index f3e2cc7c37..c99bcff5f1 100644
--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -169,12 +169,21 @@ riscv_elf_got_plt_val (bfd_vma plt_index, struct bfd_link_info *info)
/* Generate a PLT header. */
-static void
-riscv_make_plt_header (bfd_vma gotplt_addr, bfd_vma addr, uint32_t *entry)
+static bfd_boolean
+riscv_make_plt_header (bfd *output_bfd, bfd_vma gotplt_addr, bfd_vma addr,
+ uint32_t *entry)
{
bfd_vma gotplt_offset_high = RISCV_PCREL_HIGH_PART (gotplt_addr, addr);
bfd_vma gotplt_offset_low = RISCV_PCREL_LOW_PART (gotplt_addr, addr);
+ /* RVE has no t3 register, so this won't work, and is not supported. */
+ if (elf_elfheader (output_bfd)->e_flags & EF_RISCV_RVE)
+ {
+ _bfd_error_handler (_("%pB: warning: RVE PLT generation not supported"),
+ output_bfd);
+ return FALSE;
+ }
+
/* auipc t2, %hi(.got.plt)
sub t1, t1, t3 # shifted .got.plt offset + hdr size + 12
l[w|d] t3, %lo(.got.plt)(t2) # _dl_runtime_resolve
@@ -192,13 +201,24 @@ riscv_make_plt_header (bfd_vma gotplt_addr, bfd_vma addr, uint32_t *entry)
entry[5] = RISCV_ITYPE (SRLI, X_T1, X_T1, 4 - RISCV_ELF_LOG_WORD_BYTES);
entry[6] = RISCV_ITYPE (LREG, X_T0, X_T0, RISCV_ELF_WORD_BYTES);
entry[7] = RISCV_ITYPE (JALR, 0, X_T3, 0);
+
+ return TRUE;
}
/* Generate a PLT entry. */
-static void
-riscv_make_plt_entry (bfd_vma got, bfd_vma addr, uint32_t *entry)
+static bfd_boolean
+riscv_make_plt_entry (bfd *output_bfd, bfd_vma got, bfd_vma addr,
+ uint32_t *entry)
{
+ /* RVE has no t3 register, so this won't work, and is not supported. */
+ if (elf_elfheader (output_bfd)->e_flags & EF_RISCV_RVE)
+ {
+ _bfd_error_handler (_("%pB: warning: RVE PLT generation not supported"),
+ output_bfd);
+ return FALSE;
+ }
+
/* auipc t3, %hi(.got.plt entry)
l[w|d] t3, %lo(.got.plt entry)(t3)
jalr t1, t3
@@ -208,6 +228,8 @@ riscv_make_plt_entry (bfd_vma got, bfd_vma addr, uint32_t *entry)
entry[1] = RISCV_ITYPE (LREG, X_T3, X_T3, RISCV_PCREL_LOW_PART (got, addr));
entry[2] = RISCV_ITYPE (JALR, X_T1, X_T3, 0);
entry[3] = RISCV_NOP;
+
+ return TRUE;
}
/* Create an entry in an RISC-V ELF linker hash table. */
@@ -2353,8 +2375,11 @@ riscv_elf_finish_dynamic_symbol (bfd *output_bfd,
loc = htab->elf.splt->contents + h->plt.offset;
/* Fill in the PLT entry itself. */
- riscv_make_plt_entry (got_address, header_address + h->plt.offset,
- plt_entry);
+ if (! riscv_make_plt_entry (output_bfd, got_address,
+ header_address + h->plt.offset,
+ plt_entry))
+ return FALSE;
+
for (i = 0; i < PLT_ENTRY_INSNS; i++)
bfd_put_32 (output_bfd, plt_entry[i], loc + 4*i);
@@ -2529,8 +2554,11 @@ riscv_elf_finish_dynamic_sections (bfd *output_bfd,
{
int i;
uint32_t plt_header[PLT_HEADER_INSNS];
- riscv_make_plt_header (sec_addr (htab->elf.sgotplt),
- sec_addr (splt), plt_header);
+ ret = riscv_make_plt_header (output_bfd,
+ sec_addr (htab->elf.sgotplt),
+ sec_addr (splt), plt_header);
+ if (!ret)
+ return ret;
for (i = 0; i < PLT_HEADER_INSNS; i++)
bfd_put_32 (output_bfd, plt_header[i], splt->contents + 4*i);
base architecture only has 3, so this can't work. However, there is no
expectation that Linux or shared libraries will ever support RVE, so we should
just give an error for this. This is patterned after a similar error in the
ARM port for Thumb-1 PLTs.
Tested with rv32i and rv32e newlib and linux toolchain builds. The rv32e linux
build produces the expected error, after I hacked up glibc so it would build
for RVE. The other ones continue to work without error. Also tested with the
usual sanity check of riscv{32,64}-{elf,linux} binutils make check, with no
regressions.
Committed.
Jim
bfd/
* elfnn-riscv.c (riscv_make_plt_header): New arg output_bfd. Change
return type to bfd_boolean. If EF_RISCV_RVE call _bfd_error_handler
and return FALSE. Return TRUE at end.
(riscv_make_plt_entry): Likewise.
(riscv_elf_finish_dynamic_symbol): Update call to riscv_make_plt_entry.
(riscv_elf_finish_dynamic_sections): Update call to
riscv_make_plt_header.
---
bfd/elfnn-riscv.c | 44 ++++++++++++++++++++++++++++++++++++--------
1 file changed, 36 insertions(+), 8 deletions(-)
diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index f3e2cc7c37..c99bcff5f1 100644
--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -169,12 +169,21 @@ riscv_elf_got_plt_val (bfd_vma plt_index, struct bfd_link_info *info)
/* Generate a PLT header. */
-static void
-riscv_make_plt_header (bfd_vma gotplt_addr, bfd_vma addr, uint32_t *entry)
+static bfd_boolean
+riscv_make_plt_header (bfd *output_bfd, bfd_vma gotplt_addr, bfd_vma addr,
+ uint32_t *entry)
{
bfd_vma gotplt_offset_high = RISCV_PCREL_HIGH_PART (gotplt_addr, addr);
bfd_vma gotplt_offset_low = RISCV_PCREL_LOW_PART (gotplt_addr, addr);
+ /* RVE has no t3 register, so this won't work, and is not supported. */
+ if (elf_elfheader (output_bfd)->e_flags & EF_RISCV_RVE)
+ {
+ _bfd_error_handler (_("%pB: warning: RVE PLT generation not supported"),
+ output_bfd);
+ return FALSE;
+ }
+
/* auipc t2, %hi(.got.plt)
sub t1, t1, t3 # shifted .got.plt offset + hdr size + 12
l[w|d] t3, %lo(.got.plt)(t2) # _dl_runtime_resolve
@@ -192,13 +201,24 @@ riscv_make_plt_header (bfd_vma gotplt_addr, bfd_vma addr, uint32_t *entry)
entry[5] = RISCV_ITYPE (SRLI, X_T1, X_T1, 4 - RISCV_ELF_LOG_WORD_BYTES);
entry[6] = RISCV_ITYPE (LREG, X_T0, X_T0, RISCV_ELF_WORD_BYTES);
entry[7] = RISCV_ITYPE (JALR, 0, X_T3, 0);
+
+ return TRUE;
}
/* Generate a PLT entry. */
-static void
-riscv_make_plt_entry (bfd_vma got, bfd_vma addr, uint32_t *entry)
+static bfd_boolean
+riscv_make_plt_entry (bfd *output_bfd, bfd_vma got, bfd_vma addr,
+ uint32_t *entry)
{
+ /* RVE has no t3 register, so this won't work, and is not supported. */
+ if (elf_elfheader (output_bfd)->e_flags & EF_RISCV_RVE)
+ {
+ _bfd_error_handler (_("%pB: warning: RVE PLT generation not supported"),
+ output_bfd);
+ return FALSE;
+ }
+
/* auipc t3, %hi(.got.plt entry)
l[w|d] t3, %lo(.got.plt entry)(t3)
jalr t1, t3
@@ -208,6 +228,8 @@ riscv_make_plt_entry (bfd_vma got, bfd_vma addr, uint32_t *entry)
entry[1] = RISCV_ITYPE (LREG, X_T3, X_T3, RISCV_PCREL_LOW_PART (got, addr));
entry[2] = RISCV_ITYPE (JALR, X_T1, X_T3, 0);
entry[3] = RISCV_NOP;
+
+ return TRUE;
}
/* Create an entry in an RISC-V ELF linker hash table. */
@@ -2353,8 +2375,11 @@ riscv_elf_finish_dynamic_symbol (bfd *output_bfd,
loc = htab->elf.splt->contents + h->plt.offset;
/* Fill in the PLT entry itself. */
- riscv_make_plt_entry (got_address, header_address + h->plt.offset,
- plt_entry);
+ if (! riscv_make_plt_entry (output_bfd, got_address,
+ header_address + h->plt.offset,
+ plt_entry))
+ return FALSE;
+
for (i = 0; i < PLT_ENTRY_INSNS; i++)
bfd_put_32 (output_bfd, plt_entry[i], loc + 4*i);
@@ -2529,8 +2554,11 @@ riscv_elf_finish_dynamic_sections (bfd *output_bfd,
{
int i;
uint32_t plt_header[PLT_HEADER_INSNS];
- riscv_make_plt_header (sec_addr (htab->elf.sgotplt),
- sec_addr (splt), plt_header);
+ ret = riscv_make_plt_header (output_bfd,
+ sec_addr (htab->elf.sgotplt),
+ sec_addr (splt), plt_header);
+ if (!ret)
+ return ret;
for (i = 0; i < PLT_HEADER_INSNS; i++)
bfd_put_32 (output_bfd, plt_header[i], splt->contents + 4*i);
--
2.17.1
2.17.1