[PATCH 1/2] RISC-V: Clarify the addends of pc-relative access.
Nelson Chu
nelson.chu@sifive.com
Thu May 20 08:57:23 GMT 2021
The original discussion,
https://github.com/riscv/riscv-elf-psabi-doc/issues/184
After discussing with Kito Cheng, I think the addends of %pcrel_hi and
%pcrel_lo are both allowed in GNU toolchain. However, both of the them
mean the offset of symbols, rather than the pc address. But the addends
of %got_pcrel_hi and it's %pcrel_lo do not look reasonable. I believe
gcc won't generate the got patterns with addends, so linker should report
dangerous relocation errors, in case the assembly code use them.
Besides, the %pcrel_lo and it's %pcrel_hi should be placed in the same
input object and input section, so we don't need to record so many
information in the struct riscv_pcrel_lo_reloc.
bfd/
* elfnn-riscv.c (riscv_pcrel_hi_reloc): Added field to store
the original relocation type, in case the type is converted to
R_RISCV_HI20.
(riscv_pcrel_lo_reloc): Removed redundant fields.
(riscv_pcrel_relocs): Added comments.
(riscv_zero_pcrel_hi_reloc): Removed unused input_bfd.
(riscv_record_pcrel_hi_reloc): Updated.
(riscv_record_pcrel_lo_reloc): Likewise.
(riscv_resolve_pcrel_lo_relocs): Likewise. Check the original
type of auipc, to make sure the %pcrel_lo without any addends.
Otherwise, report dangerous relocation error.
(riscv_elf_relocate_section): Updated above functions are changed.
For R_RISCV_GOT_HI20, report dangerous relocation error when addend
isn't zero.
ld/
* testsuite/ld-riscv-elf/ld-riscv-elf.exp: Updated.
* testsuite/ld-riscv-elf/pcrel-lo-addend-3a.d: New testcase.
* testsuite/ld-riscv-elf/pcrel-lo-addend-3a.s: Likewise.
* testsuite/ld-riscv-elf/pcrel-lo-addend-3b.d: New testcase.
Should report error since the %pcrel_lo with addend refers to
%got_pcrel_hi.
* testsuite/ld-riscv-elf/pcrel-lo-addend-3b.s: Likewise.
* testsuite/ld-riscv-elf/pcrel-lo-addend-3c.d: New testcase.
Should report error since the %got_pcrel_hi with addend.
* testsuite/ld-riscv-elf/pcrel-lo-addend-3c.s: Likewise.
* testsuite/ld-riscv-elf/pcrel-lo-addend-3.ld: Likewise.
---
bfd/elfnn-riscv.c | 178 ++++++++++--------
ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp | 3 +
.../ld-riscv-elf/pcrel-lo-addend-3.ld | 13 ++
.../ld-riscv-elf/pcrel-lo-addend-3a.d | 18 ++
.../ld-riscv-elf/pcrel-lo-addend-3a.s | 21 +++
.../ld-riscv-elf/pcrel-lo-addend-3b.d | 4 +
.../ld-riscv-elf/pcrel-lo-addend-3b.s | 13 ++
.../ld-riscv-elf/pcrel-lo-addend-3c.d | 4 +
.../ld-riscv-elf/pcrel-lo-addend-3c.s | 13 ++
9 files changed, 184 insertions(+), 83 deletions(-)
create mode 100644 ld/testsuite/ld-riscv-elf/pcrel-lo-addend-3.ld
create mode 100644 ld/testsuite/ld-riscv-elf/pcrel-lo-addend-3a.d
create mode 100644 ld/testsuite/ld-riscv-elf/pcrel-lo-addend-3a.s
create mode 100644 ld/testsuite/ld-riscv-elf/pcrel-lo-addend-3b.d
create mode 100644 ld/testsuite/ld-riscv-elf/pcrel-lo-addend-3b.s
create mode 100644 ld/testsuite/ld-riscv-elf/pcrel-lo-addend-3c.d
create mode 100644 ld/testsuite/ld-riscv-elf/pcrel-lo-addend-3c.s
diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index 2068edebdb6..16e6c1e1484 100644
--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -1735,25 +1735,29 @@ perform_relocation (const reloc_howto_type *howto,
typedef struct
{
+ /* PC value. */
bfd_vma address;
+ /* Relocation value with addend. */
bfd_vma value;
+ /* Original reloc type. */
+ int type;
} riscv_pcrel_hi_reloc;
typedef struct riscv_pcrel_lo_reloc
{
- asection *input_section;
- struct bfd_link_info *info;
- reloc_howto_type *howto;
- const Elf_Internal_Rela *reloc;
+ /* PC value of auipc. */
bfd_vma addr;
- const char *name;
- bfd_byte *contents;
+ /* Internal relocation. */
+ const Elf_Internal_Rela *reloc;
+ /* The next riscv_pcrel_lo_reloc. */
struct riscv_pcrel_lo_reloc *next;
} riscv_pcrel_lo_reloc;
typedef struct
{
+ /* Hash table for riscv_pcrel_hi_reloc. */
htab_t hi_relocs;
+ /* Linked list for riscv_pcrel_lo_reloc. */
riscv_pcrel_lo_reloc *lo_relocs;
} riscv_pcrel_relocs;
@@ -1801,8 +1805,7 @@ riscv_zero_pcrel_hi_reloc (Elf_Internal_Rela *rel,
bfd_vma pc,
bfd_vma addr,
bfd_byte *contents,
- const reloc_howto_type *howto,
- bfd *input_bfd ATTRIBUTE_UNUSED)
+ const reloc_howto_type *howto)
{
/* We may need to reference low addreses in PC-relative modes even when the
PC is far away from these addresses. For example, undefweak references
@@ -1835,11 +1838,14 @@ riscv_zero_pcrel_hi_reloc (Elf_Internal_Rela *rel,
}
static bool
-riscv_record_pcrel_hi_reloc (riscv_pcrel_relocs *p, bfd_vma addr,
- bfd_vma value, bool absolute)
+riscv_record_pcrel_hi_reloc (riscv_pcrel_relocs *p,
+ bfd_vma addr,
+ bfd_vma value,
+ int type,
+ bool absolute)
{
bfd_vma offset = absolute ? value : value - addr;
- riscv_pcrel_hi_reloc entry = {addr, offset};
+ riscv_pcrel_hi_reloc entry = {addr, offset, type};
riscv_pcrel_hi_reloc **slot =
(riscv_pcrel_hi_reloc **) htab_find_slot (p->hi_relocs, &entry, INSERT);
@@ -1853,60 +1859,68 @@ riscv_record_pcrel_hi_reloc (riscv_pcrel_relocs *p, bfd_vma addr,
static bool
riscv_record_pcrel_lo_reloc (riscv_pcrel_relocs *p,
- asection *input_section,
- struct bfd_link_info *info,
- reloc_howto_type *howto,
- const Elf_Internal_Rela *reloc,
bfd_vma addr,
- const char *name,
- bfd_byte *contents)
+ const Elf_Internal_Rela *reloc)
{
riscv_pcrel_lo_reloc *entry;
entry = (riscv_pcrel_lo_reloc *) bfd_malloc (sizeof (riscv_pcrel_lo_reloc));
if (entry == NULL)
return false;
- *entry = (riscv_pcrel_lo_reloc) {input_section, info, howto, reloc, addr,
- name, contents, p->lo_relocs};
+ *entry = (riscv_pcrel_lo_reloc) {addr, reloc, p->lo_relocs};
p->lo_relocs = entry;
return true;
}
static bool
-riscv_resolve_pcrel_lo_relocs (riscv_pcrel_relocs *p)
+riscv_resolve_pcrel_lo_relocs (struct bfd_link_info *info,
+ bfd *input_bfd,
+ asection *input_section,
+ bfd_byte *contents,
+ riscv_pcrel_relocs *p)
{
riscv_pcrel_lo_reloc *r;
for (r = p->lo_relocs; r != NULL; r = r->next)
{
- bfd *input_bfd = r->input_section->owner;
-
- riscv_pcrel_hi_reloc search = {r->addr, 0};
+ riscv_pcrel_hi_reloc search = {r->addr, 0, 0};
riscv_pcrel_hi_reloc *entry = htab_find (p->hi_relocs, &search);
- if (entry == NULL
- /* Check the overflow when adding reloc addend. */
- || (RISCV_CONST_HIGH_PART (entry->value)
- != RISCV_CONST_HIGH_PART (entry->value + r->reloc->r_addend)))
+
+ /* There may be a risk if the %pcrel_lo with addend refers to
+ an IFUNC symbol. The %pcrel_hi has been relocated to plt,
+ so the corresponding %pcrel_lo with addend looks wrong. */
+ char *string = NULL;
+ if (entry == NULL)
+ string = _("%pcrel_lo missing matching %pcrel_hi");
+ else if (entry->type == R_RISCV_GOT_HI20
+ && r->reloc->r_addend != 0)
+ string = _("%pcrel_lo with addend isn't allowed for R_RISCV_GOT_HI20");
+ else if (RISCV_CONST_HIGH_PART (entry->value)
+ != RISCV_CONST_HIGH_PART (entry->value
+ + r->reloc->r_addend))
{
- char *string;
- if (entry == NULL)
- string = _("%pcrel_lo missing matching %pcrel_hi");
- else if (asprintf (&string,
- _("%%pcrel_lo overflow with an addend, the "
- "value of %%pcrel_hi is 0x%" PRIx64 " without "
- "any addend, but may be 0x%" PRIx64 " after "
- "adding the %%pcrel_lo addend"),
- (int64_t) RISCV_CONST_HIGH_PART (entry->value),
- (int64_t) RISCV_CONST_HIGH_PART
+ /* Check the overflow when adding reloc addend. */
+ if (asprintf (&string,
+ _("%%pcrel_lo overflow with an addend, the "
+ "value of %%pcrel_hi is 0x%" PRIx64 " without "
+ "any addend, but may be 0x%" PRIx64 " after "
+ "adding the %%pcrel_lo addend"),
+ (int64_t) RISCV_CONST_HIGH_PART (entry->value),
+ (int64_t) RISCV_CONST_HIGH_PART
(entry->value + r->reloc->r_addend)) == -1)
string = _("%pcrel_lo overflow with an addend");
+ }
- (*r->info->callbacks->reloc_dangerous)
- (r->info, string, input_bfd, r->input_section, r->reloc->r_offset);
+ if (string != NULL)
+ {
+ info->callbacks->reloc_dangerous
+ (info, string, input_bfd, input_section, r->reloc->r_offset);
return true;
}
- perform_relocation (r->howto, r->reloc, entry->value, r->input_section,
- input_bfd, r->contents);
+ int type = ELFNN_R_TYPE (r->reloc->r_info);
+ reloc_howto_type *howto = riscv_elf_rtype_to_howto (input_bfd, type);
+ perform_relocation (howto, r->reloc, entry->value, input_section,
+ input_bfd, contents);
}
return true;
@@ -2221,12 +2235,9 @@ riscv_elf_relocate_section (bfd *output_bfd,
relocation = base_got->output_section->vma
+ base_got->output_offset + off;
- r_type = ELFNN_R_TYPE (rel->r_info);
- howto = riscv_elf_rtype_to_howto (input_bfd, r_type);
- if (howto == NULL)
- r = bfd_reloc_notsupported;
- else if (!riscv_record_pcrel_hi_reloc (&pcrel_relocs, pc,
- relocation, false))
+ if (!riscv_record_pcrel_hi_reloc (&pcrel_relocs, pc,
+ relocation, r_type,
+ false))
r = bfd_reloc_overflow;
goto do_relocation;
@@ -2238,12 +2249,9 @@ riscv_elf_relocate_section (bfd *output_bfd,
goto do_relocation;
case R_RISCV_PCREL_HI20:
- r_type = ELFNN_R_TYPE (rel->r_info);
- howto = riscv_elf_rtype_to_howto (input_bfd, r_type);
- if (howto == NULL)
- r = bfd_reloc_notsupported;
- else if (!riscv_record_pcrel_hi_reloc (&pcrel_relocs, pc,
- relocation, false))
+ if (!riscv_record_pcrel_hi_reloc (&pcrel_relocs, pc,
+ relocation, r_type,
+ false))
r = bfd_reloc_overflow;
goto do_relocation;
@@ -2380,21 +2388,29 @@ riscv_elf_relocate_section (bfd *output_bfd,
local_got_offsets[r_symndx] |= 1;
}
}
- relocation = sec_addr (htab->elf.sgot) + off;
- absolute = riscv_zero_pcrel_hi_reloc (rel,
- info,
- pc,
- relocation,
- contents,
- howto,
- input_bfd);
- r_type = ELFNN_R_TYPE (rel->r_info);
- howto = riscv_elf_rtype_to_howto (input_bfd, r_type);
- if (howto == NULL)
- r = bfd_reloc_notsupported;
- else if (!riscv_record_pcrel_hi_reloc (&pcrel_relocs, pc,
- relocation, absolute))
- r = bfd_reloc_overflow;
+
+ if (rel->r_addend != 0)
+ {
+ msg = _("The addend isn't allowed for R_RISCV_GOT_HI20");
+ r = bfd_reloc_dangerous;
+ }
+ else
+ {
+ /* Address of got entry. */
+ relocation = sec_addr (htab->elf.sgot) + off;
+ absolute = riscv_zero_pcrel_hi_reloc (rel, info, pc,
+ relocation, contents,
+ howto);
+ /* Update howto if relocation is changed. */
+ howto = riscv_elf_rtype_to_howto (input_bfd,
+ ELFNN_R_TYPE (rel->r_info));
+ if (howto == NULL)
+ r = bfd_reloc_notsupported;
+ else if (!riscv_record_pcrel_hi_reloc (&pcrel_relocs, pc,
+ relocation, r_type,
+ absolute))
+ r = bfd_reloc_overflow;
+ }
break;
case R_RISCV_ADD8:
@@ -2495,20 +2511,16 @@ riscv_elf_relocate_section (bfd *output_bfd,
}
case R_RISCV_PCREL_HI20:
- absolute = riscv_zero_pcrel_hi_reloc (rel,
- info,
- pc,
- relocation,
- contents,
- howto,
- input_bfd);
- r_type = ELFNN_R_TYPE (rel->r_info);
- howto = riscv_elf_rtype_to_howto (input_bfd, r_type);
+ absolute = riscv_zero_pcrel_hi_reloc (rel, info, pc, relocation,
+ contents, howto);
+ /* Update howto if relocation is changed. */
+ howto = riscv_elf_rtype_to_howto (input_bfd,
+ ELFNN_R_TYPE (rel->r_info));
if (howto == NULL)
r = bfd_reloc_notsupported;
else if (!riscv_record_pcrel_hi_reloc (&pcrel_relocs, pc,
relocation + rel->r_addend,
- absolute))
+ r_type, absolute))
r = bfd_reloc_overflow;
break;
@@ -2528,9 +2540,7 @@ riscv_elf_relocate_section (bfd *output_bfd,
break;
}
- if (riscv_record_pcrel_lo_reloc (&pcrel_relocs, input_section, info,
- howto, rel, relocation, name,
- contents))
+ if (riscv_record_pcrel_lo_reloc (&pcrel_relocs, relocation, rel))
continue;
r = bfd_reloc_overflow;
break;
@@ -2722,7 +2732,8 @@ riscv_elf_relocate_section (bfd *output_bfd,
BFD_ASSERT (off < (bfd_vma) -2);
relocation = sec_addr (htab->elf.sgot) + off + (is_ie ? ie_off : 0);
if (!riscv_record_pcrel_hi_reloc (&pcrel_relocs, pc,
- relocation, false))
+ relocation, r_type,
+ false))
r = bfd_reloc_overflow;
unresolved_reloc = false;
break;
@@ -2829,7 +2840,8 @@ riscv_elf_relocate_section (bfd *output_bfd,
goto out;
}
- ret = riscv_resolve_pcrel_lo_relocs (&pcrel_relocs);
+ ret = riscv_resolve_pcrel_lo_relocs (info, input_bfd, input_section,
+ contents, &pcrel_relocs);
out:
riscv_free_pcrel_relocs (&pcrel_relocs);
return ret;
diff --git a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
index 319ac7e2b83..bff1b479c80 100644
--- a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
+++ b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
@@ -87,6 +87,9 @@ if [istarget "riscv*-*-*"] {
run_dump_test "pcrel-lo-addend"
run_dump_test "pcrel-lo-addend-2a"
run_dump_test "pcrel-lo-addend-2b"
+ run_dump_test "pcrel-lo-addend-3a"
+ run_dump_test "pcrel-lo-addend-3b"
+ run_dump_test "pcrel-lo-addend-3c"
run_dump_test "restart-relax"
run_dump_test "attr-merge-arch-01"
run_dump_test "attr-merge-arch-02"
diff --git a/ld/testsuite/ld-riscv-elf/pcrel-lo-addend-3.ld b/ld/testsuite/ld-riscv-elf/pcrel-lo-addend-3.ld
new file mode 100644
index 00000000000..fabb65bdc82
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/pcrel-lo-addend-3.ld
@@ -0,0 +1,13 @@
+ENTRY(_start)
+SECTIONS
+{
+ .got 0x1000 : {
+ *(.got)
+ }
+ .data 0x2000: {
+ *(.data)
+ }
+ .text 0x900000000 : {
+ *(.text)
+ }
+}
diff --git a/ld/testsuite/ld-riscv-elf/pcrel-lo-addend-3a.d b/ld/testsuite/ld-riscv-elf/pcrel-lo-addend-3a.d
new file mode 100644
index 00000000000..1f77e20d52e
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/pcrel-lo-addend-3a.d
@@ -0,0 +1,18 @@
+#source: pcrel-lo-addend-3a.s
+#as: -march=rv64i -mabi=lp64 -mno-relax
+#ld: -m[riscv_choose_lp64_emul] -Tpcrel-lo-addend-3.ld
+#objdump: -d
+
+#...
+Disassembly of section .text:
+
+0+900000000 <_start>:
+.*:[ ]+[0-9a-f]+[ ]+lui[ ]+a5,0x2
+.*:[ ]+[0-9a-f]+[ ]+ld[ ]+a0,0\(a5\) # 2000 <ll>
+.*:[ ]+[0-9a-f]+[ ]+ld[ ]+a0,4\(a5\)
+.*:[ ]+[0-9a-f]+[ ]+lui[ ]+a5,0x2
+.*:[ ]+[0-9a-f]+[ ]+ld[ ]+a0,4\(a5\) # 2004 <ll\+0x4>
+.*:[ ]+[0-9a-f]+[ ]+ld[ ]+a0,8\(a5\)
+.*:[ ]+[0-9a-f]+[ ]+lui[ ]+a5,0x1
+.*:[ ]+[0-9a-f]+[ ]+ld[ ]+a0,8\(a5\) # 1008 <_GLOBAL_OFFSET_TABLE_\+0x8>
+#pass
diff --git a/ld/testsuite/ld-riscv-elf/pcrel-lo-addend-3a.s b/ld/testsuite/ld-riscv-elf/pcrel-lo-addend-3a.s
new file mode 100644
index 00000000000..14dc596dca9
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/pcrel-lo-addend-3a.s
@@ -0,0 +1,21 @@
+ .text
+ .globl _start
+ .align 3
+_start:
+.LA0: auipc a5, %pcrel_hi (ll)
+ ld a0, %pcrel_lo (.LA0)(a5)
+ ld a0, %pcrel_lo (.LA0 + 0x4)(a5)
+
+.LA1: auipc a5, %pcrel_hi (ll + 0x4)
+ ld a0, %pcrel_lo (.LA1)(a5)
+ ld a0, %pcrel_lo (.LA1 + 0x4)(a5)
+
+.LA2: auipc a5, %got_pcrel_hi (ll)
+ ld a0, %pcrel_lo (.LA2)(a5)
+
+ .globl ll
+ .data
+ll:
+ .dword 0
+ .dword 0
+ .dword 0
diff --git a/ld/testsuite/ld-riscv-elf/pcrel-lo-addend-3b.d b/ld/testsuite/ld-riscv-elf/pcrel-lo-addend-3b.d
new file mode 100644
index 00000000000..9c87c165a58
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/pcrel-lo-addend-3b.d
@@ -0,0 +1,4 @@
+#source: pcrel-lo-addend-3b.s
+#as: -march=rv64i -mabi=lp64 -mno-relax
+#ld: -m[riscv_choose_lp64_emul] -Tpcrel-lo-addend-3.ld
+#error: .*dangerous relocation: The addend isn't allowed for R_RISCV_GOT_HI20
diff --git a/ld/testsuite/ld-riscv-elf/pcrel-lo-addend-3b.s b/ld/testsuite/ld-riscv-elf/pcrel-lo-addend-3b.s
new file mode 100644
index 00000000000..0b7ebd63a20
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/pcrel-lo-addend-3b.s
@@ -0,0 +1,13 @@
+ .text
+ .globl _start
+ .align 3
+_start:
+.LA0: auipc a5, %got_pcrel_hi (ll + 0x4)
+ ld a0, %pcrel_lo (.LA0)(a5)
+
+ .globl ll
+ .data
+ll:
+ .dword 0
+ .dword 0
+ .dword 0
diff --git a/ld/testsuite/ld-riscv-elf/pcrel-lo-addend-3c.d b/ld/testsuite/ld-riscv-elf/pcrel-lo-addend-3c.d
new file mode 100644
index 00000000000..295895b8267
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/pcrel-lo-addend-3c.d
@@ -0,0 +1,4 @@
+#source: pcrel-lo-addend-3c.s
+#as: -march=rv64i -mabi=lp64 -mno-relax
+#ld: -m[riscv_choose_lp64_emul] -Tpcrel-lo-addend-3.ld
+#error: .*dangerous relocation: %pcrel_lo with addend isn't allowed for R_RISCV_GOT_HI20
diff --git a/ld/testsuite/ld-riscv-elf/pcrel-lo-addend-3c.s b/ld/testsuite/ld-riscv-elf/pcrel-lo-addend-3c.s
new file mode 100644
index 00000000000..0495851cf93
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/pcrel-lo-addend-3c.s
@@ -0,0 +1,13 @@
+ .text
+ .globl _start
+ .align 3
+_start:
+.LA0: auipc a5, %got_pcrel_hi (ll)
+ ld a0, %pcrel_lo (.LA0 + 0x4)(a5)
+
+ .globl ll
+ .data
+ll:
+ .dword 0
+ .dword 0
+ .dword 0
--
2.30.2
More information about the Binutils
mailing list