[PATCH 1/2] RISC-V: Clarify the addends of pc-relative access.
Nelson Chu
nelson.chu@sifive.com
Tue Jun 15 01:39:03 GMT 2021
Friendly ping this series :)
Thanks
Nelson
On Thu, May 20, 2021 at 4:57 PM Nelson Chu <nelson.chu@sifive.com> wrote:
>
> 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