[v2] RISC-V: Clarify the addends of pc-relative access.

Message ID 20210622091759.1402-1-nelson.chu@sifive.com
State New
Headers show
Series
  • [v2] RISC-V: Clarify the addends of pc-relative access.
Related show

Commit Message

Nelson Chu June 22, 2021, 9:17 a.m.
The original discussion was here,
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.

Another issue was here,
https://sourceware.org/pipermail/binutils/2021-June/116983.html

At the beginnig, I suppose %pcrel_hi and %pcrel_lo are valid only
when they are in the same input section.  But Jim Wilson points out
that gcc may generate %hi and %lo in the different input sections,
when -freorder-blocks-and-partition option is used.  So that a memory
references for a loop may have the %hi outside the loop, but the %lo
remain in the loop.  However, it is hard to create the testcases,
to see if %pcrel_hi and %pcrel_lo have the same behavior.

Unfortunately, I notice that the current pcrel resolver cannot
work for the above case.  For now we build a hash table for pcrel
at the start of riscv_elf_relocate_section, and then free the hash
at the end.  But riscv_elf_relocate_section only handles an input
section at a time, so that means we can only resolve the %pcrel_hi
and %pcrel_lo which are in the same input section.  Otherwise, like
the above case, we will report "%pcrel_lo missing matching %pcrel_hi"
for them.  I have no plan to improve this in the short-term, so maybe
we can wait until someone meets the problem before we deal with it.

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 unused name field.
    (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/ChangeLog                                 |  17 ++
 bfd/elfnn-riscv.c                             | 160 ++++++++++--------
 ld/ChangeLog                                  |  14 ++
 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 ++
 11 files changed, 212 insertions(+), 68 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

-- 
2.30.2

Comments

Nelson Chu June 22, 2021, 9:20 a.m. | #1
Sorry, forgot to add the committed status to the subject.

Thanks
Nelson

On Tue, Jun 22, 2021 at 5:18 PM Nelson Chu <nelson.chu@sifive.com> wrote:
>

> The original discussion was here,

> 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.

>

> Another issue was here,

> https://sourceware.org/pipermail/binutils/2021-June/116983.html

>

> At the beginnig, I suppose %pcrel_hi and %pcrel_lo are valid only

> when they are in the same input section.  But Jim Wilson points out

> that gcc may generate %hi and %lo in the different input sections,

> when -freorder-blocks-and-partition option is used.  So that a memory

> references for a loop may have the %hi outside the loop, but the %lo

> remain in the loop.  However, it is hard to create the testcases,

> to see if %pcrel_hi and %pcrel_lo have the same behavior.

>

> Unfortunately, I notice that the current pcrel resolver cannot

> work for the above case.  For now we build a hash table for pcrel

> at the start of riscv_elf_relocate_section, and then free the hash

> at the end.  But riscv_elf_relocate_section only handles an input

> section at a time, so that means we can only resolve the %pcrel_hi

> and %pcrel_lo which are in the same input section.  Otherwise, like

> the above case, we will report "%pcrel_lo missing matching %pcrel_hi"

> for them.  I have no plan to improve this in the short-term, so maybe

> we can wait until someone meets the problem before we deal with it.

>

> 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 unused name field.

>     (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/ChangeLog                                 |  17 ++

>  bfd/elfnn-riscv.c                             | 160 ++++++++++--------

>  ld/ChangeLog                                  |  14 ++

>  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 ++

>  11 files changed, 212 insertions(+), 68 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/ChangeLog b/bfd/ChangeLog

> index 212fe332e2d..f18e16549da 100644

> --- a/bfd/ChangeLog

> +++ b/bfd/ChangeLog

> @@ -1,3 +1,20 @@

> +2021-06-22  Nelson Chu  <nelson.chu@sifive.com>

> +

> +       * 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 unused name field.

> +       (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.

> +

>  2021-06-19  H.J. Lu  <hongjiu.lu@intel.com>

>

>         PR ld/27998

> diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c

> index eef1e800221..f206708a9f3 100644

> --- a/bfd/elfnn-riscv.c

> +++ b/bfd/elfnn-riscv.c

> @@ -1739,25 +1739,41 @@ 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

>  {

> +  /* PC value of auipc.  */

> +  bfd_vma address;

> +  /* Internal relocation.  */

> +  const Elf_Internal_Rela *reloc;

> +  /* Record the following information helps to resolve the %pcrel

> +     which cross different input section.  For now we build a hash

> +     for pcrel at the start of riscv_elf_relocate_section, and then

> +     free the hash at the end.  But riscv_elf_relocate_section only

> +     handles an input section at a time, so that means we can only

> +     resolve the %pcrel_hi and %pcrel_lo which are in the same input

> +     section.  Otherwise, we will report dangerous relocation errors

> +     for those %pcrel which are not in the same input section.  */

>    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;

> +  /* 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;

>

> @@ -1805,8 +1821,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

> @@ -1839,11 +1854,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);

>

> @@ -1857,20 +1875,19 @@ riscv_record_pcrel_hi_reloc (riscv_pcrel_relocs *p, bfd_vma addr,

>

>  static bool

>  riscv_record_pcrel_lo_reloc (riscv_pcrel_relocs *p,

> +                            bfd_vma addr,

> +                            const Elf_Internal_Rela *reloc,

>                              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)

>  {

>    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, input_section, info,

> +                                  howto, contents, p->lo_relocs};

>    p->lo_relocs = entry;

>    return true;

>  }

> @@ -1884,26 +1901,34 @@ riscv_resolve_pcrel_lo_relocs (riscv_pcrel_relocs *p)

>      {

>        bfd *input_bfd = r->input_section->owner;

>

> -      riscv_pcrel_hi_reloc search = {r->addr, 0};

> +      riscv_pcrel_hi_reloc search = {r->address, 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");

> +       }

>

> +      if (string != NULL)

> +       {

>           (*r->info->callbacks->reloc_dangerous)

>             (r->info, string, input_bfd, r->input_section, r->reloc->r_offset);

>           return true;

> @@ -2225,12 +2250,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;

>

> @@ -2242,12 +2264,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;

>

> @@ -2384,21 +2403,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:

> @@ -2499,20 +2526,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;

>

> @@ -2532,8 +2555,8 @@ riscv_elf_relocate_section (bfd *output_bfd,

>               break;

>             }

>

> -         if (riscv_record_pcrel_lo_reloc (&pcrel_relocs, input_section, info,

> -                                          howto, rel, relocation, name,

> +         if (riscv_record_pcrel_lo_reloc (&pcrel_relocs, relocation, rel,

> +                                          input_section, info, howto,

>                                            contents))

>             continue;

>           r = bfd_reloc_overflow;

> @@ -2726,7 +2749,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;

> diff --git a/ld/ChangeLog b/ld/ChangeLog

> index dc08ec9f0a0..b4c49cc6513 100644

> --- a/ld/ChangeLog

> +++ b/ld/ChangeLog

> @@ -1,3 +1,17 @@

> +2021-06-22  Nelson Chu  <nelson.chu@sifive.com>

> +

> +       * 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.

> +

>  2021-06-19  H.J. Lu  <hongjiu.lu@intel.com>

>

>         PR ld/27998

> diff --git a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp

> index 0b49ddcacf6..1f1245af707 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

>

Patch

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 212fe332e2d..f18e16549da 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,20 @@ 
+2021-06-22  Nelson Chu  <nelson.chu@sifive.com>
+
+	* 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 unused name field.
+	(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.
+
 2021-06-19  H.J. Lu  <hongjiu.lu@intel.com>
 
 	PR ld/27998
diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index eef1e800221..f206708a9f3 100644
--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -1739,25 +1739,41 @@  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
 {
+  /* PC value of auipc.  */
+  bfd_vma address;
+  /* Internal relocation.  */
+  const Elf_Internal_Rela *reloc;
+  /* Record the following information helps to resolve the %pcrel
+     which cross different input section.  For now we build a hash
+     for pcrel at the start of riscv_elf_relocate_section, and then
+     free the hash at the end.  But riscv_elf_relocate_section only
+     handles an input section at a time, so that means we can only
+     resolve the %pcrel_hi and %pcrel_lo which are in the same input
+     section.  Otherwise, we will report dangerous relocation errors
+     for those %pcrel which are not in the same input section.  */
   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;
+  /* 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;
 
@@ -1805,8 +1821,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
@@ -1839,11 +1854,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);
 
@@ -1857,20 +1875,19 @@  riscv_record_pcrel_hi_reloc (riscv_pcrel_relocs *p, bfd_vma addr,
 
 static bool
 riscv_record_pcrel_lo_reloc (riscv_pcrel_relocs *p,
+			     bfd_vma addr,
+			     const Elf_Internal_Rela *reloc,
 			     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)
 {
   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, input_section, info,
+				   howto, contents, p->lo_relocs};
   p->lo_relocs = entry;
   return true;
 }
@@ -1884,26 +1901,34 @@  riscv_resolve_pcrel_lo_relocs (riscv_pcrel_relocs *p)
     {
       bfd *input_bfd = r->input_section->owner;
 
-      riscv_pcrel_hi_reloc search = {r->addr, 0};
+      riscv_pcrel_hi_reloc search = {r->address, 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");
+	}
 
+      if (string != NULL)
+	{
 	  (*r->info->callbacks->reloc_dangerous)
 	    (r->info, string, input_bfd, r->input_section, r->reloc->r_offset);
 	  return true;
@@ -2225,12 +2250,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;
 
@@ -2242,12 +2264,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;
 
@@ -2384,21 +2403,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:
@@ -2499,20 +2526,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;
 
@@ -2532,8 +2555,8 @@  riscv_elf_relocate_section (bfd *output_bfd,
 	      break;
 	    }
 
-	  if (riscv_record_pcrel_lo_reloc (&pcrel_relocs, input_section, info,
-					   howto, rel, relocation, name,
+	  if (riscv_record_pcrel_lo_reloc (&pcrel_relocs, relocation, rel,
+					   input_section, info, howto,
 					   contents))
 	    continue;
 	  r = bfd_reloc_overflow;
@@ -2726,7 +2749,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;
diff --git a/ld/ChangeLog b/ld/ChangeLog
index dc08ec9f0a0..b4c49cc6513 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,3 +1,17 @@ 
+2021-06-22  Nelson Chu  <nelson.chu@sifive.com>
+
+	* 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.
+
 2021-06-19  H.J. Lu  <hongjiu.lu@intel.com>
 
 	PR ld/27998
diff --git a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
index 0b49ddcacf6..1f1245af707 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