package/binutils: add upstream backported patches to support -mcmodel=large gcc option
authorGiulio Benetti <giulio.benetti@benettiengineering.com>
Mon, 3 May 2021 11:13:43 +0000 (13:13 +0200)
committerArnout Vandecappelle (Essensium/Mind) <arnout@mind.be>
Fri, 21 May 2021 08:36:04 +0000 (10:36 +0200)
Add upstream backported patches that allows using -mcmodel=large gcc option
that in order allows fixing build failure due to binutils bug 21464:
https://sourceware.org/bugzilla/show_bug.cgi?id=21464

Signed-off-by: Giulio Benetti <giulio.benetti@benettiengineering.com>
Signed-off-by: Arnout Vandecappelle (Essensium/Mind) <arnout@mind.be>
[Arnout: remove the PATCH M/N parts - cfr. check-package]

12 files changed:
package/binutils/2.32/0011-or1k-Implement-relocation-R_OR1K_GOT_AHI16-for-gotha.patch [new file with mode: 0644]
package/binutils/2.32/0012-or1k-Avoid-R_OR1K_GOT16-overflow-failures-in-presenc.patch [new file with mode: 0644]
package/binutils/2.32/0013-or1k-Support-large-plt_relocs-when-generating-plt-en.patch [new file with mode: 0644]
package/binutils/2.34/0004-or1k-Implement-relocation-R_OR1K_GOT_AHI16-for-gotha.patch [new file with mode: 0644]
package/binutils/2.34/0005-or1k-Avoid-R_OR1K_GOT16-overflow-failures-in-presenc.patch [new file with mode: 0644]
package/binutils/2.34/0006-or1k-Support-large-plt_relocs-when-generating-plt-en.patch [new file with mode: 0644]
package/binutils/2.35.2/0004-or1k-Implement-relocation-R_OR1K_GOT_AHI16-for-gotha.patch [new file with mode: 0644]
package/binutils/2.35.2/0005-or1k-Avoid-R_OR1K_GOT16-overflow-failures-in-presenc.patch [new file with mode: 0644]
package/binutils/2.35.2/0006-or1k-Support-large-plt_relocs-when-generating-plt-en.patch [new file with mode: 0644]
package/binutils/2.36.1/0004-or1k-Implement-relocation-R_OR1K_GOT_AHI16-for-gotha.patch [new file with mode: 0644]
package/binutils/2.36.1/0005-or1k-Avoid-R_OR1K_GOT16-overflow-failures-in-presenc.patch [new file with mode: 0644]
package/binutils/2.36.1/0006-or1k-Support-large-plt_relocs-when-generating-plt-en.patch [new file with mode: 0644]

diff --git a/package/binutils/2.32/0011-or1k-Implement-relocation-R_OR1K_GOT_AHI16-for-gotha.patch b/package/binutils/2.32/0011-or1k-Implement-relocation-R_OR1K_GOT_AHI16-for-gotha.patch
new file mode 100644 (file)
index 0000000..5a2b91f
--- /dev/null
@@ -0,0 +1,256 @@
+From b10e6230dea0015bf3b7748580b82c551f9a3a4a Mon Sep 17 00:00:00 2001
+From: Stafford Horne <shorne@gmail.com>
+Date: Sun, 2 May 2021 06:02:15 +0900
+Subject: [PATCH] or1k: Implement relocation R_OR1K_GOT_AHI16 for gotha()
+
+The gotha() relocation mnemonic will be outputted by OpenRISC GCC when
+using the -mcmodel=large option.  This relocation is used along with
+got() to generate 32-bit GOT offsets.  This increases the previous GOT
+offset limit from the previous 16-bit (64K) limit.
+
+This is needed on large binaries where the GOT grows larger than 64k.
+
+bfd/ChangeLog:
+
+       PR 21464
+       * bfd-in2.h: Add BFD_RELOC_OR1K_GOT_AHI16 relocation.
+       * elf32-or1k.c (or1k_elf_howto_table, or1k_reloc_map): Likewise.
+       (or1k_final_link_relocate, or1k_elf_relocate_section,
+       or1k_elf_check_relocs): Likewise.
+       * libbfd.h (bfd_reloc_code_real_names): Likewise.
+       * reloc.c: Likewise.
+
+cpu/ChangeLog:
+
+       PR 21464
+       * or1k.opc (or1k_imm16_relocs, parse_reloc): Define parse logic
+       for gotha() relocation.
+
+include/ChangeLog:
+
+       PR 21464
+       * elf/or1k.h (elf_or1k_reloc_type): Define R_OR1K_GOT_AHI16 number.
+
+opcodes/ChangeLog:
+
+       PR 21464
+       * or1k-asm.c: Regenerate.
+
+gas/ChangeLog:
+
+       PR 21464
+       * testsuite/gas/or1k/reloc-1.s: Add test for new relocation.
+       * testsuite/gas/or1k/reloc-1.d: Add test result for new
+       relocation.
+
+Cc: Giulio Benetti <giulio.benetti@benettiengineering.com>
+
+fixup reloc, add tests
+
+Signed-off-by: Giulio Benetti <giulio.benetti@benettiengineering.com>
+---
+ bfd/bfd-in2.h                    |  1 +
+ bfd/elf32-or1k.c                 | 21 ++++++++++++++++++++-
+ bfd/libbfd.h                     |  1 +
+ bfd/reloc.c                      |  2 ++
+ cpu/or1k.opc                     |  7 ++++++-
+ gas/testsuite/gas/or1k/reloc-1.d |  4 +++-
+ gas/testsuite/gas/or1k/reloc-1.s |  4 ++++
+ include/elf/or1k.h               |  1 +
+ opcodes/or1k-asm.c               |  7 ++++++-
+ 9 files changed, 44 insertions(+), 4 deletions(-)
+
+diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
+index e25da50aafb..530a41fca43 100644
+--- a/bfd/bfd-in2.h
++++ b/bfd/bfd-in2.h
+@@ -5517,6 +5517,7 @@ then it may be truncated to 8 bits.  */
+   BFD_RELOC_OR1K_TLS_TPOFF,
+   BFD_RELOC_OR1K_TLS_DTPOFF,
+   BFD_RELOC_OR1K_TLS_DTPMOD,
++  BFD_RELOC_OR1K_GOT_AHI16,
+ /* H8 elf Relocations.  */
+   BFD_RELOC_H8_DIR16A8,
+diff --git a/bfd/elf32-or1k.c b/bfd/elf32-or1k.c
+index 1f2c88b0b3a..a4a64f73b7c 100644
+--- a/bfd/elf32-or1k.c
++++ b/bfd/elf32-or1k.c
+@@ -808,6 +808,20 @@ static reloc_howto_type or1k_elf_howto_table[] =
+        0,                     /* Source Mask.  */
+        0x03ffffff,            /* Dest Mask.  */
+        TRUE),                 /* PC relative offset?  */
++
++  HOWTO (R_OR1K_GOT_AHI16,     /* type */
++      16,                    /* rightshift */
++      2,                     /* size (0 = byte, 1 = short, 2 = long) */
++      16,                    /* bitsize */
++      FALSE,                 /* pc_relative */
++      0,                     /* bitpos */
++      complain_overflow_signed, /* complain_on_overflow */
++      bfd_elf_generic_reloc, /* special_function */
++      "R_OR1K_GOT_AHI16",    /* name */
++      FALSE,                 /* partial_inplace */
++      0,                     /* src_mask */
++      0xffff,                /* dst_mask */
++      FALSE),                /* pcrel_offset */
+ };
+ /* Map BFD reloc types to Or1k ELF reloc types.  */
+@@ -871,6 +885,7 @@ static const struct or1k_reloc_map or1k_reloc_map[] =
+   { BFD_RELOC_OR1K_TLS_IE_LO13,       R_OR1K_TLS_IE_LO13 },
+   { BFD_RELOC_OR1K_SLO13,     R_OR1K_SLO13 },
+   { BFD_RELOC_OR1K_PLTA26,    R_OR1K_PLTA26 },
++  { BFD_RELOC_OR1K_GOT_AHI16, R_OR1K_GOT_AHI16 },
+ };
+ #define TLS_UNKNOWN    0
+@@ -1080,6 +1095,7 @@ or1k_final_link_relocate (reloc_howto_type *howto, bfd *input_bfd,
+   switch (howto->type)
+     {
+     case R_OR1K_AHI16:
++    case R_OR1K_GOT_AHI16:
+     case R_OR1K_GOTOFF_AHI16:
+     case R_OR1K_TLS_IE_AHI16:
+     case R_OR1K_TLS_LE_AHI16:
+@@ -1344,6 +1360,7 @@ or1k_elf_relocate_section (bfd *output_bfd,
+           }
+         break;
++      case R_OR1K_GOT_AHI16:
+       case R_OR1K_GOT16:
+       case R_OR1K_GOT_PG21:
+       case R_OR1K_GOT_LO13:
+@@ -1435,7 +1452,8 @@ or1k_elf_relocate_section (bfd *output_bfd,
+           /* The GOT_PG21 and GOT_LO13 relocs are pc-relative,
+              while the GOT16 reloc is GOT relative.  */
+           relocation = got_base + off;
+-          if (r_type == R_OR1K_GOT16)
++          if (r_type == R_OR1K_GOT16
++              || r_type == R_OR1K_GOT_AHI16)
+             relocation -= got_sym_value;
+         /* Addend should be zero.  */
+@@ -1945,6 +1963,7 @@ or1k_elf_check_relocs (bfd *abfd,
+           }
+         break;
++      case R_OR1K_GOT_AHI16:
+       case R_OR1K_GOT16:
+       case R_OR1K_GOT_PG21:
+       case R_OR1K_GOT_LO13:
+diff --git a/bfd/libbfd.h b/bfd/libbfd.h
+index 36284d71a9b..6e9e3190bb8 100644
+--- a/bfd/libbfd.h
++++ b/bfd/libbfd.h
+@@ -2702,6 +2702,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
+   "BFD_RELOC_OR1K_TLS_TPOFF",
+   "BFD_RELOC_OR1K_TLS_DTPOFF",
+   "BFD_RELOC_OR1K_TLS_DTPMOD",
++  "BFD_RELOC_OR1K_GOT_AHI16",
+   "BFD_RELOC_H8_DIR16A8",
+   "BFD_RELOC_H8_DIR16R8",
+   "BFD_RELOC_H8_DIR24A8",
+diff --git a/bfd/reloc.c b/bfd/reloc.c
+index e6446a78098..b0003ab1175 100644
+--- a/bfd/reloc.c
++++ b/bfd/reloc.c
+@@ -6164,6 +6164,8 @@ ENUMX
+   BFD_RELOC_OR1K_GOTPC_HI16
+ ENUMX
+   BFD_RELOC_OR1K_GOTPC_LO16
++ENUMX
++  BFD_RELOC_OR1K_GOT_AHI16
+ ENUMX
+   BFD_RELOC_OR1K_GOT16
+ ENUMX
+diff --git a/cpu/or1k.opc b/cpu/or1k.opc
+index 5082a30cee1..85163fc96c9 100644
+--- a/cpu/or1k.opc
++++ b/cpu/or1k.opc
+@@ -173,7 +173,7 @@ static const bfd_reloc_code_real_type or1k_imm16_relocs[][6] = {
+     BFD_RELOC_OR1K_GOT_LO13,
+     BFD_RELOC_UNUSED,
+     BFD_RELOC_UNUSED,
+-    BFD_RELOC_UNUSED },
++    BFD_RELOC_OR1K_GOT_AHI16 },
+   { BFD_RELOC_OR1K_GOTPC_LO16,
+     BFD_RELOC_UNUSED,
+     BFD_RELOC_UNUSED,
+@@ -276,6 +276,11 @@ parse_reloc (const char **strp)
+       str += 5;
+       cls = RCLASS_TPOFF;
+       }
++    else if (strncasecmp (str, "got", 3) == 0)
++      {
++      str += 3;
++      cls = RCLASS_GOT;
++      }
+     if (strncasecmp (str, "hi(", 3) == 0)
+       {
+diff --git a/gas/testsuite/gas/or1k/reloc-1.d b/gas/testsuite/gas/or1k/reloc-1.d
+index d1bcf5608bb..3a001c4ed99 100644
+--- a/gas/testsuite/gas/or1k/reloc-1.d
++++ b/gas/testsuite/gas/or1k/reloc-1.d
+@@ -68,5 +68,7 @@ OFFSET   TYPE              VALUE
+ 000000ec R_OR1K_LO13       x
+ 000000f0 R_OR1K_GOT_LO13   x
+ 000000f4 R_OR1K_SLO13      x
+-
++000000f8 R_OR1K_GOT_AHI16  x
++000000fc R_OR1K_GOT_AHI16  x
++00000100 R_OR1K_GOT_AHI16  x
+diff --git a/gas/testsuite/gas/or1k/reloc-1.s b/gas/testsuite/gas/or1k/reloc-1.s
+index e76abef6532..562609aa869 100644
+--- a/gas/testsuite/gas/or1k/reloc-1.s
++++ b/gas/testsuite/gas/or1k/reloc-1.s
+@@ -74,3 +74,7 @@
+       l.lbz   r5,po(x)(r3)
+       l.lbz   r5,gotpo(x)(r3)
+       l.sb    po(x)(r3),r6
++
++      l.movhi r4,gotha(x)
++      l.ori   r3,r4,gotha(x)
++      l.addi  r3,r4,gotha(x)
+diff --git a/include/elf/or1k.h b/include/elf/or1k.h
+index 0abef046202..7db3cad18eb 100644
+--- a/include/elf/or1k.h
++++ b/include/elf/or1k.h
+@@ -77,6 +77,7 @@ START_RELOC_NUMBERS (elf_or1k_reloc_type)
+   RELOC_NUMBER (R_OR1K_TLS_IE_LO13,   51)
+   RELOC_NUMBER (R_OR1K_SLO13,         52)
+   RELOC_NUMBER (R_OR1K_PLTA26,        53)
++  RELOC_NUMBER (R_OR1K_GOT_AHI16,     54)
+ END_RELOC_NUMBERS (R_OR1K_max)
+ #define EF_OR1K_NODELAY (1UL << 0)
+diff --git a/opcodes/or1k-asm.c b/opcodes/or1k-asm.c
+index 7d058d03f5f..332f4b7a9b5 100644
+--- a/opcodes/or1k-asm.c
++++ b/opcodes/or1k-asm.c
+@@ -177,7 +177,7 @@ static const bfd_reloc_code_real_type or1k_imm16_relocs[][6] = {
+     BFD_RELOC_OR1K_GOT_LO13,
+     BFD_RELOC_UNUSED,
+     BFD_RELOC_UNUSED,
+-    BFD_RELOC_UNUSED },
++    BFD_RELOC_OR1K_GOT_AHI16 },
+   { BFD_RELOC_OR1K_GOTPC_LO16,
+     BFD_RELOC_UNUSED,
+     BFD_RELOC_UNUSED,
+@@ -280,6 +280,11 @@ parse_reloc (const char **strp)
+       str += 5;
+       cls = RCLASS_TPOFF;
+       }
++    else if (strncasecmp (str, "got", 3) == 0)
++      {
++      str += 3;
++      cls = RCLASS_GOT;
++      }
+     if (strncasecmp (str, "hi(", 3) == 0)
+       {
+-- 
+2.25.1
+
diff --git a/package/binutils/2.32/0012-or1k-Avoid-R_OR1K_GOT16-overflow-failures-in-presenc.patch b/package/binutils/2.32/0012-or1k-Avoid-R_OR1K_GOT16-overflow-failures-in-presenc.patch
new file mode 100644 (file)
index 0000000..adc6f5f
--- /dev/null
@@ -0,0 +1,61 @@
+From 0f61f76454a9420f158f626cb09a4fbc08c3709e Mon Sep 17 00:00:00 2001
+From: Stafford Horne <shorne@gmail.com>
+Date: Sun, 2 May 2021 06:02:16 +0900
+Subject: [PATCH] or1k: Avoid R_OR1K_GOT16 overflow failures in presence
+ of R_OR1K_GOT_AHI16
+
+Now that we support R_OR1K_GOT_AHI16 we can relax the R_OR1K_GOT16
+overflow validation check if the section has R_OR1K_GOT_AHI16.
+
+We cannot simple disable R_OR1K_GOT16 overflow validation as there will
+still be binaries that will have only R_OR1K_GOT16.  The
+R_OR1K_GOT_AHI16 relocation will only be added by GCC when building with
+the option -mcmodel=large.
+
+This assumes that R_OR1K_GOT_AHI16 will come before R_OR1K_GOT16, which
+is the code pattern that will be emitted by GCC.
+
+bfd/ChangeLog:
+
+       PR 21464
+       * elf32-or1k.c (or1k_elf_relocate_section): Relax R_OR1K_GOT16
+       overflow check if we have R_OR1K_GOT_AHI16 followed by
+       R_OR1K_GOT16.
+
+Signed-off-by: Giulio Benetti <giulio.benetti@benettiengineering.com>
+---
+ bfd/elf32-or1k.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/bfd/elf32-or1k.c b/bfd/elf32-or1k.c
+index a4a64f73b7c..07fff3602a3 100644
+--- a/bfd/elf32-or1k.c
++++ b/bfd/elf32-or1k.c
+@@ -1248,6 +1248,7 @@ or1k_elf_relocate_section (bfd *output_bfd,
+   asection *sgot, *splt;
+   bfd_vma plt_base, got_base, got_sym_value;
+   bfd_boolean ret_val = TRUE;
++  bfd_boolean saw_gotha = FALSE;
+   if (htab == NULL)
+     return FALSE;
+@@ -1456,6 +1457,16 @@ or1k_elf_relocate_section (bfd *output_bfd,
+               || r_type == R_OR1K_GOT_AHI16)
+             relocation -= got_sym_value;
++          if (r_type == R_OR1K_GOT_AHI16)
++            saw_gotha = TRUE;
++
++          /* If we have a R_OR1K_GOT16 followed by a R_OR1K_GOT_AHI16
++             relocation we assume the code is doing the right thing to avoid
++             overflows.  Here we mask the lower 16-bit of the relocation to
++             avoid overflow validation failures.  */
++          if (r_type == R_OR1K_GOT16 && saw_gotha)
++            relocation &= 0xffff;
++
+         /* Addend should be zero.  */
+         if (rel->r_addend != 0)
+           {
+-- 
+2.25.1
+
diff --git a/package/binutils/2.32/0013-or1k-Support-large-plt_relocs-when-generating-plt-en.patch b/package/binutils/2.32/0013-or1k-Support-large-plt_relocs-when-generating-plt-en.patch
new file mode 100644 (file)
index 0000000..dc0431e
--- /dev/null
@@ -0,0 +1,500 @@
+From 36c7de7ef77ab0c30cb33e2c7ea7a6f4e3052c73 Mon Sep 17 00:00:00 2001
+From: Stafford Horne <shorne@gmail.com>
+Date: Sun, 2 May 2021 06:02:17 +0900
+Subject: [PATCH] or1k: Support large plt_relocs when generating plt
+ entries
+
+The current PLT generation code will generate invalid code when the PLT
+relocation offset exceeds 64k.  This fixes the issue by detecting large
+plt_reloc offsets and generare code sequences to create larger plt
+relocations.
+
+The "large" plt code needs 2 extra instructions to create 32-bit offsets.
+
+bfd/ChangeLog:
+
+       PR 27746
+       * elf32-or1k.c (PLT_ENTRY_SIZE_LARGE, PLT_MAX_INSN_COUNT,
+       OR1K_ADD, OR1K_ORI): New macros to help with plt creation.
+       (elf_or1k_link_hash_table): New field plt_count.
+       (elf_or1k_link_hash_entry): New field plt_index.
+       (elf_or1k_plt_entry_size): New function.
+       (or1k_write_plt_entry): Update to support variable size PLTs.
+       (or1k_elf_finish_dynamic_sections): Use new or1k_write_plt_entry
+       API.
+       (or1k_elf_finish_dynamic_symbol): Update to write large PLTs
+       when needed.
+       (allocate_dynrelocs): Use elf_or1k_plt_entry_size to account for
+       PLT size.
+
+ld/ChangeLog:
+
+       PR 27746
+       testsuite/ld-or1k/or1k.exp (or1kplttests): Add tests for linking
+       along with gotha() relocations.
+       testsuite/ld-or1k/gotha1.dd: New file.
+       testsuite/ld-or1k/gotha1.s: New file.
+       testsuite/ld-or1k/gotha2.dd: New file.
+       testsuite/ld-or1k/gotha2.s: New file
+       testsuite/ld-or1k/pltlib.s (x): Define size to avoid link
+       failure.
+
+Signed-off-by: Giulio Benetti <giulio.benetti@benettiengineering.com>
+---
+ bfd/elf32-or1k.c               | 149 ++++++++++++++++++++++++---------
+ ld/testsuite/ld-or1k/gotha1.dd |  34 ++++++++
+ ld/testsuite/ld-or1k/gotha1.s  |  24 ++++++
+ ld/testsuite/ld-or1k/gotha2.dd |  21 +++++
+ ld/testsuite/ld-or1k/gotha2.s  |  22 +++++
+ ld/testsuite/ld-or1k/or1k.exp  |   8 ++
+ ld/testsuite/ld-or1k/pltlib.s  |   1 +
+ 7 files changed, 220 insertions(+), 39 deletions(-)
+ create mode 100644 ld/testsuite/ld-or1k/gotha1.dd
+ create mode 100644 ld/testsuite/ld-or1k/gotha1.s
+ create mode 100644 ld/testsuite/ld-or1k/gotha2.dd
+ create mode 100644 ld/testsuite/ld-or1k/gotha2.s
+
+diff --git a/bfd/elf32-or1k.c b/bfd/elf32-or1k.c
+index 07fff3602a3..fcebbe5f23a 100644
+--- a/bfd/elf32-or1k.c
++++ b/bfd/elf32-or1k.c
+@@ -30,10 +30,14 @@
+ #define N_ONES(X)     (((bfd_vma)2 << (X)) - 1)
+ #define PLT_ENTRY_SIZE 16
++#define PLT_ENTRY_SIZE_LARGE (6*4)
++#define PLT_MAX_INSN_COUNT 6
+ #define OR1K_MOVHI(D)         (0x18000000 | (D << 21))
+ #define OR1K_ADRP(D)          (0x08000000 | (D << 21))
+ #define OR1K_LWZ(D,A)         (0x84000000 | (D << 21) | (A << 16))
++#define OR1K_ADD(D,A,B)               (0xE0000000 | (D << 21) | (A << 16) | (B << 11))
++#define OR1K_ORI(D,A)         (0xA8000000 | (D << 21) | (A << 16))
+ #define OR1K_ORI0(D)          (0xA8000000 | (D << 21))
+ #define OR1K_JR(B)            (0x44000000 | (B << 11))
+ #define OR1K_NOP              0x15000000
+@@ -903,6 +907,8 @@ struct elf_or1k_link_hash_entry
+   /* Track dynamic relocs copied for this symbol.  */
+   struct elf_dyn_relocs *dyn_relocs;
++  /* For calculating PLT size.  */
++  bfd_vma plt_index;
+   /* Track type of TLS access.  */
+   unsigned char tls_type;
+ };
+@@ -930,9 +936,20 @@ struct elf_or1k_link_hash_table
+   /* Small local sym to section mapping cache.  */
+   struct sym_cache sym_sec;
++  bfd_vma plt_count;
+   bfd_boolean saw_plta;
+ };
++static size_t
++elf_or1k_plt_entry_size (bfd_vma plt_index)
++{
++  bfd_vma plt_reloc;
++
++  plt_reloc = plt_index * sizeof (Elf32_External_Rela);
++
++  return (plt_reloc > 0xffff) ? PLT_ENTRY_SIZE_LARGE : PLT_ENTRY_SIZE;
++}
++
+ /* Get the ELF linker hash table from a link_info structure.  */
+ #define or1k_elf_hash_table(p) \
+   (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \
+@@ -2176,33 +2193,46 @@ or1k_elf_check_relocs (bfd *abfd,
+ }
+ static void
+-or1k_write_plt_entry (bfd *output_bfd, bfd_byte *contents, unsigned insn1,
+-                    unsigned insn2, unsigned insn3, unsigned insnj)
++or1k_write_plt_entry (bfd *output_bfd, bfd_byte *contents, unsigned insnj,
++                    unsigned insns[], size_t insn_count)
+ {
+   unsigned nodelay = elf_elfheader (output_bfd)->e_flags & EF_OR1K_NODELAY;
+-  unsigned insn4;
++  unsigned output_insns[PLT_MAX_INSN_COUNT];
++
++  /* Copy instructions into the output buffer.  */
++  for (size_t i = 0; i < insn_count; i++)
++    output_insns[i] = insns[i];
+   /* Honor the no-delay-slot setting.  */
+-  if (insn3 == OR1K_NOP)
++  if (insns[insn_count-1] == OR1K_NOP)
+     {
+-      insn4 = insn3;
++      unsigned slot1, slot2;
++
+       if (nodelay)
+-      insn3 = insnj;
++      slot1 = insns[insn_count-2], slot2 = insnj;
+       else
+-      insn3 = insn2, insn2 = insnj;
++      slot1 = insnj, slot2 = insns[insn_count-2];
++
++      output_insns[insn_count-2] = slot1;
++      output_insns[insn_count-1] = slot2;
++      output_insns[insn_count]   = OR1K_NOP;
+     }
+   else
+     {
++      unsigned slot1, slot2;
++
+       if (nodelay)
+-      insn4 = insnj;
++      slot1 = insns[insn_count-1], slot2 = insnj;
+       else
+-      insn4 = insn3, insn3 = insnj;
++      slot1 = insnj, slot2 = insns[insn_count-1];
++
++      output_insns[insn_count-1] = slot1;
++      output_insns[insn_count]   = slot2;
+     }
+-  bfd_put_32 (output_bfd, insn1, contents);
+-  bfd_put_32 (output_bfd, insn2, contents + 4);
+-  bfd_put_32 (output_bfd, insn3, contents + 8);
+-  bfd_put_32 (output_bfd, insn4, contents + 12);
++  /* Write out the output buffer.  */
++  for (size_t i = 0; i < (insn_count+1); i++)
++    bfd_put_32 (output_bfd, output_insns[i], contents + (i*4));
+ }
+ /* Finish up the dynamic sections.  */
+@@ -2269,7 +2299,8 @@ or1k_elf_finish_dynamic_sections (bfd *output_bfd,
+       splt = htab->root.splt;
+       if (splt && splt->size > 0)
+       {
+-        unsigned plt0, plt1, plt2;
++        unsigned plt[PLT_MAX_INSN_COUNT];
++        size_t plt_insn_count = 3;
+         bfd_vma got_addr = sgot->output_section->vma + sgot->output_offset;
+         /* Note we force 16 byte alignment on the .got, so that
+@@ -2280,27 +2311,27 @@ or1k_elf_finish_dynamic_sections (bfd *output_bfd,
+             bfd_vma pc = splt->output_section->vma + splt->output_offset;
+             unsigned pa = ((got_addr >> 13) - (pc >> 13)) & 0x1fffff;
+             unsigned po = got_addr & 0x1fff;
+-            plt0 = OR1K_ADRP(12) | pa;
+-            plt1 = OR1K_LWZ(15,12) | (po + 8);
+-            plt2 = OR1K_LWZ(12,12) | (po + 4);
++            plt[0] = OR1K_ADRP(12) | pa;
++            plt[1] = OR1K_LWZ(15,12) | (po + 8);
++            plt[2] = OR1K_LWZ(12,12) | (po + 4);
+           }
+         else if (bfd_link_pic (info))
+           {
+-            plt0 = OR1K_LWZ(15, 16) | 8;      /* .got+8 */
+-            plt1 = OR1K_LWZ(12, 16) | 4;      /* .got+4 */
+-            plt2 = OR1K_NOP;
++            plt[0] = OR1K_LWZ(15, 16) | 8;    /* .got+8 */
++            plt[1] = OR1K_LWZ(12, 16) | 4;    /* .got+4 */
++            plt[2] = OR1K_NOP;
+           }
+         else
+           {
+             unsigned ha = ((got_addr + 0x8000) >> 16) & 0xffff;
+             unsigned lo = got_addr & 0xffff;
+-            plt0 = OR1K_MOVHI(12) | ha;
+-            plt1 = OR1K_LWZ(15,12) | (lo + 8);
+-            plt2 = OR1K_LWZ(12,12) | (lo + 4);
++            plt[0] = OR1K_MOVHI(12) | ha;
++            plt[1] = OR1K_LWZ(15,12) | (lo + 8);
++            plt[2] = OR1K_LWZ(12,12) | (lo + 4);
+           }
+-        or1k_write_plt_entry (output_bfd, splt->contents,
+-                              plt0, plt1, plt2, OR1K_JR(15));
++        or1k_write_plt_entry (output_bfd, splt->contents, OR1K_JR(15),
++                              plt, plt_insn_count);
+         elf_section_data (splt->output_section)->this_hdr.sh_entsize = 4;
+       }
+@@ -2343,7 +2374,8 @@ or1k_elf_finish_dynamic_symbol (bfd *output_bfd,
+   if (h->plt.offset != (bfd_vma) -1)
+     {
+-      unsigned int plt0, plt1, plt2;
++      unsigned int plt[PLT_MAX_INSN_COUNT];
++      size_t plt_insn_count = 3;
+       asection *splt;
+       asection *sgot;
+       asection *srela;
+@@ -2355,6 +2387,7 @@ or1k_elf_finish_dynamic_symbol (bfd *output_bfd,
+       bfd_vma got_offset;
+       bfd_vma got_addr;
+       Elf_Internal_Rela rela;
++      bfd_boolean large_plt_entry;
+       /* This symbol has an entry in the procedure linkage table.  Set
+        it up.  */
+@@ -2372,10 +2405,13 @@ or1k_elf_finish_dynamic_symbol (bfd *output_bfd,
+        corresponds to this symbol.  This is the index of this symbol
+        in all the symbols for which we are making plt entries.  The
+        first entry in the procedure linkage table is reserved.  */
+-      plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1;
++      plt_index = ((struct elf_or1k_link_hash_entry *) h)->plt_index;
+       plt_addr = plt_base_addr + h->plt.offset;
+       plt_reloc = plt_index * sizeof (Elf32_External_Rela);
++      large_plt_entry = (elf_or1k_plt_entry_size (plt_index)
++                       == PLT_ENTRY_SIZE_LARGE);
++
+       /* Get the offset into the .got table of the entry that
+       corresponds to this function.  Each .got entry is 4 bytes.
+       The first three are reserved.  */
+@@ -2387,27 +2423,57 @@ or1k_elf_finish_dynamic_symbol (bfd *output_bfd,
+       {
+         unsigned pa = ((got_addr >> 13) - (plt_addr >> 13)) & 0x1fffff;
+         unsigned po = (got_addr & 0x1fff);
+-        plt0 = OR1K_ADRP(12) | pa;
+-        plt1 = OR1K_LWZ(12,12) | po;
+-        plt2 = OR1K_ORI0(11) | plt_reloc;
++        plt[0] = OR1K_ADRP(12) | pa;
++        plt[1] = OR1K_LWZ(12,12) | po;
++        plt[2] = OR1K_ORI0(11) | plt_reloc;
+       }
+       else if (bfd_link_pic (info))
+       {
+-        plt0 = OR1K_LWZ(12,16) | got_offset;
+-        plt1 = OR1K_ORI0(11) | plt_reloc;
+-        plt2 = OR1K_NOP;
++        if (large_plt_entry)
++          {
++            unsigned gotha = ((got_offset + 0x8000) >> 16) & 0xffff;
++            unsigned got = got_offset & 0xffff;
++            unsigned pltrelhi = (plt_reloc >> 16) & 0xffff;
++            unsigned pltrello = plt_reloc & 0xffff;
++
++            plt[0] = OR1K_MOVHI(12) | gotha;
++            plt[1] = OR1K_ADD(12,12,16);
++            plt[2] = OR1K_LWZ(12,12) | got;
++            plt[3] = OR1K_MOVHI(11) | pltrelhi;
++            plt[4] = OR1K_ORI(11,11) | pltrello;
++            plt_insn_count = 5;
++          }
++        else
++          {
++            plt[0] = OR1K_LWZ(12,16) | got_offset;
++            plt[1] = OR1K_ORI0(11) | plt_reloc;
++            plt[2] = OR1K_NOP;
++          }
+       }
+       else
+       {
+         unsigned ha = ((got_addr + 0x8000) >> 16) & 0xffff;
+         unsigned lo = got_addr & 0xffff;
+-        plt0 = OR1K_MOVHI(12) | ha;
+-        plt1 = OR1K_LWZ(12,12) | lo;
+-        plt2 = OR1K_ORI0(11) | plt_reloc;
++        plt[0] = OR1K_MOVHI(12) | ha;
++        plt[1] = OR1K_LWZ(12,12) | lo;
++        plt[2] = OR1K_ORI0(11) | plt_reloc;
++      }
++
++      /* For large code model we fixup the non-PIC PLT relocation instructions
++       here.  */
++      if (large_plt_entry && !bfd_link_pic (info))
++      {
++        unsigned pltrelhi = (plt_reloc >> 16) & 0xffff;
++        unsigned pltrello = plt_reloc & 0xffff;
++
++        plt[2] = OR1K_MOVHI(11) | pltrelhi;
++        plt[3] = OR1K_ORI(11,11) | pltrello;
++        plt[4] = OR1K_NOP;
++        plt_insn_count = 5;
+       }
+       or1k_write_plt_entry (output_bfd, splt->contents + h->plt.offset,
+-                          plt0, plt1, plt2, OR1K_JR(12));
++                          OR1K_JR(12), plt, plt_insn_count);
+       /* Fill in the entry in the global offset table.  */
+       bfd_put_32 (output_bfd, plt_addr, sgot->contents + got_offset);
+@@ -2699,11 +2765,16 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
+       if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, bfd_link_pic (info), h))
+       {
+         asection *s = htab->root.splt;
++        bfd_vma plt_index;
++
++        /* Track the index of our plt entry for use in calculating size.  */
++        plt_index = htab->plt_count++;
++        ((struct elf_or1k_link_hash_entry *) h)->plt_index = plt_index;
+         /* If this is the first .plt entry, make room for the special
+            first entry.  */
+         if (s->size == 0)
+-          s->size = PLT_ENTRY_SIZE;
++          s->size = elf_or1k_plt_entry_size (plt_index);
+         h->plt.offset = s->size;
+@@ -2720,7 +2791,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
+           }
+         /* Make room for this entry.  */
+-        s->size += PLT_ENTRY_SIZE;
++        s->size += elf_or1k_plt_entry_size (plt_index);
+         /* We also need to make an entry in the .got.plt section, which
+            will be placed in the .got section by the linker script.  */
+diff --git a/ld/testsuite/ld-or1k/gotha1.dd b/ld/testsuite/ld-or1k/gotha1.dd
+new file mode 100644
+index 00000000000..0ad1f8f5399
+--- /dev/null
++++ b/ld/testsuite/ld-or1k/gotha1.dd
+@@ -0,0 +1,34 @@
++
++.*\.x:     file format elf32-or1k
++
++
++Disassembly of section \.plt:
++
++[0-9a-f]+ <\.plt>:
++ +[0-9a-f]+:  19 80 00 00     l\.movhi r12,0x0
++ +[0-9a-f]+:  85 ec [0-9a-f]+ [0-9a-f]+       l\.lwz r15,[0-9]+\(r12\)
++ +[0-9a-f]+:  44 00 78 00     l\.jr r15
++ +[0-9a-f]+:  85 8c [0-9a-f]+ [0-9a-f]+       l\.lwz r12,[0-9]+\(r12\)
++ +[0-9a-f]+:  19 80 00 00     l\.movhi r12,0x0
++ +[0-9a-f]+:  85 8c [0-9a-f]+ [0-9a-f]+       l\.lwz r12,[0-9]+\(r12\)
++ +[0-9a-f]+:  44 00 60 00     l\.jr r12
++ +[0-9a-f]+:  a9 60 00 00     l\.ori r11,r0,0x0
++
++Disassembly of section \.text:
++
++[0-9a-f]+ <_start>:
++ +[0-9a-f]+:  9c 21 ff fc     l\.addi r1,r1,-4
++ +[0-9a-f]+:  d4 01 48 00     l\.sw 0\(r1\),r9
++ +[0-9a-f]+:  04 00 00 02     l\.jal [0-9a-f]+ <_start\+0x10>
++ +[0-9a-f]+:  1a 60 00 00     l\.movhi r19,0x0
++ +[0-9a-f]+:  aa 73 [0-9a-f]+ [0-9a-f]+       l\.ori r19,r19,0x[0-9a-f]+
++ +[0-9a-f]+:  e2 73 48 00     l\.add r19,r19,r9
++ +[0-9a-f]+:  1a 20 00 00     l\.movhi r17,0x0
++ +[0-9a-f]+:  e2 31 98 00     l\.add r17,r17,r19
++ +[0-9a-f]+:  86 31 00 10     l\.lwz r17,16\(r17\)
++ +[0-9a-f]+:  84 71 00 00     l\.lwz r3,0\(r17\)
++ +[0-9a-f]+:  07 ff ff f2     l\.jal [0-9a-f]+ <\.plt\+0x10>
++ +[0-9a-f]+:  15 00 00 00     l\.nop 0x0
++ +[0-9a-f]+:  85 21 00 00     l\.lwz r9,0\(r1\)
++ +[0-9a-f]+:  44 00 48 00     l\.jr r9
++ +[0-9a-f]+:  9c 21 00 04     l\.addi r1,r1,4
+diff --git a/ld/testsuite/ld-or1k/gotha1.s b/ld/testsuite/ld-or1k/gotha1.s
+new file mode 100644
+index 00000000000..42b16db425c
+--- /dev/null
++++ b/ld/testsuite/ld-or1k/gotha1.s
+@@ -0,0 +1,24 @@
++      .data
++      .p2align 16
++
++      .text
++      .globl  _start
++_start:
++      l.addi  r1, r1, -4
++      l.sw    0(r1), r9
++
++      l.jal   8
++       l.movhi        r19, gotpchi(_GLOBAL_OFFSET_TABLE_-4)
++      l.ori   r19, r19, gotpclo(_GLOBAL_OFFSET_TABLE_+0)
++      l.add   r19, r19, r9
++
++      l.movhi r17, gotha(x)
++      l.add   r17, r17, r19
++      l.lwz   r17, got(x)(r17)
++      l.lwz   r3, 0(r17)
++
++      l.jal   plt(func)
++       l.nop
++      l.lwz   r9, 0(r1)
++      l.jr    r9
++       l.addi r1, r1, 4
+diff --git a/ld/testsuite/ld-or1k/gotha2.dd b/ld/testsuite/ld-or1k/gotha2.dd
+new file mode 100644
+index 00000000000..fe09da5466b
+--- /dev/null
++++ b/ld/testsuite/ld-or1k/gotha2.dd
+@@ -0,0 +1,21 @@
++
++.*\.x:     file format elf32-or1k
++
++
++Disassembly of section \.text:
++
++[0-9a-f]+ <test>:
++ +[0-9a-f]+:  9c 21 ff f8     l\.addi r1,r1,-8
++ +[0-9a-f]+:  d4 01 80 00     l\.sw 0\(r1\),r16
++ +[0-9a-f]+:  d4 01 48 04     l\.sw 4\(r1\),r9
++ +[0-9a-f]+:  04 00 [0-9a-f]+ [0-9a-f]+       l\.jal [0-9a-f]+ <test\+0x14>
++ +[0-9a-f]+:  1a 00 00 00     l\.movhi r16,0x0
++ +[0-9a-f]+:  aa 10 [0-9a-f]+ [0-9a-f]+       l\.ori r16,r16,0x[0-9a-f]+
++ +[0-9a-f]+:  e2 10 48 00     l\.add r16,r16,r9
++ +[0-9a-f]+:  1a 20 00 00     l\.movhi r17,0x0
++ +[0-9a-f]+:  e2 31 80 00     l\.add r17,r17,r16
++ +[0-9a-f]+:  86 31 00 0c     l\.lwz r17,12\(r17\)
++ +[0-9a-f]+:  85 21 00 04     l\.lwz r9,4\(r1\)
++ +[0-9a-f]+:  86 01 00 00     l\.lwz r16,0\(r1\)
++ +[0-9a-f]+:  44 00 48 00     l\.jr r9
++ +[0-9a-f]+:  9c 21 00 08     l\.addi r1,r1,8
+diff --git a/ld/testsuite/ld-or1k/gotha2.s b/ld/testsuite/ld-or1k/gotha2.s
+new file mode 100644
+index 00000000000..164b282f2dd
+--- /dev/null
++++ b/ld/testsuite/ld-or1k/gotha2.s
+@@ -0,0 +1,22 @@
++      .section        .text
++      .align 4
++      .global test
++      .type   test, @function
++test:
++      l.addi  r1, r1, -8
++      l.sw    0(r1), r16
++      l.sw    4(r1), r9
++
++      l.jal   8
++       l.movhi        r16, gotpchi(_GLOBAL_OFFSET_TABLE_-4)
++      l.ori   r16, r16, gotpclo(_GLOBAL_OFFSET_TABLE_+0)
++      l.add   r16, r16, r9
++
++      l.movhi r17, gotha(i)
++      l.add   r17, r17, r16
++      l.lwz   r17, got(i)(r17)
++
++      l.lwz   r9, 4(r1)
++      l.lwz   r16, 0(r1)
++      l.jr    r9
++       l.addi r1, r1, 8
+diff --git a/ld/testsuite/ld-or1k/or1k.exp b/ld/testsuite/ld-or1k/or1k.exp
+index 24cdbe5fbf3..9cebc49b946 100644
+--- a/ld/testsuite/ld-or1k/or1k.exp
++++ b/ld/testsuite/ld-or1k/or1k.exp
+@@ -53,6 +53,14 @@ set or1kplttests {
+      "" {plt1.s}
+      {{objdump -dr plt1.x.dd}}
+      "plt1.x"}
++    {"gotha exec plt" "tmpdir/libpltlib.so" ""
++     "" {gotha1.s}
++     {{objdump -dr gotha1.dd}}
++     "gotha1.x"}
++    {"gotha -fpic -shared" "-fpic -shared" ""
++     "" {gotha2.s}
++     {{objdump -dr gotha2.dd}}
++     "gotha2.x"}
+ }
+ # Not implemented yet
+diff --git a/ld/testsuite/ld-or1k/pltlib.s b/ld/testsuite/ld-or1k/pltlib.s
+index baf76ca1af7..8b4d7ba48fd 100644
+--- a/ld/testsuite/ld-or1k/pltlib.s
++++ b/ld/testsuite/ld-or1k/pltlib.s
+@@ -1,5 +1,6 @@
+       .section .data
+       .globl x, y
++      .size x, 4
+ x:    .long 33
+ y:    .long 44
+-- 
+2.25.1
+
diff --git a/package/binutils/2.34/0004-or1k-Implement-relocation-R_OR1K_GOT_AHI16-for-gotha.patch b/package/binutils/2.34/0004-or1k-Implement-relocation-R_OR1K_GOT_AHI16-for-gotha.patch
new file mode 100644 (file)
index 0000000..5edef90
--- /dev/null
@@ -0,0 +1,256 @@
+From 5fb945116ba058eb8f032f94ab2e0c71024388ec Mon Sep 17 00:00:00 2001
+From: Stafford Horne <shorne@gmail.com>
+Date: Sun, 2 May 2021 06:02:15 +0900
+Subject: [PATCH] or1k: Implement relocation R_OR1K_GOT_AHI16 for gotha()
+
+The gotha() relocation mnemonic will be outputted by OpenRISC GCC when
+using the -mcmodel=large option.  This relocation is used along with
+got() to generate 32-bit GOT offsets.  This increases the previous GOT
+offset limit from the previous 16-bit (64K) limit.
+
+This is needed on large binaries where the GOT grows larger than 64k.
+
+bfd/ChangeLog:
+
+       PR 21464
+       * bfd-in2.h: Add BFD_RELOC_OR1K_GOT_AHI16 relocation.
+       * elf32-or1k.c (or1k_elf_howto_table, or1k_reloc_map): Likewise.
+       (or1k_final_link_relocate, or1k_elf_relocate_section,
+       or1k_elf_check_relocs): Likewise.
+       * libbfd.h (bfd_reloc_code_real_names): Likewise.
+       * reloc.c: Likewise.
+
+cpu/ChangeLog:
+
+       PR 21464
+       * or1k.opc (or1k_imm16_relocs, parse_reloc): Define parse logic
+       for gotha() relocation.
+
+include/ChangeLog:
+
+       PR 21464
+       * elf/or1k.h (elf_or1k_reloc_type): Define R_OR1K_GOT_AHI16 number.
+
+opcodes/ChangeLog:
+
+       PR 21464
+       * or1k-asm.c: Regenerate.
+
+gas/ChangeLog:
+
+       PR 21464
+       * testsuite/gas/or1k/reloc-1.s: Add test for new relocation.
+       * testsuite/gas/or1k/reloc-1.d: Add test result for new
+       relocation.
+
+Cc: Giulio Benetti <giulio.benetti@benettiengineering.com>
+
+fixup reloc, add tests
+
+Signed-off-by: Giulio Benetti <giulio.benetti@benettiengineering.com>
+---
+ bfd/bfd-in2.h                    |  1 +
+ bfd/elf32-or1k.c                 | 21 ++++++++++++++++++++-
+ bfd/libbfd.h                     |  1 +
+ bfd/reloc.c                      |  2 ++
+ cpu/or1k.opc                     |  7 ++++++-
+ gas/testsuite/gas/or1k/reloc-1.d |  4 +++-
+ gas/testsuite/gas/or1k/reloc-1.s |  4 ++++
+ include/elf/or1k.h               |  1 +
+ opcodes/or1k-asm.c               |  7 ++++++-
+ 9 files changed, 44 insertions(+), 4 deletions(-)
+
+diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
+index 7c13bc8c91a..ae1082a67c2 100644
+--- a/bfd/bfd-in2.h
++++ b/bfd/bfd-in2.h
+@@ -5017,6 +5017,7 @@ then it may be truncated to 8 bits.  */
+   BFD_RELOC_OR1K_TLS_TPOFF,
+   BFD_RELOC_OR1K_TLS_DTPOFF,
+   BFD_RELOC_OR1K_TLS_DTPMOD,
++  BFD_RELOC_OR1K_GOT_AHI16,
+ /* H8 elf Relocations.  */
+   BFD_RELOC_H8_DIR16A8,
+diff --git a/bfd/elf32-or1k.c b/bfd/elf32-or1k.c
+index 58246875546..1273fbacb3c 100644
+--- a/bfd/elf32-or1k.c
++++ b/bfd/elf32-or1k.c
+@@ -808,6 +808,20 @@ static reloc_howto_type or1k_elf_howto_table[] =
+        0,                     /* Source Mask.  */
+        0x03ffffff,            /* Dest Mask.  */
+        TRUE),                 /* PC relative offset?  */
++
++  HOWTO (R_OR1K_GOT_AHI16,     /* type */
++      16,                    /* rightshift */
++      2,                     /* size (0 = byte, 1 = short, 2 = long) */
++      16,                    /* bitsize */
++      FALSE,                 /* pc_relative */
++      0,                     /* bitpos */
++      complain_overflow_signed, /* complain_on_overflow */
++      bfd_elf_generic_reloc, /* special_function */
++      "R_OR1K_GOT_AHI16",    /* name */
++      FALSE,                 /* partial_inplace */
++      0,                     /* src_mask */
++      0xffff,                /* dst_mask */
++      FALSE),                /* pcrel_offset */
+ };
+ /* Map BFD reloc types to Or1k ELF reloc types.  */
+@@ -871,6 +885,7 @@ static const struct or1k_reloc_map or1k_reloc_map[] =
+   { BFD_RELOC_OR1K_TLS_IE_LO13,       R_OR1K_TLS_IE_LO13 },
+   { BFD_RELOC_OR1K_SLO13,     R_OR1K_SLO13 },
+   { BFD_RELOC_OR1K_PLTA26,    R_OR1K_PLTA26 },
++  { BFD_RELOC_OR1K_GOT_AHI16, R_OR1K_GOT_AHI16 },
+ };
+ #define TLS_UNKNOWN    0
+@@ -1080,6 +1095,7 @@ or1k_final_link_relocate (reloc_howto_type *howto, bfd *input_bfd,
+   switch (howto->type)
+     {
+     case R_OR1K_AHI16:
++    case R_OR1K_GOT_AHI16:
+     case R_OR1K_GOTOFF_AHI16:
+     case R_OR1K_TLS_IE_AHI16:
+     case R_OR1K_TLS_LE_AHI16:
+@@ -1344,6 +1360,7 @@ or1k_elf_relocate_section (bfd *output_bfd,
+           }
+         break;
++      case R_OR1K_GOT_AHI16:
+       case R_OR1K_GOT16:
+       case R_OR1K_GOT_PG21:
+       case R_OR1K_GOT_LO13:
+@@ -1435,7 +1452,8 @@ or1k_elf_relocate_section (bfd *output_bfd,
+           /* The GOT_PG21 and GOT_LO13 relocs are pc-relative,
+              while the GOT16 reloc is GOT relative.  */
+           relocation = got_base + off;
+-          if (r_type == R_OR1K_GOT16)
++          if (r_type == R_OR1K_GOT16
++              || r_type == R_OR1K_GOT_AHI16)
+             relocation -= got_sym_value;
+         /* Addend should be zero.  */
+@@ -1943,6 +1961,7 @@ or1k_elf_check_relocs (bfd *abfd,
+           }
+         break;
++      case R_OR1K_GOT_AHI16:
+       case R_OR1K_GOT16:
+       case R_OR1K_GOT_PG21:
+       case R_OR1K_GOT_LO13:
+diff --git a/bfd/libbfd.h b/bfd/libbfd.h
+index d97d4e57a77..9edc71e0558 100644
+--- a/bfd/libbfd.h
++++ b/bfd/libbfd.h
+@@ -2704,6 +2704,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
+   "BFD_RELOC_OR1K_TLS_TPOFF",
+   "BFD_RELOC_OR1K_TLS_DTPOFF",
+   "BFD_RELOC_OR1K_TLS_DTPMOD",
++  "BFD_RELOC_OR1K_GOT_AHI16",
+   "BFD_RELOC_H8_DIR16A8",
+   "BFD_RELOC_H8_DIR16R8",
+   "BFD_RELOC_H8_DIR24A8",
+diff --git a/bfd/reloc.c b/bfd/reloc.c
+index 33cd67150cf..f57ad14a501 100644
+--- a/bfd/reloc.c
++++ b/bfd/reloc.c
+@@ -6175,6 +6175,8 @@ ENUMX
+   BFD_RELOC_OR1K_GOTPC_HI16
+ ENUMX
+   BFD_RELOC_OR1K_GOTPC_LO16
++ENUMX
++  BFD_RELOC_OR1K_GOT_AHI16
+ ENUMX
+   BFD_RELOC_OR1K_GOT16
+ ENUMX
+diff --git a/cpu/or1k.opc b/cpu/or1k.opc
+index f0adcbb00a5..5d20a1f33a7 100644
+--- a/cpu/or1k.opc
++++ b/cpu/or1k.opc
+@@ -193,7 +193,7 @@ static const bfd_reloc_code_real_type or1k_imm16_relocs[][6] = {
+     BFD_RELOC_OR1K_GOT_LO13,
+     BFD_RELOC_UNUSED,
+     BFD_RELOC_UNUSED,
+-    BFD_RELOC_UNUSED },
++    BFD_RELOC_OR1K_GOT_AHI16 },
+   { BFD_RELOC_OR1K_GOTPC_LO16,
+     BFD_RELOC_UNUSED,
+     BFD_RELOC_UNUSED,
+@@ -296,6 +296,11 @@ parse_reloc (const char **strp)
+       str += 5;
+       cls = RCLASS_TPOFF;
+       }
++    else if (strncasecmp (str, "got", 3) == 0)
++      {
++      str += 3;
++      cls = RCLASS_GOT;
++      }
+     if (strncasecmp (str, "hi(", 3) == 0)
+       {
+diff --git a/gas/testsuite/gas/or1k/reloc-1.d b/gas/testsuite/gas/or1k/reloc-1.d
+index d1bcf5608bb..3a001c4ed99 100644
+--- a/gas/testsuite/gas/or1k/reloc-1.d
++++ b/gas/testsuite/gas/or1k/reloc-1.d
+@@ -68,5 +68,7 @@ OFFSET   TYPE              VALUE
+ 000000ec R_OR1K_LO13       x
+ 000000f0 R_OR1K_GOT_LO13   x
+ 000000f4 R_OR1K_SLO13      x
+-
++000000f8 R_OR1K_GOT_AHI16  x
++000000fc R_OR1K_GOT_AHI16  x
++00000100 R_OR1K_GOT_AHI16  x
+diff --git a/gas/testsuite/gas/or1k/reloc-1.s b/gas/testsuite/gas/or1k/reloc-1.s
+index e76abef6532..562609aa869 100644
+--- a/gas/testsuite/gas/or1k/reloc-1.s
++++ b/gas/testsuite/gas/or1k/reloc-1.s
+@@ -74,3 +74,7 @@
+       l.lbz   r5,po(x)(r3)
+       l.lbz   r5,gotpo(x)(r3)
+       l.sb    po(x)(r3),r6
++
++      l.movhi r4,gotha(x)
++      l.ori   r3,r4,gotha(x)
++      l.addi  r3,r4,gotha(x)
+diff --git a/include/elf/or1k.h b/include/elf/or1k.h
+index a215ef5c17e..dff37d875f2 100644
+--- a/include/elf/or1k.h
++++ b/include/elf/or1k.h
+@@ -77,6 +77,7 @@ START_RELOC_NUMBERS (elf_or1k_reloc_type)
+   RELOC_NUMBER (R_OR1K_TLS_IE_LO13,   51)
+   RELOC_NUMBER (R_OR1K_SLO13,         52)
+   RELOC_NUMBER (R_OR1K_PLTA26,        53)
++  RELOC_NUMBER (R_OR1K_GOT_AHI16,     54)
+ END_RELOC_NUMBERS (R_OR1K_max)
+ #define EF_OR1K_NODELAY (1UL << 0)
+diff --git a/opcodes/or1k-asm.c b/opcodes/or1k-asm.c
+index 4715c4f2826..a72a4e85363 100644
+--- a/opcodes/or1k-asm.c
++++ b/opcodes/or1k-asm.c
+@@ -177,7 +177,7 @@ static const bfd_reloc_code_real_type or1k_imm16_relocs[][6] = {
+     BFD_RELOC_OR1K_GOT_LO13,
+     BFD_RELOC_UNUSED,
+     BFD_RELOC_UNUSED,
+-    BFD_RELOC_UNUSED },
++    BFD_RELOC_OR1K_GOT_AHI16 },
+   { BFD_RELOC_OR1K_GOTPC_LO16,
+     BFD_RELOC_UNUSED,
+     BFD_RELOC_UNUSED,
+@@ -280,6 +280,11 @@ parse_reloc (const char **strp)
+       str += 5;
+       cls = RCLASS_TPOFF;
+       }
++    else if (strncasecmp (str, "got", 3) == 0)
++      {
++      str += 3;
++      cls = RCLASS_GOT;
++      }
+     if (strncasecmp (str, "hi(", 3) == 0)
+       {
+-- 
+2.25.1
+
diff --git a/package/binutils/2.34/0005-or1k-Avoid-R_OR1K_GOT16-overflow-failures-in-presenc.patch b/package/binutils/2.34/0005-or1k-Avoid-R_OR1K_GOT16-overflow-failures-in-presenc.patch
new file mode 100644 (file)
index 0000000..e292c9c
--- /dev/null
@@ -0,0 +1,61 @@
+From d92116c7df340ff40063c5c97d202e7e87400027 Mon Sep 17 00:00:00 2001
+From: Stafford Horne <shorne@gmail.com>
+Date: Sun, 2 May 2021 06:02:16 +0900
+Subject: [PATCH] or1k: Avoid R_OR1K_GOT16 overflow failures in presence of
+ R_OR1K_GOT_AHI16
+
+Now that we support R_OR1K_GOT_AHI16 we can relax the R_OR1K_GOT16
+overflow validation check if the section has R_OR1K_GOT_AHI16.
+
+We cannot simple disable R_OR1K_GOT16 overflow validation as there will
+still be binaries that will have only R_OR1K_GOT16.  The
+R_OR1K_GOT_AHI16 relocation will only be added by GCC when building with
+the option -mcmodel=large.
+
+This assumes that R_OR1K_GOT_AHI16 will come before R_OR1K_GOT16, which
+is the code pattern that will be emitted by GCC.
+
+bfd/ChangeLog:
+
+       PR 21464
+       * elf32-or1k.c (or1k_elf_relocate_section): Relax R_OR1K_GOT16
+       overflow check if we have R_OR1K_GOT_AHI16 followed by
+       R_OR1K_GOT16.
+
+Signed-off-by: Giulio Benetti <giulio.benetti@benettiengineering.com>
+---
+ bfd/elf32-or1k.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/bfd/elf32-or1k.c b/bfd/elf32-or1k.c
+index 1273fbacb3c..ce2c4fdb3bd 100644
+--- a/bfd/elf32-or1k.c
++++ b/bfd/elf32-or1k.c
+@@ -1248,6 +1248,7 @@ or1k_elf_relocate_section (bfd *output_bfd,
+   asection *sgot, *splt;
+   bfd_vma plt_base, got_base, got_sym_value;
+   bfd_boolean ret_val = TRUE;
++  bfd_boolean saw_gotha = FALSE;
+   if (htab == NULL)
+     return FALSE;
+@@ -1456,6 +1457,16 @@ or1k_elf_relocate_section (bfd *output_bfd,
+               || r_type == R_OR1K_GOT_AHI16)
+             relocation -= got_sym_value;
++          if (r_type == R_OR1K_GOT_AHI16)
++            saw_gotha = TRUE;
++
++          /* If we have a R_OR1K_GOT16 followed by a R_OR1K_GOT_AHI16
++             relocation we assume the code is doing the right thing to avoid
++             overflows.  Here we mask the lower 16-bit of the relocation to
++             avoid overflow validation failures.  */
++          if (r_type == R_OR1K_GOT16 && saw_gotha)
++            relocation &= 0xffff;
++
+         /* Addend should be zero.  */
+         if (rel->r_addend != 0)
+           {
+-- 
+2.25.1
+
diff --git a/package/binutils/2.34/0006-or1k-Support-large-plt_relocs-when-generating-plt-en.patch b/package/binutils/2.34/0006-or1k-Support-large-plt_relocs-when-generating-plt-en.patch
new file mode 100644 (file)
index 0000000..d6695d4
--- /dev/null
@@ -0,0 +1,500 @@
+From cba29e387040eaa401c52eb20e7cab5a4401185c Mon Sep 17 00:00:00 2001
+From: Stafford Horne <shorne@gmail.com>
+Date: Sun, 2 May 2021 06:02:17 +0900
+Subject: [PATCH] or1k: Support large plt_relocs when generating plt
+ entries
+
+The current PLT generation code will generate invalid code when the PLT
+relocation offset exceeds 64k.  This fixes the issue by detecting large
+plt_reloc offsets and generare code sequences to create larger plt
+relocations.
+
+The "large" plt code needs 2 extra instructions to create 32-bit offsets.
+
+bfd/ChangeLog:
+
+       PR 27746
+       * elf32-or1k.c (PLT_ENTRY_SIZE_LARGE, PLT_MAX_INSN_COUNT,
+       OR1K_ADD, OR1K_ORI): New macros to help with plt creation.
+       (elf_or1k_link_hash_table): New field plt_count.
+       (elf_or1k_link_hash_entry): New field plt_index.
+       (elf_or1k_plt_entry_size): New function.
+       (or1k_write_plt_entry): Update to support variable size PLTs.
+       (or1k_elf_finish_dynamic_sections): Use new or1k_write_plt_entry
+       API.
+       (or1k_elf_finish_dynamic_symbol): Update to write large PLTs
+       when needed.
+       (allocate_dynrelocs): Use elf_or1k_plt_entry_size to account for
+       PLT size.
+
+ld/ChangeLog:
+
+       PR 27746
+       testsuite/ld-or1k/or1k.exp (or1kplttests): Add tests for linking
+       along with gotha() relocations.
+       testsuite/ld-or1k/gotha1.dd: New file.
+       testsuite/ld-or1k/gotha1.s: New file.
+       testsuite/ld-or1k/gotha2.dd: New file.
+       testsuite/ld-or1k/gotha2.s: New file
+       testsuite/ld-or1k/pltlib.s (x): Define size to avoid link
+       failure.
+
+Signed-off-by: Giulio Benetti <giulio.benetti@benettiengineering.com>
+---
+ bfd/elf32-or1k.c               | 149 ++++++++++++++++++++++++---------
+ ld/testsuite/ld-or1k/gotha1.dd |  34 ++++++++
+ ld/testsuite/ld-or1k/gotha1.s  |  24 ++++++
+ ld/testsuite/ld-or1k/gotha2.dd |  21 +++++
+ ld/testsuite/ld-or1k/gotha2.s  |  22 +++++
+ ld/testsuite/ld-or1k/or1k.exp  |   8 ++
+ ld/testsuite/ld-or1k/pltlib.s  |   1 +
+ 7 files changed, 220 insertions(+), 39 deletions(-)
+ create mode 100644 ld/testsuite/ld-or1k/gotha1.dd
+ create mode 100644 ld/testsuite/ld-or1k/gotha1.s
+ create mode 100644 ld/testsuite/ld-or1k/gotha2.dd
+ create mode 100644 ld/testsuite/ld-or1k/gotha2.s
+
+diff --git a/bfd/elf32-or1k.c b/bfd/elf32-or1k.c
+index ce2c4fdb3bd..8b021b79d92 100644
+--- a/bfd/elf32-or1k.c
++++ b/bfd/elf32-or1k.c
+@@ -30,10 +30,14 @@
+ #define N_ONES(X)     (((bfd_vma)2 << (X)) - 1)
+ #define PLT_ENTRY_SIZE 16
++#define PLT_ENTRY_SIZE_LARGE (6*4)
++#define PLT_MAX_INSN_COUNT 6
+ #define OR1K_MOVHI(D)         (0x18000000 | (D << 21))
+ #define OR1K_ADRP(D)          (0x08000000 | (D << 21))
+ #define OR1K_LWZ(D,A)         (0x84000000 | (D << 21) | (A << 16))
++#define OR1K_ADD(D,A,B)               (0xE0000000 | (D << 21) | (A << 16) | (B << 11))
++#define OR1K_ORI(D,A)         (0xA8000000 | (D << 21) | (A << 16))
+ #define OR1K_ORI0(D)          (0xA8000000 | (D << 21))
+ #define OR1K_JR(B)            (0x44000000 | (B << 11))
+ #define OR1K_NOP              0x15000000
+@@ -903,6 +907,8 @@ struct elf_or1k_link_hash_entry
+   /* Track dynamic relocs copied for this symbol.  */
+   struct elf_dyn_relocs *dyn_relocs;
++  /* For calculating PLT size.  */
++  bfd_vma plt_index;
+   /* Track type of TLS access.  */
+   unsigned char tls_type;
+ };
+@@ -930,9 +936,20 @@ struct elf_or1k_link_hash_table
+   /* Small local sym to section mapping cache.  */
+   struct sym_cache sym_sec;
++  bfd_vma plt_count;
+   bfd_boolean saw_plta;
+ };
++static size_t
++elf_or1k_plt_entry_size (bfd_vma plt_index)
++{
++  bfd_vma plt_reloc;
++
++  plt_reloc = plt_index * sizeof (Elf32_External_Rela);
++
++  return (plt_reloc > 0xffff) ? PLT_ENTRY_SIZE_LARGE : PLT_ENTRY_SIZE;
++}
++
+ /* Get the ELF linker hash table from a link_info structure.  */
+ #define or1k_elf_hash_table(p) \
+   (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \
+@@ -2173,33 +2190,46 @@ or1k_elf_check_relocs (bfd *abfd,
+ }
+ static void
+-or1k_write_plt_entry (bfd *output_bfd, bfd_byte *contents, unsigned insn1,
+-                    unsigned insn2, unsigned insn3, unsigned insnj)
++or1k_write_plt_entry (bfd *output_bfd, bfd_byte *contents, unsigned insnj,
++                    unsigned insns[], size_t insn_count)
+ {
+   unsigned nodelay = elf_elfheader (output_bfd)->e_flags & EF_OR1K_NODELAY;
+-  unsigned insn4;
++  unsigned output_insns[PLT_MAX_INSN_COUNT];
++
++  /* Copy instructions into the output buffer.  */
++  for (size_t i = 0; i < insn_count; i++)
++    output_insns[i] = insns[i];
+   /* Honor the no-delay-slot setting.  */
+-  if (insn3 == OR1K_NOP)
++  if (insns[insn_count-1] == OR1K_NOP)
+     {
+-      insn4 = insn3;
++      unsigned slot1, slot2;
++
+       if (nodelay)
+-      insn3 = insnj;
++      slot1 = insns[insn_count-2], slot2 = insnj;
+       else
+-      insn3 = insn2, insn2 = insnj;
++      slot1 = insnj, slot2 = insns[insn_count-2];
++
++      output_insns[insn_count-2] = slot1;
++      output_insns[insn_count-1] = slot2;
++      output_insns[insn_count]   = OR1K_NOP;
+     }
+   else
+     {
++      unsigned slot1, slot2;
++
+       if (nodelay)
+-      insn4 = insnj;
++      slot1 = insns[insn_count-1], slot2 = insnj;
+       else
+-      insn4 = insn3, insn3 = insnj;
++      slot1 = insnj, slot2 = insns[insn_count-1];
++
++      output_insns[insn_count-1] = slot1;
++      output_insns[insn_count]   = slot2;
+     }
+-  bfd_put_32 (output_bfd, insn1, contents);
+-  bfd_put_32 (output_bfd, insn2, contents + 4);
+-  bfd_put_32 (output_bfd, insn3, contents + 8);
+-  bfd_put_32 (output_bfd, insn4, contents + 12);
++  /* Write out the output buffer.  */
++  for (size_t i = 0; i < (insn_count+1); i++)
++    bfd_put_32 (output_bfd, output_insns[i], contents + (i*4));
+ }
+ /* Finish up the dynamic sections.  */
+@@ -2266,7 +2296,8 @@ or1k_elf_finish_dynamic_sections (bfd *output_bfd,
+       splt = htab->root.splt;
+       if (splt && splt->size > 0)
+       {
+-        unsigned plt0, plt1, plt2;
++        unsigned plt[PLT_MAX_INSN_COUNT];
++        size_t plt_insn_count = 3;
+         bfd_vma got_addr = sgot->output_section->vma + sgot->output_offset;
+         /* Note we force 16 byte alignment on the .got, so that
+@@ -2277,27 +2308,27 @@ or1k_elf_finish_dynamic_sections (bfd *output_bfd,
+             bfd_vma pc = splt->output_section->vma + splt->output_offset;
+             unsigned pa = ((got_addr >> 13) - (pc >> 13)) & 0x1fffff;
+             unsigned po = got_addr & 0x1fff;
+-            plt0 = OR1K_ADRP(12) | pa;
+-            plt1 = OR1K_LWZ(15,12) | (po + 8);
+-            plt2 = OR1K_LWZ(12,12) | (po + 4);
++            plt[0] = OR1K_ADRP(12) | pa;
++            plt[1] = OR1K_LWZ(15,12) | (po + 8);
++            plt[2] = OR1K_LWZ(12,12) | (po + 4);
+           }
+         else if (bfd_link_pic (info))
+           {
+-            plt0 = OR1K_LWZ(15, 16) | 8;      /* .got+8 */
+-            plt1 = OR1K_LWZ(12, 16) | 4;      /* .got+4 */
+-            plt2 = OR1K_NOP;
++            plt[0] = OR1K_LWZ(15, 16) | 8;    /* .got+8 */
++            plt[1] = OR1K_LWZ(12, 16) | 4;    /* .got+4 */
++            plt[2] = OR1K_NOP;
+           }
+         else
+           {
+             unsigned ha = ((got_addr + 0x8000) >> 16) & 0xffff;
+             unsigned lo = got_addr & 0xffff;
+-            plt0 = OR1K_MOVHI(12) | ha;
+-            plt1 = OR1K_LWZ(15,12) | (lo + 8);
+-            plt2 = OR1K_LWZ(12,12) | (lo + 4);
++            plt[0] = OR1K_MOVHI(12) | ha;
++            plt[1] = OR1K_LWZ(15,12) | (lo + 8);
++            plt[2] = OR1K_LWZ(12,12) | (lo + 4);
+           }
+-        or1k_write_plt_entry (output_bfd, splt->contents,
+-                              plt0, plt1, plt2, OR1K_JR(15));
++        or1k_write_plt_entry (output_bfd, splt->contents, OR1K_JR(15),
++                              plt, plt_insn_count);
+         elf_section_data (splt->output_section)->this_hdr.sh_entsize = 4;
+       }
+@@ -2340,7 +2371,8 @@ or1k_elf_finish_dynamic_symbol (bfd *output_bfd,
+   if (h->plt.offset != (bfd_vma) -1)
+     {
+-      unsigned int plt0, plt1, plt2;
++      unsigned int plt[PLT_MAX_INSN_COUNT];
++      size_t plt_insn_count = 3;
+       asection *splt;
+       asection *sgot;
+       asection *srela;
+@@ -2352,6 +2384,7 @@ or1k_elf_finish_dynamic_symbol (bfd *output_bfd,
+       bfd_vma got_offset;
+       bfd_vma got_addr;
+       Elf_Internal_Rela rela;
++      bfd_boolean large_plt_entry;
+       /* This symbol has an entry in the procedure linkage table.  Set
+        it up.  */
+@@ -2369,10 +2402,13 @@ or1k_elf_finish_dynamic_symbol (bfd *output_bfd,
+        corresponds to this symbol.  This is the index of this symbol
+        in all the symbols for which we are making plt entries.  The
+        first entry in the procedure linkage table is reserved.  */
+-      plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1;
++      plt_index = ((struct elf_or1k_link_hash_entry *) h)->plt_index;
+       plt_addr = plt_base_addr + h->plt.offset;
+       plt_reloc = plt_index * sizeof (Elf32_External_Rela);
++      large_plt_entry = (elf_or1k_plt_entry_size (plt_index)
++                       == PLT_ENTRY_SIZE_LARGE);
++
+       /* Get the offset into the .got table of the entry that
+       corresponds to this function.  Each .got entry is 4 bytes.
+       The first three are reserved.  */
+@@ -2384,27 +2420,57 @@ or1k_elf_finish_dynamic_symbol (bfd *output_bfd,
+       {
+         unsigned pa = ((got_addr >> 13) - (plt_addr >> 13)) & 0x1fffff;
+         unsigned po = (got_addr & 0x1fff);
+-        plt0 = OR1K_ADRP(12) | pa;
+-        plt1 = OR1K_LWZ(12,12) | po;
+-        plt2 = OR1K_ORI0(11) | plt_reloc;
++        plt[0] = OR1K_ADRP(12) | pa;
++        plt[1] = OR1K_LWZ(12,12) | po;
++        plt[2] = OR1K_ORI0(11) | plt_reloc;
+       }
+       else if (bfd_link_pic (info))
+       {
+-        plt0 = OR1K_LWZ(12,16) | got_offset;
+-        plt1 = OR1K_ORI0(11) | plt_reloc;
+-        plt2 = OR1K_NOP;
++        if (large_plt_entry)
++          {
++            unsigned gotha = ((got_offset + 0x8000) >> 16) & 0xffff;
++            unsigned got = got_offset & 0xffff;
++            unsigned pltrelhi = (plt_reloc >> 16) & 0xffff;
++            unsigned pltrello = plt_reloc & 0xffff;
++
++            plt[0] = OR1K_MOVHI(12) | gotha;
++            plt[1] = OR1K_ADD(12,12,16);
++            plt[2] = OR1K_LWZ(12,12) | got;
++            plt[3] = OR1K_MOVHI(11) | pltrelhi;
++            plt[4] = OR1K_ORI(11,11) | pltrello;
++            plt_insn_count = 5;
++          }
++        else
++          {
++            plt[0] = OR1K_LWZ(12,16) | got_offset;
++            plt[1] = OR1K_ORI0(11) | plt_reloc;
++            plt[2] = OR1K_NOP;
++          }
+       }
+       else
+       {
+         unsigned ha = ((got_addr + 0x8000) >> 16) & 0xffff;
+         unsigned lo = got_addr & 0xffff;
+-        plt0 = OR1K_MOVHI(12) | ha;
+-        plt1 = OR1K_LWZ(12,12) | lo;
+-        plt2 = OR1K_ORI0(11) | plt_reloc;
++        plt[0] = OR1K_MOVHI(12) | ha;
++        plt[1] = OR1K_LWZ(12,12) | lo;
++        plt[2] = OR1K_ORI0(11) | plt_reloc;
++      }
++
++      /* For large code model we fixup the non-PIC PLT relocation instructions
++       here.  */
++      if (large_plt_entry && !bfd_link_pic (info))
++      {
++        unsigned pltrelhi = (plt_reloc >> 16) & 0xffff;
++        unsigned pltrello = plt_reloc & 0xffff;
++
++        plt[2] = OR1K_MOVHI(11) | pltrelhi;
++        plt[3] = OR1K_ORI(11,11) | pltrello;
++        plt[4] = OR1K_NOP;
++        plt_insn_count = 5;
+       }
+       or1k_write_plt_entry (output_bfd, splt->contents + h->plt.offset,
+-                          plt0, plt1, plt2, OR1K_JR(12));
++                          OR1K_JR(12), plt, plt_insn_count);
+       /* Fill in the entry in the global offset table.  We initialize it to
+        point to the top of the plt.  This is done to lazy lookup the actual
+@@ -2699,11 +2765,16 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
+       if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, bfd_link_pic (info), h))
+       {
+         asection *s = htab->root.splt;
++        bfd_vma plt_index;
++
++        /* Track the index of our plt entry for use in calculating size.  */
++        plt_index = htab->plt_count++;
++        ((struct elf_or1k_link_hash_entry *) h)->plt_index = plt_index;
+         /* If this is the first .plt entry, make room for the special
+            first entry.  */
+         if (s->size == 0)
+-          s->size = PLT_ENTRY_SIZE;
++          s->size = elf_or1k_plt_entry_size (plt_index);
+         h->plt.offset = s->size;
+@@ -2720,7 +2791,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
+           }
+         /* Make room for this entry.  */
+-        s->size += PLT_ENTRY_SIZE;
++        s->size += elf_or1k_plt_entry_size (plt_index);
+         /* We also need to make an entry in the .got.plt section, which
+            will be placed in the .got section by the linker script.  */
+diff --git a/ld/testsuite/ld-or1k/gotha1.dd b/ld/testsuite/ld-or1k/gotha1.dd
+new file mode 100644
+index 00000000000..0ad1f8f5399
+--- /dev/null
++++ b/ld/testsuite/ld-or1k/gotha1.dd
+@@ -0,0 +1,34 @@
++
++.*\.x:     file format elf32-or1k
++
++
++Disassembly of section \.plt:
++
++[0-9a-f]+ <\.plt>:
++ +[0-9a-f]+:  19 80 00 00     l\.movhi r12,0x0
++ +[0-9a-f]+:  85 ec [0-9a-f]+ [0-9a-f]+       l\.lwz r15,[0-9]+\(r12\)
++ +[0-9a-f]+:  44 00 78 00     l\.jr r15
++ +[0-9a-f]+:  85 8c [0-9a-f]+ [0-9a-f]+       l\.lwz r12,[0-9]+\(r12\)
++ +[0-9a-f]+:  19 80 00 00     l\.movhi r12,0x0
++ +[0-9a-f]+:  85 8c [0-9a-f]+ [0-9a-f]+       l\.lwz r12,[0-9]+\(r12\)
++ +[0-9a-f]+:  44 00 60 00     l\.jr r12
++ +[0-9a-f]+:  a9 60 00 00     l\.ori r11,r0,0x0
++
++Disassembly of section \.text:
++
++[0-9a-f]+ <_start>:
++ +[0-9a-f]+:  9c 21 ff fc     l\.addi r1,r1,-4
++ +[0-9a-f]+:  d4 01 48 00     l\.sw 0\(r1\),r9
++ +[0-9a-f]+:  04 00 00 02     l\.jal [0-9a-f]+ <_start\+0x10>
++ +[0-9a-f]+:  1a 60 00 00     l\.movhi r19,0x0
++ +[0-9a-f]+:  aa 73 [0-9a-f]+ [0-9a-f]+       l\.ori r19,r19,0x[0-9a-f]+
++ +[0-9a-f]+:  e2 73 48 00     l\.add r19,r19,r9
++ +[0-9a-f]+:  1a 20 00 00     l\.movhi r17,0x0
++ +[0-9a-f]+:  e2 31 98 00     l\.add r17,r17,r19
++ +[0-9a-f]+:  86 31 00 10     l\.lwz r17,16\(r17\)
++ +[0-9a-f]+:  84 71 00 00     l\.lwz r3,0\(r17\)
++ +[0-9a-f]+:  07 ff ff f2     l\.jal [0-9a-f]+ <\.plt\+0x10>
++ +[0-9a-f]+:  15 00 00 00     l\.nop 0x0
++ +[0-9a-f]+:  85 21 00 00     l\.lwz r9,0\(r1\)
++ +[0-9a-f]+:  44 00 48 00     l\.jr r9
++ +[0-9a-f]+:  9c 21 00 04     l\.addi r1,r1,4
+diff --git a/ld/testsuite/ld-or1k/gotha1.s b/ld/testsuite/ld-or1k/gotha1.s
+new file mode 100644
+index 00000000000..42b16db425c
+--- /dev/null
++++ b/ld/testsuite/ld-or1k/gotha1.s
+@@ -0,0 +1,24 @@
++      .data
++      .p2align 16
++
++      .text
++      .globl  _start
++_start:
++      l.addi  r1, r1, -4
++      l.sw    0(r1), r9
++
++      l.jal   8
++       l.movhi        r19, gotpchi(_GLOBAL_OFFSET_TABLE_-4)
++      l.ori   r19, r19, gotpclo(_GLOBAL_OFFSET_TABLE_+0)
++      l.add   r19, r19, r9
++
++      l.movhi r17, gotha(x)
++      l.add   r17, r17, r19
++      l.lwz   r17, got(x)(r17)
++      l.lwz   r3, 0(r17)
++
++      l.jal   plt(func)
++       l.nop
++      l.lwz   r9, 0(r1)
++      l.jr    r9
++       l.addi r1, r1, 4
+diff --git a/ld/testsuite/ld-or1k/gotha2.dd b/ld/testsuite/ld-or1k/gotha2.dd
+new file mode 100644
+index 00000000000..fe09da5466b
+--- /dev/null
++++ b/ld/testsuite/ld-or1k/gotha2.dd
+@@ -0,0 +1,21 @@
++
++.*\.x:     file format elf32-or1k
++
++
++Disassembly of section \.text:
++
++[0-9a-f]+ <test>:
++ +[0-9a-f]+:  9c 21 ff f8     l\.addi r1,r1,-8
++ +[0-9a-f]+:  d4 01 80 00     l\.sw 0\(r1\),r16
++ +[0-9a-f]+:  d4 01 48 04     l\.sw 4\(r1\),r9
++ +[0-9a-f]+:  04 00 [0-9a-f]+ [0-9a-f]+       l\.jal [0-9a-f]+ <test\+0x14>
++ +[0-9a-f]+:  1a 00 00 00     l\.movhi r16,0x0
++ +[0-9a-f]+:  aa 10 [0-9a-f]+ [0-9a-f]+       l\.ori r16,r16,0x[0-9a-f]+
++ +[0-9a-f]+:  e2 10 48 00     l\.add r16,r16,r9
++ +[0-9a-f]+:  1a 20 00 00     l\.movhi r17,0x0
++ +[0-9a-f]+:  e2 31 80 00     l\.add r17,r17,r16
++ +[0-9a-f]+:  86 31 00 0c     l\.lwz r17,12\(r17\)
++ +[0-9a-f]+:  85 21 00 04     l\.lwz r9,4\(r1\)
++ +[0-9a-f]+:  86 01 00 00     l\.lwz r16,0\(r1\)
++ +[0-9a-f]+:  44 00 48 00     l\.jr r9
++ +[0-9a-f]+:  9c 21 00 08     l\.addi r1,r1,8
+diff --git a/ld/testsuite/ld-or1k/gotha2.s b/ld/testsuite/ld-or1k/gotha2.s
+new file mode 100644
+index 00000000000..164b282f2dd
+--- /dev/null
++++ b/ld/testsuite/ld-or1k/gotha2.s
+@@ -0,0 +1,22 @@
++      .section        .text
++      .align 4
++      .global test
++      .type   test, @function
++test:
++      l.addi  r1, r1, -8
++      l.sw    0(r1), r16
++      l.sw    4(r1), r9
++
++      l.jal   8
++       l.movhi        r16, gotpchi(_GLOBAL_OFFSET_TABLE_-4)
++      l.ori   r16, r16, gotpclo(_GLOBAL_OFFSET_TABLE_+0)
++      l.add   r16, r16, r9
++
++      l.movhi r17, gotha(i)
++      l.add   r17, r17, r16
++      l.lwz   r17, got(i)(r17)
++
++      l.lwz   r9, 4(r1)
++      l.lwz   r16, 0(r1)
++      l.jr    r9
++       l.addi r1, r1, 8
+diff --git a/ld/testsuite/ld-or1k/or1k.exp b/ld/testsuite/ld-or1k/or1k.exp
+index 7592e8307c1..8e19ec6c31a 100644
+--- a/ld/testsuite/ld-or1k/or1k.exp
++++ b/ld/testsuite/ld-or1k/or1k.exp
+@@ -53,6 +53,14 @@ set or1kplttests {
+      "" {plt1.s}
+      {{objdump -dr plt1.x.dd}}
+      "plt1.x"}
++    {"gotha exec plt" "tmpdir/libpltlib.so" ""
++     "" {gotha1.s}
++     {{objdump -dr gotha1.dd}}
++     "gotha1.x"}
++    {"gotha -fpic -shared" "-fpic -shared" ""
++     "" {gotha2.s}
++     {{objdump -dr gotha2.dd}}
++     "gotha2.x"}
+ }
+ # Not implemented yet
+diff --git a/ld/testsuite/ld-or1k/pltlib.s b/ld/testsuite/ld-or1k/pltlib.s
+index baf76ca1af7..8b4d7ba48fd 100644
+--- a/ld/testsuite/ld-or1k/pltlib.s
++++ b/ld/testsuite/ld-or1k/pltlib.s
+@@ -1,5 +1,6 @@
+       .section .data
+       .globl x, y
++      .size x, 4
+ x:    .long 33
+ y:    .long 44
+-- 
+2.25.1
+
diff --git a/package/binutils/2.35.2/0004-or1k-Implement-relocation-R_OR1K_GOT_AHI16-for-gotha.patch b/package/binutils/2.35.2/0004-or1k-Implement-relocation-R_OR1K_GOT_AHI16-for-gotha.patch
new file mode 100644 (file)
index 0000000..a4af57d
--- /dev/null
@@ -0,0 +1,256 @@
+From c67656e248d6dadaa2729975a17c8dd03afe48d0 Mon Sep 17 00:00:00 2001
+From: Stafford Horne <shorne@gmail.com>
+Date: Sun, 2 May 2021 06:02:15 +0900
+Subject: [PATCH] or1k: Implement relocation R_OR1K_GOT_AHI16 for gotha()
+
+The gotha() relocation mnemonic will be outputted by OpenRISC GCC when
+using the -mcmodel=large option.  This relocation is used along with
+got() to generate 32-bit GOT offsets.  This increases the previous GOT
+offset limit from the previous 16-bit (64K) limit.
+
+This is needed on large binaries where the GOT grows larger than 64k.
+
+bfd/ChangeLog:
+
+       PR 21464
+       * bfd-in2.h: Add BFD_RELOC_OR1K_GOT_AHI16 relocation.
+       * elf32-or1k.c (or1k_elf_howto_table, or1k_reloc_map): Likewise.
+       (or1k_final_link_relocate, or1k_elf_relocate_section,
+       or1k_elf_check_relocs): Likewise.
+       * libbfd.h (bfd_reloc_code_real_names): Likewise.
+       * reloc.c: Likewise.
+
+cpu/ChangeLog:
+
+       PR 21464
+       * or1k.opc (or1k_imm16_relocs, parse_reloc): Define parse logic
+       for gotha() relocation.
+
+include/ChangeLog:
+
+       PR 21464
+       * elf/or1k.h (elf_or1k_reloc_type): Define R_OR1K_GOT_AHI16 number.
+
+opcodes/ChangeLog:
+
+       PR 21464
+       * or1k-asm.c: Regenerate.
+
+gas/ChangeLog:
+
+       PR 21464
+       * testsuite/gas/or1k/reloc-1.s: Add test for new relocation.
+       * testsuite/gas/or1k/reloc-1.d: Add test result for new
+       relocation.
+
+Cc: Giulio Benetti <giulio.benetti@benettiengineering.com>
+
+fixup reloc, add tests
+
+Signed-off-by: Giulio Benetti <giulio.benetti@benettiengineering.com>
+---
+ bfd/bfd-in2.h                    |  1 +
+ bfd/elf32-or1k.c                 | 21 ++++++++++++++++++++-
+ bfd/libbfd.h                     |  1 +
+ bfd/reloc.c                      |  2 ++
+ cpu/or1k.opc                     |  7 ++++++-
+ gas/testsuite/gas/or1k/reloc-1.d |  4 +++-
+ gas/testsuite/gas/or1k/reloc-1.s |  4 ++++
+ include/elf/or1k.h               |  1 +
+ opcodes/or1k-asm.c               |  7 ++++++-
+ 9 files changed, 44 insertions(+), 4 deletions(-)
+
+diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
+index df6f9f45673..ab861395e93 100644
+--- a/bfd/bfd-in2.h
++++ b/bfd/bfd-in2.h
+@@ -5041,6 +5041,7 @@ then it may be truncated to 8 bits.  */
+   BFD_RELOC_OR1K_TLS_TPOFF,
+   BFD_RELOC_OR1K_TLS_DTPOFF,
+   BFD_RELOC_OR1K_TLS_DTPMOD,
++  BFD_RELOC_OR1K_GOT_AHI16,
+ /* H8 elf Relocations.  */
+   BFD_RELOC_H8_DIR16A8,
+diff --git a/bfd/elf32-or1k.c b/bfd/elf32-or1k.c
+index bbfa2bfe614..8e395827123 100644
+--- a/bfd/elf32-or1k.c
++++ b/bfd/elf32-or1k.c
+@@ -808,6 +808,20 @@ static reloc_howto_type or1k_elf_howto_table[] =
+        0,                     /* Source Mask.  */
+        0x03ffffff,            /* Dest Mask.  */
+        TRUE),                 /* PC relative offset?  */
++
++  HOWTO (R_OR1K_GOT_AHI16,     /* type */
++      16,                    /* rightshift */
++      2,                     /* size (0 = byte, 1 = short, 2 = long) */
++      16,                    /* bitsize */
++      FALSE,                 /* pc_relative */
++      0,                     /* bitpos */
++      complain_overflow_signed, /* complain_on_overflow */
++      bfd_elf_generic_reloc, /* special_function */
++      "R_OR1K_GOT_AHI16",    /* name */
++      FALSE,                 /* partial_inplace */
++      0,                     /* src_mask */
++      0xffff,                /* dst_mask */
++      FALSE),                /* pcrel_offset */
+ };
+ /* Map BFD reloc types to Or1k ELF reloc types.  */
+@@ -871,6 +885,7 @@ static const struct or1k_reloc_map or1k_reloc_map[] =
+   { BFD_RELOC_OR1K_TLS_IE_LO13,       R_OR1K_TLS_IE_LO13 },
+   { BFD_RELOC_OR1K_SLO13,     R_OR1K_SLO13 },
+   { BFD_RELOC_OR1K_PLTA26,    R_OR1K_PLTA26 },
++  { BFD_RELOC_OR1K_GOT_AHI16, R_OR1K_GOT_AHI16 },
+ };
+ /* tls_type is a mask used to track how each symbol is accessed,
+@@ -1113,6 +1128,7 @@ or1k_final_link_relocate (reloc_howto_type *howto, bfd *input_bfd,
+   switch (howto->type)
+     {
+     case R_OR1K_AHI16:
++    case R_OR1K_GOT_AHI16:
+     case R_OR1K_GOTOFF_AHI16:
+     case R_OR1K_TLS_IE_AHI16:
+     case R_OR1K_TLS_LE_AHI16:
+@@ -1375,6 +1391,7 @@ or1k_elf_relocate_section (bfd *output_bfd,
+           }
+         break;
++      case R_OR1K_GOT_AHI16:
+       case R_OR1K_GOT16:
+       case R_OR1K_GOT_PG21:
+       case R_OR1K_GOT_LO13:
+@@ -1466,7 +1483,8 @@ or1k_elf_relocate_section (bfd *output_bfd,
+           /* The GOT_PG21 and GOT_LO13 relocs are pc-relative,
+              while the GOT16 reloc is GOT relative.  */
+           relocation = got_base + off;
+-          if (r_type == R_OR1K_GOT16)
++          if (r_type == R_OR1K_GOT16
++              || r_type == R_OR1K_GOT_AHI16)
+             relocation -= got_sym_value;
+         /* Addend should be zero.  */
+@@ -1992,6 +2010,7 @@ or1k_elf_check_relocs (bfd *abfd,
+           }
+         break;
++      case R_OR1K_GOT_AHI16:
+       case R_OR1K_GOT16:
+       case R_OR1K_GOT_PG21:
+       case R_OR1K_GOT_LO13:
+diff --git a/bfd/libbfd.h b/bfd/libbfd.h
+index b97534fc9fe..795c9b9d27f 100644
+--- a/bfd/libbfd.h
++++ b/bfd/libbfd.h
+@@ -2755,6 +2755,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
+   "BFD_RELOC_OR1K_TLS_TPOFF",
+   "BFD_RELOC_OR1K_TLS_DTPOFF",
+   "BFD_RELOC_OR1K_TLS_DTPMOD",
++  "BFD_RELOC_OR1K_GOT_AHI16",
+   "BFD_RELOC_H8_DIR16A8",
+   "BFD_RELOC_H8_DIR16R8",
+   "BFD_RELOC_H8_DIR24A8",
+diff --git a/bfd/reloc.c b/bfd/reloc.c
+index 9aba84ca81e..1e021febef2 100644
+--- a/bfd/reloc.c
++++ b/bfd/reloc.c
+@@ -6175,6 +6175,8 @@ ENUMX
+   BFD_RELOC_OR1K_GOTPC_HI16
+ ENUMX
+   BFD_RELOC_OR1K_GOTPC_LO16
++ENUMX
++  BFD_RELOC_OR1K_GOT_AHI16
+ ENUMX
+   BFD_RELOC_OR1K_GOT16
+ ENUMX
+diff --git a/cpu/or1k.opc b/cpu/or1k.opc
+index f0adcbb00a5..5d20a1f33a7 100644
+--- a/cpu/or1k.opc
++++ b/cpu/or1k.opc
+@@ -193,7 +193,7 @@ static const bfd_reloc_code_real_type or1k_imm16_relocs[][6] = {
+     BFD_RELOC_OR1K_GOT_LO13,
+     BFD_RELOC_UNUSED,
+     BFD_RELOC_UNUSED,
+-    BFD_RELOC_UNUSED },
++    BFD_RELOC_OR1K_GOT_AHI16 },
+   { BFD_RELOC_OR1K_GOTPC_LO16,
+     BFD_RELOC_UNUSED,
+     BFD_RELOC_UNUSED,
+@@ -296,6 +296,11 @@ parse_reloc (const char **strp)
+       str += 5;
+       cls = RCLASS_TPOFF;
+       }
++    else if (strncasecmp (str, "got", 3) == 0)
++      {
++      str += 3;
++      cls = RCLASS_GOT;
++      }
+     if (strncasecmp (str, "hi(", 3) == 0)
+       {
+diff --git a/gas/testsuite/gas/or1k/reloc-1.d b/gas/testsuite/gas/or1k/reloc-1.d
+index d1bcf5608bb..3a001c4ed99 100644
+--- a/gas/testsuite/gas/or1k/reloc-1.d
++++ b/gas/testsuite/gas/or1k/reloc-1.d
+@@ -68,5 +68,7 @@ OFFSET   TYPE              VALUE
+ 000000ec R_OR1K_LO13       x
+ 000000f0 R_OR1K_GOT_LO13   x
+ 000000f4 R_OR1K_SLO13      x
+-
++000000f8 R_OR1K_GOT_AHI16  x
++000000fc R_OR1K_GOT_AHI16  x
++00000100 R_OR1K_GOT_AHI16  x
+diff --git a/gas/testsuite/gas/or1k/reloc-1.s b/gas/testsuite/gas/or1k/reloc-1.s
+index e76abef6532..562609aa869 100644
+--- a/gas/testsuite/gas/or1k/reloc-1.s
++++ b/gas/testsuite/gas/or1k/reloc-1.s
+@@ -74,3 +74,7 @@
+       l.lbz   r5,po(x)(r3)
+       l.lbz   r5,gotpo(x)(r3)
+       l.sb    po(x)(r3),r6
++
++      l.movhi r4,gotha(x)
++      l.ori   r3,r4,gotha(x)
++      l.addi  r3,r4,gotha(x)
+diff --git a/include/elf/or1k.h b/include/elf/or1k.h
+index a215ef5c17e..dff37d875f2 100644
+--- a/include/elf/or1k.h
++++ b/include/elf/or1k.h
+@@ -77,6 +77,7 @@ START_RELOC_NUMBERS (elf_or1k_reloc_type)
+   RELOC_NUMBER (R_OR1K_TLS_IE_LO13,   51)
+   RELOC_NUMBER (R_OR1K_SLO13,         52)
+   RELOC_NUMBER (R_OR1K_PLTA26,        53)
++  RELOC_NUMBER (R_OR1K_GOT_AHI16,     54)
+ END_RELOC_NUMBERS (R_OR1K_max)
+ #define EF_OR1K_NODELAY (1UL << 0)
+diff --git a/opcodes/or1k-asm.c b/opcodes/or1k-asm.c
+index 5f3c6c74b12..e0c49b3b8cd 100644
+--- a/opcodes/or1k-asm.c
++++ b/opcodes/or1k-asm.c
+@@ -177,7 +177,7 @@ static const bfd_reloc_code_real_type or1k_imm16_relocs[][6] = {
+     BFD_RELOC_OR1K_GOT_LO13,
+     BFD_RELOC_UNUSED,
+     BFD_RELOC_UNUSED,
+-    BFD_RELOC_UNUSED },
++    BFD_RELOC_OR1K_GOT_AHI16 },
+   { BFD_RELOC_OR1K_GOTPC_LO16,
+     BFD_RELOC_UNUSED,
+     BFD_RELOC_UNUSED,
+@@ -280,6 +280,11 @@ parse_reloc (const char **strp)
+       str += 5;
+       cls = RCLASS_TPOFF;
+       }
++    else if (strncasecmp (str, "got", 3) == 0)
++      {
++      str += 3;
++      cls = RCLASS_GOT;
++      }
+     if (strncasecmp (str, "hi(", 3) == 0)
+       {
+-- 
+2.25.1
+
diff --git a/package/binutils/2.35.2/0005-or1k-Avoid-R_OR1K_GOT16-overflow-failures-in-presenc.patch b/package/binutils/2.35.2/0005-or1k-Avoid-R_OR1K_GOT16-overflow-failures-in-presenc.patch
new file mode 100644 (file)
index 0000000..82198dd
--- /dev/null
@@ -0,0 +1,61 @@
+From 097b83a1c9c694a14e6081cee034bf24f16875c1 Mon Sep 17 00:00:00 2001
+From: Stafford Horne <shorne@gmail.com>
+Date: Sun, 2 May 2021 06:02:16 +0900
+Subject: [PATCH] or1k: Avoid R_OR1K_GOT16 overflow failures in presence of
+ R_OR1K_GOT_AHI16
+
+Now that we support R_OR1K_GOT_AHI16 we can relax the R_OR1K_GOT16
+overflow validation check if the section has R_OR1K_GOT_AHI16.
+
+We cannot simple disable R_OR1K_GOT16 overflow validation as there will
+still be binaries that will have only R_OR1K_GOT16.  The
+R_OR1K_GOT_AHI16 relocation will only be added by GCC when building with
+the option -mcmodel=large.
+
+This assumes that R_OR1K_GOT_AHI16 will come before R_OR1K_GOT16, which
+is the code pattern that will be emitted by GCC.
+
+bfd/ChangeLog:
+
+       PR 21464
+       * elf32-or1k.c (or1k_elf_relocate_section): Relax R_OR1K_GOT16
+       overflow check if we have R_OR1K_GOT_AHI16 followed by
+       R_OR1K_GOT16.
+
+Signed-off-by: Giulio Benetti <giulio.benetti@benettiengineering.com>
+---
+ bfd/elf32-or1k.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/bfd/elf32-or1k.c b/bfd/elf32-or1k.c
+index 8e395827123..9f315bfda99 100644
+--- a/bfd/elf32-or1k.c
++++ b/bfd/elf32-or1k.c
+@@ -1280,6 +1280,7 @@ or1k_elf_relocate_section (bfd *output_bfd,
+   asection *sgot, *splt;
+   bfd_vma plt_base, got_base, got_sym_value;
+   bfd_boolean ret_val = TRUE;
++  bfd_boolean saw_gotha = FALSE;
+   if (htab == NULL)
+     return FALSE;
+@@ -1487,6 +1488,16 @@ or1k_elf_relocate_section (bfd *output_bfd,
+               || r_type == R_OR1K_GOT_AHI16)
+             relocation -= got_sym_value;
++          if (r_type == R_OR1K_GOT_AHI16)
++            saw_gotha = TRUE;
++
++          /* If we have a R_OR1K_GOT16 followed by a R_OR1K_GOT_AHI16
++             relocation we assume the code is doing the right thing to avoid
++             overflows.  Here we mask the lower 16-bit of the relocation to
++             avoid overflow validation failures.  */
++          if (r_type == R_OR1K_GOT16 && saw_gotha)
++            relocation &= 0xffff;
++
+         /* Addend should be zero.  */
+         if (rel->r_addend != 0)
+           {
+-- 
+2.25.1
+
diff --git a/package/binutils/2.35.2/0006-or1k-Support-large-plt_relocs-when-generating-plt-en.patch b/package/binutils/2.35.2/0006-or1k-Support-large-plt_relocs-when-generating-plt-en.patch
new file mode 100644 (file)
index 0000000..c884ab8
--- /dev/null
@@ -0,0 +1,500 @@
+From c87692eb894b4b86eced7b7ba205f9bf27c2c213 Mon Sep 17 00:00:00 2001
+From: Stafford Horne <shorne@gmail.com>
+Date: Sun, 2 May 2021 06:02:17 +0900
+Subject: [PATCH] or1k: Support large plt_relocs when generating plt
+ entries
+
+The current PLT generation code will generate invalid code when the PLT
+relocation offset exceeds 64k.  This fixes the issue by detecting large
+plt_reloc offsets and generare code sequences to create larger plt
+relocations.
+
+The "large" plt code needs 2 extra instructions to create 32-bit offsets.
+
+bfd/ChangeLog:
+
+       PR 27746
+       * elf32-or1k.c (PLT_ENTRY_SIZE_LARGE, PLT_MAX_INSN_COUNT,
+       OR1K_ADD, OR1K_ORI): New macros to help with plt creation.
+       (elf_or1k_link_hash_table): New field plt_count.
+       (elf_or1k_link_hash_entry): New field plt_index.
+       (elf_or1k_plt_entry_size): New function.
+       (or1k_write_plt_entry): Update to support variable size PLTs.
+       (or1k_elf_finish_dynamic_sections): Use new or1k_write_plt_entry
+       API.
+       (or1k_elf_finish_dynamic_symbol): Update to write large PLTs
+       when needed.
+       (allocate_dynrelocs): Use elf_or1k_plt_entry_size to account for
+       PLT size.
+
+ld/ChangeLog:
+
+       PR 27746
+       testsuite/ld-or1k/or1k.exp (or1kplttests): Add tests for linking
+       along with gotha() relocations.
+       testsuite/ld-or1k/gotha1.dd: New file.
+       testsuite/ld-or1k/gotha1.s: New file.
+       testsuite/ld-or1k/gotha2.dd: New file.
+       testsuite/ld-or1k/gotha2.s: New file
+       testsuite/ld-or1k/pltlib.s (x): Define size to avoid link
+       failure.
+
+Signed-off-by: Giulio Benetti <giulio.benetti@benettiengineering.com>
+---
+ bfd/elf32-or1k.c               | 149 ++++++++++++++++++++++++---------
+ ld/testsuite/ld-or1k/gotha1.dd |  34 ++++++++
+ ld/testsuite/ld-or1k/gotha1.s  |  24 ++++++
+ ld/testsuite/ld-or1k/gotha2.dd |  21 +++++
+ ld/testsuite/ld-or1k/gotha2.s  |  22 +++++
+ ld/testsuite/ld-or1k/or1k.exp  |   8 ++
+ ld/testsuite/ld-or1k/pltlib.s  |   1 +
+ 7 files changed, 220 insertions(+), 39 deletions(-)
+ create mode 100644 ld/testsuite/ld-or1k/gotha1.dd
+ create mode 100644 ld/testsuite/ld-or1k/gotha1.s
+ create mode 100644 ld/testsuite/ld-or1k/gotha2.dd
+ create mode 100644 ld/testsuite/ld-or1k/gotha2.s
+
+diff --git a/bfd/elf32-or1k.c b/bfd/elf32-or1k.c
+index 9f315bfda99..7a14eaa3a46 100644
+--- a/bfd/elf32-or1k.c
++++ b/bfd/elf32-or1k.c
+@@ -30,10 +30,14 @@
+ #define N_ONES(X)     (((bfd_vma)2 << (X)) - 1)
+ #define PLT_ENTRY_SIZE 16
++#define PLT_ENTRY_SIZE_LARGE (6*4)
++#define PLT_MAX_INSN_COUNT 6
+ #define OR1K_MOVHI(D)         (0x18000000 | (D << 21))
+ #define OR1K_ADRP(D)          (0x08000000 | (D << 21))
+ #define OR1K_LWZ(D,A)         (0x84000000 | (D << 21) | (A << 16))
++#define OR1K_ADD(D,A,B)               (0xE0000000 | (D << 21) | (A << 16) | (B << 11))
++#define OR1K_ORI(D,A)         (0xA8000000 | (D << 21) | (A << 16))
+ #define OR1K_ORI0(D)          (0xA8000000 | (D << 21))
+ #define OR1K_JR(B)            (0x44000000 | (B << 11))
+ #define OR1K_NOP              0x15000000
+@@ -907,6 +911,8 @@ struct elf_or1k_link_hash_entry
+ {
+   struct elf_link_hash_entry root;
++  /* For calculating PLT size.  */
++  bfd_vma plt_index;
+   /* Track type of TLS access.  */
+   unsigned char tls_type;
+ };
+@@ -934,9 +940,20 @@ struct elf_or1k_link_hash_table
+   /* Small local sym to section mapping cache.  */
+   struct sym_cache sym_sec;
++  bfd_vma plt_count;
+   bfd_boolean saw_plta;
+ };
++static size_t
++elf_or1k_plt_entry_size (bfd_vma plt_index)
++{
++  bfd_vma plt_reloc;
++
++  plt_reloc = plt_index * sizeof (Elf32_External_Rela);
++
++  return (plt_reloc > 0xffff) ? PLT_ENTRY_SIZE_LARGE : PLT_ENTRY_SIZE;
++}
++
+ /* Get the ELF linker hash table from a link_info structure.  */
+ #define or1k_elf_hash_table(p) \
+   (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \
+@@ -2224,33 +2241,46 @@ or1k_elf_check_relocs (bfd *abfd,
+ }
+ static void
+-or1k_write_plt_entry (bfd *output_bfd, bfd_byte *contents, unsigned insn1,
+-                    unsigned insn2, unsigned insn3, unsigned insnj)
++or1k_write_plt_entry (bfd *output_bfd, bfd_byte *contents, unsigned insnj,
++                    unsigned insns[], size_t insn_count)
+ {
+   unsigned nodelay = elf_elfheader (output_bfd)->e_flags & EF_OR1K_NODELAY;
+-  unsigned insn4;
++  unsigned output_insns[PLT_MAX_INSN_COUNT];
++
++  /* Copy instructions into the output buffer.  */
++  for (size_t i = 0; i < insn_count; i++)
++    output_insns[i] = insns[i];
+   /* Honor the no-delay-slot setting.  */
+-  if (insn3 == OR1K_NOP)
++  if (insns[insn_count-1] == OR1K_NOP)
+     {
+-      insn4 = insn3;
++      unsigned slot1, slot2;
++
+       if (nodelay)
+-      insn3 = insnj;
++      slot1 = insns[insn_count-2], slot2 = insnj;
+       else
+-      insn3 = insn2, insn2 = insnj;
++      slot1 = insnj, slot2 = insns[insn_count-2];
++
++      output_insns[insn_count-2] = slot1;
++      output_insns[insn_count-1] = slot2;
++      output_insns[insn_count]   = OR1K_NOP;
+     }
+   else
+     {
++      unsigned slot1, slot2;
++
+       if (nodelay)
+-      insn4 = insnj;
++      slot1 = insns[insn_count-1], slot2 = insnj;
+       else
+-      insn4 = insn3, insn3 = insnj;
++      slot1 = insnj, slot2 = insns[insn_count-1];
++
++      output_insns[insn_count-1] = slot1;
++      output_insns[insn_count]   = slot2;
+     }
+-  bfd_put_32 (output_bfd, insn1, contents);
+-  bfd_put_32 (output_bfd, insn2, contents + 4);
+-  bfd_put_32 (output_bfd, insn3, contents + 8);
+-  bfd_put_32 (output_bfd, insn4, contents + 12);
++  /* Write out the output buffer.  */
++  for (size_t i = 0; i < (insn_count+1); i++)
++    bfd_put_32 (output_bfd, output_insns[i], contents + (i*4));
+ }
+ /* Finish up the dynamic sections.  */
+@@ -2317,7 +2347,8 @@ or1k_elf_finish_dynamic_sections (bfd *output_bfd,
+       splt = htab->root.splt;
+       if (splt && splt->size > 0)
+       {
+-        unsigned plt0, plt1, plt2;
++        unsigned plt[PLT_MAX_INSN_COUNT];
++        size_t plt_insn_count = 3;
+         bfd_vma got_addr = sgot->output_section->vma + sgot->output_offset;
+         /* Note we force 16 byte alignment on the .got, so that
+@@ -2328,27 +2359,27 @@ or1k_elf_finish_dynamic_sections (bfd *output_bfd,
+             bfd_vma pc = splt->output_section->vma + splt->output_offset;
+             unsigned pa = ((got_addr >> 13) - (pc >> 13)) & 0x1fffff;
+             unsigned po = got_addr & 0x1fff;
+-            plt0 = OR1K_ADRP(12) | pa;
+-            plt1 = OR1K_LWZ(15,12) | (po + 8);
+-            plt2 = OR1K_LWZ(12,12) | (po + 4);
++            plt[0] = OR1K_ADRP(12) | pa;
++            plt[1] = OR1K_LWZ(15,12) | (po + 8);
++            plt[2] = OR1K_LWZ(12,12) | (po + 4);
+           }
+         else if (bfd_link_pic (info))
+           {
+-            plt0 = OR1K_LWZ(15, 16) | 8;      /* .got+8 */
+-            plt1 = OR1K_LWZ(12, 16) | 4;      /* .got+4 */
+-            plt2 = OR1K_NOP;
++            plt[0] = OR1K_LWZ(15, 16) | 8;    /* .got+8 */
++            plt[1] = OR1K_LWZ(12, 16) | 4;    /* .got+4 */
++            plt[2] = OR1K_NOP;
+           }
+         else
+           {
+             unsigned ha = ((got_addr + 0x8000) >> 16) & 0xffff;
+             unsigned lo = got_addr & 0xffff;
+-            plt0 = OR1K_MOVHI(12) | ha;
+-            plt1 = OR1K_LWZ(15,12) | (lo + 8);
+-            plt2 = OR1K_LWZ(12,12) | (lo + 4);
++            plt[0] = OR1K_MOVHI(12) | ha;
++            plt[1] = OR1K_LWZ(15,12) | (lo + 8);
++            plt[2] = OR1K_LWZ(12,12) | (lo + 4);
+           }
+-        or1k_write_plt_entry (output_bfd, splt->contents,
+-                              plt0, plt1, plt2, OR1K_JR(15));
++        or1k_write_plt_entry (output_bfd, splt->contents, OR1K_JR(15),
++                              plt, plt_insn_count);
+         elf_section_data (splt->output_section)->this_hdr.sh_entsize = 4;
+       }
+@@ -2391,7 +2422,8 @@ or1k_elf_finish_dynamic_symbol (bfd *output_bfd,
+   if (h->plt.offset != (bfd_vma) -1)
+     {
+-      unsigned int plt0, plt1, plt2;
++      unsigned int plt[PLT_MAX_INSN_COUNT];
++      size_t plt_insn_count = 3;
+       asection *splt;
+       asection *sgot;
+       asection *srela;
+@@ -2403,6 +2435,7 @@ or1k_elf_finish_dynamic_symbol (bfd *output_bfd,
+       bfd_vma got_offset;
+       bfd_vma got_addr;
+       Elf_Internal_Rela rela;
++      bfd_boolean large_plt_entry;
+       /* This symbol has an entry in the procedure linkage table.  Set
+        it up.  */
+@@ -2420,10 +2453,13 @@ or1k_elf_finish_dynamic_symbol (bfd *output_bfd,
+        corresponds to this symbol.  This is the index of this symbol
+        in all the symbols for which we are making plt entries.  The
+        first entry in the procedure linkage table is reserved.  */
+-      plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1;
++      plt_index = ((struct elf_or1k_link_hash_entry *) h)->plt_index;
+       plt_addr = plt_base_addr + h->plt.offset;
+       plt_reloc = plt_index * sizeof (Elf32_External_Rela);
++      large_plt_entry = (elf_or1k_plt_entry_size (plt_index)
++                       == PLT_ENTRY_SIZE_LARGE);
++
+       /* Get the offset into the .got table of the entry that
+       corresponds to this function.  Each .got entry is 4 bytes.
+       The first three are reserved.  */
+@@ -2435,27 +2471,57 @@ or1k_elf_finish_dynamic_symbol (bfd *output_bfd,
+       {
+         unsigned pa = ((got_addr >> 13) - (plt_addr >> 13)) & 0x1fffff;
+         unsigned po = (got_addr & 0x1fff);
+-        plt0 = OR1K_ADRP(12) | pa;
+-        plt1 = OR1K_LWZ(12,12) | po;
+-        plt2 = OR1K_ORI0(11) | plt_reloc;
++        plt[0] = OR1K_ADRP(12) | pa;
++        plt[1] = OR1K_LWZ(12,12) | po;
++        plt[2] = OR1K_ORI0(11) | plt_reloc;
+       }
+       else if (bfd_link_pic (info))
+       {
+-        plt0 = OR1K_LWZ(12,16) | got_offset;
+-        plt1 = OR1K_ORI0(11) | plt_reloc;
+-        plt2 = OR1K_NOP;
++        if (large_plt_entry)
++          {
++            unsigned gotha = ((got_offset + 0x8000) >> 16) & 0xffff;
++            unsigned got = got_offset & 0xffff;
++            unsigned pltrelhi = (plt_reloc >> 16) & 0xffff;
++            unsigned pltrello = plt_reloc & 0xffff;
++
++            plt[0] = OR1K_MOVHI(12) | gotha;
++            plt[1] = OR1K_ADD(12,12,16);
++            plt[2] = OR1K_LWZ(12,12) | got;
++            plt[3] = OR1K_MOVHI(11) | pltrelhi;
++            plt[4] = OR1K_ORI(11,11) | pltrello;
++            plt_insn_count = 5;
++          }
++        else
++          {
++            plt[0] = OR1K_LWZ(12,16) | got_offset;
++            plt[1] = OR1K_ORI0(11) | plt_reloc;
++            plt[2] = OR1K_NOP;
++          }
+       }
+       else
+       {
+         unsigned ha = ((got_addr + 0x8000) >> 16) & 0xffff;
+         unsigned lo = got_addr & 0xffff;
+-        plt0 = OR1K_MOVHI(12) | ha;
+-        plt1 = OR1K_LWZ(12,12) | lo;
+-        plt2 = OR1K_ORI0(11) | plt_reloc;
++        plt[0] = OR1K_MOVHI(12) | ha;
++        plt[1] = OR1K_LWZ(12,12) | lo;
++        plt[2] = OR1K_ORI0(11) | plt_reloc;
++      }
++
++      /* For large code model we fixup the non-PIC PLT relocation instructions
++       here.  */
++      if (large_plt_entry && !bfd_link_pic (info))
++      {
++        unsigned pltrelhi = (plt_reloc >> 16) & 0xffff;
++        unsigned pltrello = plt_reloc & 0xffff;
++
++        plt[2] = OR1K_MOVHI(11) | pltrelhi;
++        plt[3] = OR1K_ORI(11,11) | pltrello;
++        plt[4] = OR1K_NOP;
++        plt_insn_count = 5;
+       }
+       or1k_write_plt_entry (output_bfd, splt->contents + h->plt.offset,
+-                          plt0, plt1, plt2, OR1K_JR(12));
++                          OR1K_JR(12), plt, plt_insn_count);
+       /* Fill in the entry in the global offset table.  We initialize it to
+        point to the top of the plt.  This is done to lazy lookup the actual
+@@ -2779,11 +2845,16 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
+       if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, bfd_link_pic (info), h))
+       {
+         asection *splt = htab->root.splt;
++        bfd_vma plt_index;
++
++        /* Track the index of our plt entry for use in calculating size.  */
++        plt_index = htab->plt_count++;
++        ((struct elf_or1k_link_hash_entry *) h)->plt_index = plt_index;
+         /* If this is the first .plt entry, make room for the special
+            first entry.  */
+         if (splt->size == 0)
+-          splt->size = PLT_ENTRY_SIZE;
++          splt->size = elf_or1k_plt_entry_size (plt_index);
+         h->plt.offset = splt->size;
+@@ -2800,7 +2871,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
+           }
+         /* Make room for this entry.  */
+-        splt->size += PLT_ENTRY_SIZE;
++        splt->size += elf_or1k_plt_entry_size (plt_index);
+         /* We also need to make an entry in the .got.plt section, which
+            will be placed in the .got section by the linker script.  */
+diff --git a/ld/testsuite/ld-or1k/gotha1.dd b/ld/testsuite/ld-or1k/gotha1.dd
+new file mode 100644
+index 00000000000..0ad1f8f5399
+--- /dev/null
++++ b/ld/testsuite/ld-or1k/gotha1.dd
+@@ -0,0 +1,34 @@
++
++.*\.x:     file format elf32-or1k
++
++
++Disassembly of section \.plt:
++
++[0-9a-f]+ <\.plt>:
++ +[0-9a-f]+:  19 80 00 00     l\.movhi r12,0x0
++ +[0-9a-f]+:  85 ec [0-9a-f]+ [0-9a-f]+       l\.lwz r15,[0-9]+\(r12\)
++ +[0-9a-f]+:  44 00 78 00     l\.jr r15
++ +[0-9a-f]+:  85 8c [0-9a-f]+ [0-9a-f]+       l\.lwz r12,[0-9]+\(r12\)
++ +[0-9a-f]+:  19 80 00 00     l\.movhi r12,0x0
++ +[0-9a-f]+:  85 8c [0-9a-f]+ [0-9a-f]+       l\.lwz r12,[0-9]+\(r12\)
++ +[0-9a-f]+:  44 00 60 00     l\.jr r12
++ +[0-9a-f]+:  a9 60 00 00     l\.ori r11,r0,0x0
++
++Disassembly of section \.text:
++
++[0-9a-f]+ <_start>:
++ +[0-9a-f]+:  9c 21 ff fc     l\.addi r1,r1,-4
++ +[0-9a-f]+:  d4 01 48 00     l\.sw 0\(r1\),r9
++ +[0-9a-f]+:  04 00 00 02     l\.jal [0-9a-f]+ <_start\+0x10>
++ +[0-9a-f]+:  1a 60 00 00     l\.movhi r19,0x0
++ +[0-9a-f]+:  aa 73 [0-9a-f]+ [0-9a-f]+       l\.ori r19,r19,0x[0-9a-f]+
++ +[0-9a-f]+:  e2 73 48 00     l\.add r19,r19,r9
++ +[0-9a-f]+:  1a 20 00 00     l\.movhi r17,0x0
++ +[0-9a-f]+:  e2 31 98 00     l\.add r17,r17,r19
++ +[0-9a-f]+:  86 31 00 10     l\.lwz r17,16\(r17\)
++ +[0-9a-f]+:  84 71 00 00     l\.lwz r3,0\(r17\)
++ +[0-9a-f]+:  07 ff ff f2     l\.jal [0-9a-f]+ <\.plt\+0x10>
++ +[0-9a-f]+:  15 00 00 00     l\.nop 0x0
++ +[0-9a-f]+:  85 21 00 00     l\.lwz r9,0\(r1\)
++ +[0-9a-f]+:  44 00 48 00     l\.jr r9
++ +[0-9a-f]+:  9c 21 00 04     l\.addi r1,r1,4
+diff --git a/ld/testsuite/ld-or1k/gotha1.s b/ld/testsuite/ld-or1k/gotha1.s
+new file mode 100644
+index 00000000000..42b16db425c
+--- /dev/null
++++ b/ld/testsuite/ld-or1k/gotha1.s
+@@ -0,0 +1,24 @@
++      .data
++      .p2align 16
++
++      .text
++      .globl  _start
++_start:
++      l.addi  r1, r1, -4
++      l.sw    0(r1), r9
++
++      l.jal   8
++       l.movhi        r19, gotpchi(_GLOBAL_OFFSET_TABLE_-4)
++      l.ori   r19, r19, gotpclo(_GLOBAL_OFFSET_TABLE_+0)
++      l.add   r19, r19, r9
++
++      l.movhi r17, gotha(x)
++      l.add   r17, r17, r19
++      l.lwz   r17, got(x)(r17)
++      l.lwz   r3, 0(r17)
++
++      l.jal   plt(func)
++       l.nop
++      l.lwz   r9, 0(r1)
++      l.jr    r9
++       l.addi r1, r1, 4
+diff --git a/ld/testsuite/ld-or1k/gotha2.dd b/ld/testsuite/ld-or1k/gotha2.dd
+new file mode 100644
+index 00000000000..fe09da5466b
+--- /dev/null
++++ b/ld/testsuite/ld-or1k/gotha2.dd
+@@ -0,0 +1,21 @@
++
++.*\.x:     file format elf32-or1k
++
++
++Disassembly of section \.text:
++
++[0-9a-f]+ <test>:
++ +[0-9a-f]+:  9c 21 ff f8     l\.addi r1,r1,-8
++ +[0-9a-f]+:  d4 01 80 00     l\.sw 0\(r1\),r16
++ +[0-9a-f]+:  d4 01 48 04     l\.sw 4\(r1\),r9
++ +[0-9a-f]+:  04 00 [0-9a-f]+ [0-9a-f]+       l\.jal [0-9a-f]+ <test\+0x14>
++ +[0-9a-f]+:  1a 00 00 00     l\.movhi r16,0x0
++ +[0-9a-f]+:  aa 10 [0-9a-f]+ [0-9a-f]+       l\.ori r16,r16,0x[0-9a-f]+
++ +[0-9a-f]+:  e2 10 48 00     l\.add r16,r16,r9
++ +[0-9a-f]+:  1a 20 00 00     l\.movhi r17,0x0
++ +[0-9a-f]+:  e2 31 80 00     l\.add r17,r17,r16
++ +[0-9a-f]+:  86 31 00 0c     l\.lwz r17,12\(r17\)
++ +[0-9a-f]+:  85 21 00 04     l\.lwz r9,4\(r1\)
++ +[0-9a-f]+:  86 01 00 00     l\.lwz r16,0\(r1\)
++ +[0-9a-f]+:  44 00 48 00     l\.jr r9
++ +[0-9a-f]+:  9c 21 00 08     l\.addi r1,r1,8
+diff --git a/ld/testsuite/ld-or1k/gotha2.s b/ld/testsuite/ld-or1k/gotha2.s
+new file mode 100644
+index 00000000000..164b282f2dd
+--- /dev/null
++++ b/ld/testsuite/ld-or1k/gotha2.s
+@@ -0,0 +1,22 @@
++      .section        .text
++      .align 4
++      .global test
++      .type   test, @function
++test:
++      l.addi  r1, r1, -8
++      l.sw    0(r1), r16
++      l.sw    4(r1), r9
++
++      l.jal   8
++       l.movhi        r16, gotpchi(_GLOBAL_OFFSET_TABLE_-4)
++      l.ori   r16, r16, gotpclo(_GLOBAL_OFFSET_TABLE_+0)
++      l.add   r16, r16, r9
++
++      l.movhi r17, gotha(i)
++      l.add   r17, r17, r16
++      l.lwz   r17, got(i)(r17)
++
++      l.lwz   r9, 4(r1)
++      l.lwz   r16, 0(r1)
++      l.jr    r9
++       l.addi r1, r1, 8
+diff --git a/ld/testsuite/ld-or1k/or1k.exp b/ld/testsuite/ld-or1k/or1k.exp
+index 7592e8307c1..8e19ec6c31a 100644
+--- a/ld/testsuite/ld-or1k/or1k.exp
++++ b/ld/testsuite/ld-or1k/or1k.exp
+@@ -53,6 +53,14 @@ set or1kplttests {
+      "" {plt1.s}
+      {{objdump -dr plt1.x.dd}}
+      "plt1.x"}
++    {"gotha exec plt" "tmpdir/libpltlib.so" ""
++     "" {gotha1.s}
++     {{objdump -dr gotha1.dd}}
++     "gotha1.x"}
++    {"gotha -fpic -shared" "-fpic -shared" ""
++     "" {gotha2.s}
++     {{objdump -dr gotha2.dd}}
++     "gotha2.x"}
+ }
+ # Not implemented yet
+diff --git a/ld/testsuite/ld-or1k/pltlib.s b/ld/testsuite/ld-or1k/pltlib.s
+index baf76ca1af7..8b4d7ba48fd 100644
+--- a/ld/testsuite/ld-or1k/pltlib.s
++++ b/ld/testsuite/ld-or1k/pltlib.s
+@@ -1,5 +1,6 @@
+       .section .data
+       .globl x, y
++      .size x, 4
+ x:    .long 33
+ y:    .long 44
+-- 
+2.25.1
+
diff --git a/package/binutils/2.36.1/0004-or1k-Implement-relocation-R_OR1K_GOT_AHI16-for-gotha.patch b/package/binutils/2.36.1/0004-or1k-Implement-relocation-R_OR1K_GOT_AHI16-for-gotha.patch
new file mode 100644 (file)
index 0000000..08c23d2
--- /dev/null
@@ -0,0 +1,256 @@
+From 141dee7402871c7b3994838c3eddf64a92d67be7 Mon Sep 17 00:00:00 2001
+From: Stafford Horne <shorne@gmail.com>
+Date: Sun, 2 May 2021 06:02:15 +0900
+Subject: [PATCH] or1k: Implement relocation R_OR1K_GOT_AHI16 for gotha()
+
+The gotha() relocation mnemonic will be outputted by OpenRISC GCC when
+using the -mcmodel=large option.  This relocation is used along with
+got() to generate 32-bit GOT offsets.  This increases the previous GOT
+offset limit from the previous 16-bit (64K) limit.
+
+This is needed on large binaries where the GOT grows larger than 64k.
+
+bfd/ChangeLog:
+
+       PR 21464
+       * bfd-in2.h: Add BFD_RELOC_OR1K_GOT_AHI16 relocation.
+       * elf32-or1k.c (or1k_elf_howto_table, or1k_reloc_map): Likewise.
+       (or1k_final_link_relocate, or1k_elf_relocate_section,
+       or1k_elf_check_relocs): Likewise.
+       * libbfd.h (bfd_reloc_code_real_names): Likewise.
+       * reloc.c: Likewise.
+
+cpu/ChangeLog:
+
+       PR 21464
+       * or1k.opc (or1k_imm16_relocs, parse_reloc): Define parse logic
+       for gotha() relocation.
+
+include/ChangeLog:
+
+       PR 21464
+       * elf/or1k.h (elf_or1k_reloc_type): Define R_OR1K_GOT_AHI16 number.
+
+opcodes/ChangeLog:
+
+       PR 21464
+       * or1k-asm.c: Regenerate.
+
+gas/ChangeLog:
+
+       PR 21464
+       * testsuite/gas/or1k/reloc-1.s: Add test for new relocation.
+       * testsuite/gas/or1k/reloc-1.d: Add test result for new
+       relocation.
+
+Cc: Giulio Benetti <giulio.benetti@benettiengineering.com>
+
+fixup reloc, add tests
+
+Signed-off-by: Giulio Benetti <giulio.benetti@benettiengineering.com>
+---
+ bfd/bfd-in2.h                    |  1 +
+ bfd/elf32-or1k.c                 | 21 ++++++++++++++++++++-
+ bfd/libbfd.h                     |  1 +
+ bfd/reloc.c                      |  2 ++
+ cpu/or1k.opc                     |  7 ++++++-
+ gas/testsuite/gas/or1k/reloc-1.d |  4 +++-
+ gas/testsuite/gas/or1k/reloc-1.s |  4 ++++
+ include/elf/or1k.h               |  1 +
+ opcodes/or1k-asm.c               |  7 ++++++-
+ 9 files changed, 44 insertions(+), 4 deletions(-)
+
+diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
+index 7eff85b7eaa..e76b9e7a319 100644
+--- a/bfd/bfd-in2.h
++++ b/bfd/bfd-in2.h
+@@ -5048,6 +5048,7 @@ then it may be truncated to 8 bits.  */
+   BFD_RELOC_OR1K_TLS_TPOFF,
+   BFD_RELOC_OR1K_TLS_DTPOFF,
+   BFD_RELOC_OR1K_TLS_DTPMOD,
++  BFD_RELOC_OR1K_GOT_AHI16,
+ /* H8 elf Relocations.  */
+   BFD_RELOC_H8_DIR16A8,
+diff --git a/bfd/elf32-or1k.c b/bfd/elf32-or1k.c
+index 4f82cc4c667..48461854a96 100644
+--- a/bfd/elf32-or1k.c
++++ b/bfd/elf32-or1k.c
+@@ -808,6 +808,20 @@ static reloc_howto_type or1k_elf_howto_table[] =
+        0,                     /* Source Mask.  */
+        0x03ffffff,            /* Dest Mask.  */
+        TRUE),                 /* PC relative offset?  */
++
++  HOWTO (R_OR1K_GOT_AHI16,     /* type */
++      16,                    /* rightshift */
++      2,                     /* size (0 = byte, 1 = short, 2 = long) */
++      16,                    /* bitsize */
++      FALSE,                 /* pc_relative */
++      0,                     /* bitpos */
++      complain_overflow_signed, /* complain_on_overflow */
++      bfd_elf_generic_reloc, /* special_function */
++      "R_OR1K_GOT_AHI16",    /* name */
++      FALSE,                 /* partial_inplace */
++      0,                     /* src_mask */
++      0xffff,                /* dst_mask */
++      FALSE),                /* pcrel_offset */
+ };
+ /* Map BFD reloc types to Or1k ELF reloc types.  */
+@@ -871,6 +885,7 @@ static const struct or1k_reloc_map or1k_reloc_map[] =
+   { BFD_RELOC_OR1K_TLS_IE_LO13,       R_OR1K_TLS_IE_LO13 },
+   { BFD_RELOC_OR1K_SLO13,     R_OR1K_SLO13 },
+   { BFD_RELOC_OR1K_PLTA26,    R_OR1K_PLTA26 },
++  { BFD_RELOC_OR1K_GOT_AHI16, R_OR1K_GOT_AHI16 },
+ };
+ /* tls_type is a mask used to track how each symbol is accessed,
+@@ -1111,6 +1126,7 @@ or1k_final_link_relocate (reloc_howto_type *howto, bfd *input_bfd,
+   switch (howto->type)
+     {
+     case R_OR1K_AHI16:
++    case R_OR1K_GOT_AHI16:
+     case R_OR1K_GOTOFF_AHI16:
+     case R_OR1K_TLS_IE_AHI16:
+     case R_OR1K_TLS_LE_AHI16:
+@@ -1373,6 +1389,7 @@ or1k_elf_relocate_section (bfd *output_bfd,
+           }
+         break;
++      case R_OR1K_GOT_AHI16:
+       case R_OR1K_GOT16:
+       case R_OR1K_GOT_PG21:
+       case R_OR1K_GOT_LO13:
+@@ -1464,7 +1481,8 @@ or1k_elf_relocate_section (bfd *output_bfd,
+           /* The GOT_PG21 and GOT_LO13 relocs are pc-relative,
+              while the GOT16 reloc is GOT relative.  */
+           relocation = got_base + off;
+-          if (r_type == R_OR1K_GOT16)
++          if (r_type == R_OR1K_GOT16
++              || r_type == R_OR1K_GOT_AHI16)
+             relocation -= got_sym_value;
+         /* Addend should be zero.  */
+@@ -1990,6 +2008,7 @@ or1k_elf_check_relocs (bfd *abfd,
+           }
+         break;
++      case R_OR1K_GOT_AHI16:
+       case R_OR1K_GOT16:
+       case R_OR1K_GOT_PG21:
+       case R_OR1K_GOT_LO13:
+diff --git a/bfd/libbfd.h b/bfd/libbfd.h
+index 7271a2ad5a1..e0ee2dafc07 100644
+--- a/bfd/libbfd.h
++++ b/bfd/libbfd.h
+@@ -2757,6 +2757,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
+   "BFD_RELOC_OR1K_TLS_TPOFF",
+   "BFD_RELOC_OR1K_TLS_DTPOFF",
+   "BFD_RELOC_OR1K_TLS_DTPMOD",
++  "BFD_RELOC_OR1K_GOT_AHI16",
+   "BFD_RELOC_H8_DIR16A8",
+   "BFD_RELOC_H8_DIR16R8",
+   "BFD_RELOC_H8_DIR24A8",
+diff --git a/bfd/reloc.c b/bfd/reloc.c
+index 4f4b95a0b7f..fe94e0d8f91 100644
+--- a/bfd/reloc.c
++++ b/bfd/reloc.c
+@@ -6204,6 +6204,8 @@ ENUMX
+   BFD_RELOC_OR1K_GOTPC_HI16
+ ENUMX
+   BFD_RELOC_OR1K_GOTPC_LO16
++ENUMX
++  BFD_RELOC_OR1K_GOT_AHI16
+ ENUMX
+   BFD_RELOC_OR1K_GOT16
+ ENUMX
+diff --git a/cpu/or1k.opc b/cpu/or1k.opc
+index f0adcbb00a5..5d20a1f33a7 100644
+--- a/cpu/or1k.opc
++++ b/cpu/or1k.opc
+@@ -193,7 +193,7 @@ static const bfd_reloc_code_real_type or1k_imm16_relocs[][6] = {
+     BFD_RELOC_OR1K_GOT_LO13,
+     BFD_RELOC_UNUSED,
+     BFD_RELOC_UNUSED,
+-    BFD_RELOC_UNUSED },
++    BFD_RELOC_OR1K_GOT_AHI16 },
+   { BFD_RELOC_OR1K_GOTPC_LO16,
+     BFD_RELOC_UNUSED,
+     BFD_RELOC_UNUSED,
+@@ -296,6 +296,11 @@ parse_reloc (const char **strp)
+       str += 5;
+       cls = RCLASS_TPOFF;
+       }
++    else if (strncasecmp (str, "got", 3) == 0)
++      {
++      str += 3;
++      cls = RCLASS_GOT;
++      }
+     if (strncasecmp (str, "hi(", 3) == 0)
+       {
+diff --git a/gas/testsuite/gas/or1k/reloc-1.d b/gas/testsuite/gas/or1k/reloc-1.d
+index d1bcf5608bb..3a001c4ed99 100644
+--- a/gas/testsuite/gas/or1k/reloc-1.d
++++ b/gas/testsuite/gas/or1k/reloc-1.d
+@@ -68,5 +68,7 @@ OFFSET   TYPE              VALUE
+ 000000ec R_OR1K_LO13       x
+ 000000f0 R_OR1K_GOT_LO13   x
+ 000000f4 R_OR1K_SLO13      x
+-
++000000f8 R_OR1K_GOT_AHI16  x
++000000fc R_OR1K_GOT_AHI16  x
++00000100 R_OR1K_GOT_AHI16  x
+diff --git a/gas/testsuite/gas/or1k/reloc-1.s b/gas/testsuite/gas/or1k/reloc-1.s
+index e76abef6532..562609aa869 100644
+--- a/gas/testsuite/gas/or1k/reloc-1.s
++++ b/gas/testsuite/gas/or1k/reloc-1.s
+@@ -74,3 +74,7 @@
+       l.lbz   r5,po(x)(r3)
+       l.lbz   r5,gotpo(x)(r3)
+       l.sb    po(x)(r3),r6
++
++      l.movhi r4,gotha(x)
++      l.ori   r3,r4,gotha(x)
++      l.addi  r3,r4,gotha(x)
+diff --git a/include/elf/or1k.h b/include/elf/or1k.h
+index 7f281481061..69ab90584a2 100644
+--- a/include/elf/or1k.h
++++ b/include/elf/or1k.h
+@@ -77,6 +77,7 @@ START_RELOC_NUMBERS (elf_or1k_reloc_type)
+   RELOC_NUMBER (R_OR1K_TLS_IE_LO13,   51)
+   RELOC_NUMBER (R_OR1K_SLO13,         52)
+   RELOC_NUMBER (R_OR1K_PLTA26,        53)
++  RELOC_NUMBER (R_OR1K_GOT_AHI16,     54)
+ END_RELOC_NUMBERS (R_OR1K_max)
+ #define EF_OR1K_NODELAY (1UL << 0)
+diff --git a/opcodes/or1k-asm.c b/opcodes/or1k-asm.c
+index 045ab6230b6..fdccf67f9e1 100644
+--- a/opcodes/or1k-asm.c
++++ b/opcodes/or1k-asm.c
+@@ -177,7 +177,7 @@ static const bfd_reloc_code_real_type or1k_imm16_relocs[][6] = {
+     BFD_RELOC_OR1K_GOT_LO13,
+     BFD_RELOC_UNUSED,
+     BFD_RELOC_UNUSED,
+-    BFD_RELOC_UNUSED },
++    BFD_RELOC_OR1K_GOT_AHI16 },
+   { BFD_RELOC_OR1K_GOTPC_LO16,
+     BFD_RELOC_UNUSED,
+     BFD_RELOC_UNUSED,
+@@ -280,6 +280,11 @@ parse_reloc (const char **strp)
+       str += 5;
+       cls = RCLASS_TPOFF;
+       }
++    else if (strncasecmp (str, "got", 3) == 0)
++      {
++      str += 3;
++      cls = RCLASS_GOT;
++      }
+     if (strncasecmp (str, "hi(", 3) == 0)
+       {
+-- 
+2.25.1
+
diff --git a/package/binutils/2.36.1/0005-or1k-Avoid-R_OR1K_GOT16-overflow-failures-in-presenc.patch b/package/binutils/2.36.1/0005-or1k-Avoid-R_OR1K_GOT16-overflow-failures-in-presenc.patch
new file mode 100644 (file)
index 0000000..618072f
--- /dev/null
@@ -0,0 +1,61 @@
+From de914df5f2ba23a9f6f1fbf6efdc22e1b045901c Mon Sep 17 00:00:00 2001
+From: Stafford Horne <shorne@gmail.com>
+Date: Sun, 2 May 2021 06:02:16 +0900
+Subject: [PATCH] or1k: Avoid R_OR1K_GOT16 overflow failures in presence of
+ R_OR1K_GOT_AHI16
+
+Now that we support R_OR1K_GOT_AHI16 we can relax the R_OR1K_GOT16
+overflow validation check if the section has R_OR1K_GOT_AHI16.
+
+We cannot simple disable R_OR1K_GOT16 overflow validation as there will
+still be binaries that will have only R_OR1K_GOT16.  The
+R_OR1K_GOT_AHI16 relocation will only be added by GCC when building with
+the option -mcmodel=large.
+
+This assumes that R_OR1K_GOT_AHI16 will come before R_OR1K_GOT16, which
+is the code pattern that will be emitted by GCC.
+
+bfd/ChangeLog:
+
+       PR 21464
+       * elf32-or1k.c (or1k_elf_relocate_section): Relax R_OR1K_GOT16
+       overflow check if we have R_OR1K_GOT_AHI16 followed by
+       R_OR1K_GOT16.
+
+Signed-off-by: Giulio Benetti <giulio.benetti@benettiengineering.com>
+---
+ bfd/elf32-or1k.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/bfd/elf32-or1k.c b/bfd/elf32-or1k.c
+index 48461854a96..44e67f2b84b 100644
+--- a/bfd/elf32-or1k.c
++++ b/bfd/elf32-or1k.c
+@@ -1278,6 +1278,7 @@ or1k_elf_relocate_section (bfd *output_bfd,
+   asection *sgot, *splt;
+   bfd_vma plt_base, got_base, got_sym_value;
+   bfd_boolean ret_val = TRUE;
++  bfd_boolean saw_gotha = FALSE;
+   if (htab == NULL)
+     return FALSE;
+@@ -1485,6 +1486,16 @@ or1k_elf_relocate_section (bfd *output_bfd,
+               || r_type == R_OR1K_GOT_AHI16)
+             relocation -= got_sym_value;
++          if (r_type == R_OR1K_GOT_AHI16)
++            saw_gotha = TRUE;
++
++          /* If we have a R_OR1K_GOT16 followed by a R_OR1K_GOT_AHI16
++             relocation we assume the code is doing the right thing to avoid
++             overflows.  Here we mask the lower 16-bit of the relocation to
++             avoid overflow validation failures.  */
++          if (r_type == R_OR1K_GOT16 && saw_gotha)
++            relocation &= 0xffff;
++
+         /* Addend should be zero.  */
+         if (rel->r_addend != 0)
+           {
+-- 
+2.25.1
+
diff --git a/package/binutils/2.36.1/0006-or1k-Support-large-plt_relocs-when-generating-plt-en.patch b/package/binutils/2.36.1/0006-or1k-Support-large-plt_relocs-when-generating-plt-en.patch
new file mode 100644 (file)
index 0000000..6d50852
--- /dev/null
@@ -0,0 +1,500 @@
+From 4a7b357d0c802685bee7706bafb9702c821286e1 Mon Sep 17 00:00:00 2001
+From: Stafford Horne <shorne@gmail.com>
+Date: Sun, 2 May 2021 06:02:17 +0900
+Subject: [PATCH] or1k: Support large plt_relocs when generating plt
+ entries
+
+The current PLT generation code will generate invalid code when the PLT
+relocation offset exceeds 64k.  This fixes the issue by detecting large
+plt_reloc offsets and generare code sequences to create larger plt
+relocations.
+
+The "large" plt code needs 2 extra instructions to create 32-bit offsets.
+
+bfd/ChangeLog:
+
+       PR 27746
+       * elf32-or1k.c (PLT_ENTRY_SIZE_LARGE, PLT_MAX_INSN_COUNT,
+       OR1K_ADD, OR1K_ORI): New macros to help with plt creation.
+       (elf_or1k_link_hash_table): New field plt_count.
+       (elf_or1k_link_hash_entry): New field plt_index.
+       (elf_or1k_plt_entry_size): New function.
+       (or1k_write_plt_entry): Update to support variable size PLTs.
+       (or1k_elf_finish_dynamic_sections): Use new or1k_write_plt_entry
+       API.
+       (or1k_elf_finish_dynamic_symbol): Update to write large PLTs
+       when needed.
+       (allocate_dynrelocs): Use elf_or1k_plt_entry_size to account for
+       PLT size.
+
+ld/ChangeLog:
+
+       PR 27746
+       testsuite/ld-or1k/or1k.exp (or1kplttests): Add tests for linking
+       along with gotha() relocations.
+       testsuite/ld-or1k/gotha1.dd: New file.
+       testsuite/ld-or1k/gotha1.s: New file.
+       testsuite/ld-or1k/gotha2.dd: New file.
+       testsuite/ld-or1k/gotha2.s: New file
+       testsuite/ld-or1k/pltlib.s (x): Define size to avoid link
+       failure.
+
+Signed-off-by: Giulio Benetti <giulio.benetti@benettiengineering.com>
+---
+ bfd/elf32-or1k.c               | 149 ++++++++++++++++++++++++---------
+ ld/testsuite/ld-or1k/gotha1.dd |  34 ++++++++
+ ld/testsuite/ld-or1k/gotha1.s  |  24 ++++++
+ ld/testsuite/ld-or1k/gotha2.dd |  21 +++++
+ ld/testsuite/ld-or1k/gotha2.s  |  22 +++++
+ ld/testsuite/ld-or1k/or1k.exp  |   8 ++
+ ld/testsuite/ld-or1k/pltlib.s  |   1 +
+ 7 files changed, 220 insertions(+), 39 deletions(-)
+ create mode 100644 ld/testsuite/ld-or1k/gotha1.dd
+ create mode 100644 ld/testsuite/ld-or1k/gotha1.s
+ create mode 100644 ld/testsuite/ld-or1k/gotha2.dd
+ create mode 100644 ld/testsuite/ld-or1k/gotha2.s
+
+diff --git a/bfd/elf32-or1k.c b/bfd/elf32-or1k.c
+index 44e67f2b84b..3da68e52425 100644
+--- a/bfd/elf32-or1k.c
++++ b/bfd/elf32-or1k.c
+@@ -30,10 +30,14 @@
+ #define N_ONES(X)     (((bfd_vma)2 << (X)) - 1)
+ #define PLT_ENTRY_SIZE 16
++#define PLT_ENTRY_SIZE_LARGE (6*4)
++#define PLT_MAX_INSN_COUNT 6
+ #define OR1K_MOVHI(D)         (0x18000000 | (D << 21))
+ #define OR1K_ADRP(D)          (0x08000000 | (D << 21))
+ #define OR1K_LWZ(D,A)         (0x84000000 | (D << 21) | (A << 16))
++#define OR1K_ADD(D,A,B)               (0xE0000000 | (D << 21) | (A << 16) | (B << 11))
++#define OR1K_ORI(D,A)         (0xA8000000 | (D << 21) | (A << 16))
+ #define OR1K_ORI0(D)          (0xA8000000 | (D << 21))
+ #define OR1K_JR(B)            (0x44000000 | (B << 11))
+ #define OR1K_NOP              0x15000000
+@@ -907,6 +911,8 @@ struct elf_or1k_link_hash_entry
+ {
+   struct elf_link_hash_entry root;
++  /* For calculating PLT size.  */
++  bfd_vma plt_index;
+   /* Track type of TLS access.  */
+   unsigned char tls_type;
+ };
+@@ -931,9 +937,20 @@ struct elf_or1k_link_hash_table
+ {
+   struct elf_link_hash_table root;
++  bfd_vma plt_count;
+   bfd_boolean saw_plta;
+ };
++static size_t
++elf_or1k_plt_entry_size (bfd_vma plt_index)
++{
++  bfd_vma plt_reloc;
++
++  plt_reloc = plt_index * sizeof (Elf32_External_Rela);
++
++  return (plt_reloc > 0xffff) ? PLT_ENTRY_SIZE_LARGE : PLT_ENTRY_SIZE;
++}
++
+ /* Get the ELF linker hash table from a link_info structure.  */
+ #define or1k_elf_hash_table(p) \
+   ((is_elf_hash_table ((p)->hash)                                     \
+@@ -2222,33 +2239,46 @@ or1k_elf_check_relocs (bfd *abfd,
+ }
+ static void
+-or1k_write_plt_entry (bfd *output_bfd, bfd_byte *contents, unsigned insn1,
+-                    unsigned insn2, unsigned insn3, unsigned insnj)
++or1k_write_plt_entry (bfd *output_bfd, bfd_byte *contents, unsigned insnj,
++                    unsigned insns[], size_t insn_count)
+ {
+   unsigned nodelay = elf_elfheader (output_bfd)->e_flags & EF_OR1K_NODELAY;
+-  unsigned insn4;
++  unsigned output_insns[PLT_MAX_INSN_COUNT];
++
++  /* Copy instructions into the output buffer.  */
++  for (size_t i = 0; i < insn_count; i++)
++    output_insns[i] = insns[i];
+   /* Honor the no-delay-slot setting.  */
+-  if (insn3 == OR1K_NOP)
++  if (insns[insn_count-1] == OR1K_NOP)
+     {
+-      insn4 = insn3;
++      unsigned slot1, slot2;
++
+       if (nodelay)
+-      insn3 = insnj;
++      slot1 = insns[insn_count-2], slot2 = insnj;
+       else
+-      insn3 = insn2, insn2 = insnj;
++      slot1 = insnj, slot2 = insns[insn_count-2];
++
++      output_insns[insn_count-2] = slot1;
++      output_insns[insn_count-1] = slot2;
++      output_insns[insn_count]   = OR1K_NOP;
+     }
+   else
+     {
++      unsigned slot1, slot2;
++
+       if (nodelay)
+-      insn4 = insnj;
++      slot1 = insns[insn_count-1], slot2 = insnj;
+       else
+-      insn4 = insn3, insn3 = insnj;
++      slot1 = insnj, slot2 = insns[insn_count-1];
++
++      output_insns[insn_count-1] = slot1;
++      output_insns[insn_count]   = slot2;
+     }
+-  bfd_put_32 (output_bfd, insn1, contents);
+-  bfd_put_32 (output_bfd, insn2, contents + 4);
+-  bfd_put_32 (output_bfd, insn3, contents + 8);
+-  bfd_put_32 (output_bfd, insn4, contents + 12);
++  /* Write out the output buffer.  */
++  for (size_t i = 0; i < (insn_count+1); i++)
++    bfd_put_32 (output_bfd, output_insns[i], contents + (i*4));
+ }
+ /* Finish up the dynamic sections.  */
+@@ -2315,7 +2345,8 @@ or1k_elf_finish_dynamic_sections (bfd *output_bfd,
+       splt = htab->root.splt;
+       if (splt && splt->size > 0)
+       {
+-        unsigned plt0, plt1, plt2;
++        unsigned plt[PLT_MAX_INSN_COUNT];
++        size_t plt_insn_count = 3;
+         bfd_vma got_addr = sgot->output_section->vma + sgot->output_offset;
+         /* Note we force 16 byte alignment on the .got, so that
+@@ -2326,27 +2357,27 @@ or1k_elf_finish_dynamic_sections (bfd *output_bfd,
+             bfd_vma pc = splt->output_section->vma + splt->output_offset;
+             unsigned pa = ((got_addr >> 13) - (pc >> 13)) & 0x1fffff;
+             unsigned po = got_addr & 0x1fff;
+-            plt0 = OR1K_ADRP(12) | pa;
+-            plt1 = OR1K_LWZ(15,12) | (po + 8);
+-            plt2 = OR1K_LWZ(12,12) | (po + 4);
++            plt[0] = OR1K_ADRP(12) | pa;
++            plt[1] = OR1K_LWZ(15,12) | (po + 8);
++            plt[2] = OR1K_LWZ(12,12) | (po + 4);
+           }
+         else if (bfd_link_pic (info))
+           {
+-            plt0 = OR1K_LWZ(15, 16) | 8;      /* .got+8 */
+-            plt1 = OR1K_LWZ(12, 16) | 4;      /* .got+4 */
+-            plt2 = OR1K_NOP;
++            plt[0] = OR1K_LWZ(15, 16) | 8;    /* .got+8 */
++            plt[1] = OR1K_LWZ(12, 16) | 4;    /* .got+4 */
++            plt[2] = OR1K_NOP;
+           }
+         else
+           {
+             unsigned ha = ((got_addr + 0x8000) >> 16) & 0xffff;
+             unsigned lo = got_addr & 0xffff;
+-            plt0 = OR1K_MOVHI(12) | ha;
+-            plt1 = OR1K_LWZ(15,12) | (lo + 8);
+-            plt2 = OR1K_LWZ(12,12) | (lo + 4);
++            plt[0] = OR1K_MOVHI(12) | ha;
++            plt[1] = OR1K_LWZ(15,12) | (lo + 8);
++            plt[2] = OR1K_LWZ(12,12) | (lo + 4);
+           }
+-        or1k_write_plt_entry (output_bfd, splt->contents,
+-                              plt0, plt1, plt2, OR1K_JR(15));
++        or1k_write_plt_entry (output_bfd, splt->contents, OR1K_JR(15),
++                              plt, plt_insn_count);
+         elf_section_data (splt->output_section)->this_hdr.sh_entsize = 4;
+       }
+@@ -2389,7 +2420,8 @@ or1k_elf_finish_dynamic_symbol (bfd *output_bfd,
+   if (h->plt.offset != (bfd_vma) -1)
+     {
+-      unsigned int plt0, plt1, plt2;
++      unsigned int plt[PLT_MAX_INSN_COUNT];
++      size_t plt_insn_count = 3;
+       asection *splt;
+       asection *sgot;
+       asection *srela;
+@@ -2401,6 +2433,7 @@ or1k_elf_finish_dynamic_symbol (bfd *output_bfd,
+       bfd_vma got_offset;
+       bfd_vma got_addr;
+       Elf_Internal_Rela rela;
++      bfd_boolean large_plt_entry;
+       /* This symbol has an entry in the procedure linkage table.  Set
+        it up.  */
+@@ -2418,10 +2451,13 @@ or1k_elf_finish_dynamic_symbol (bfd *output_bfd,
+        corresponds to this symbol.  This is the index of this symbol
+        in all the symbols for which we are making plt entries.  The
+        first entry in the procedure linkage table is reserved.  */
+-      plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1;
++      plt_index = ((struct elf_or1k_link_hash_entry *) h)->plt_index;
+       plt_addr = plt_base_addr + h->plt.offset;
+       plt_reloc = plt_index * sizeof (Elf32_External_Rela);
++      large_plt_entry = (elf_or1k_plt_entry_size (plt_index)
++                       == PLT_ENTRY_SIZE_LARGE);
++
+       /* Get the offset into the .got table of the entry that
+       corresponds to this function.  Each .got entry is 4 bytes.
+       The first three are reserved.  */
+@@ -2433,27 +2469,57 @@ or1k_elf_finish_dynamic_symbol (bfd *output_bfd,
+       {
+         unsigned pa = ((got_addr >> 13) - (plt_addr >> 13)) & 0x1fffff;
+         unsigned po = (got_addr & 0x1fff);
+-        plt0 = OR1K_ADRP(12) | pa;
+-        plt1 = OR1K_LWZ(12,12) | po;
+-        plt2 = OR1K_ORI0(11) | plt_reloc;
++        plt[0] = OR1K_ADRP(12) | pa;
++        plt[1] = OR1K_LWZ(12,12) | po;
++        plt[2] = OR1K_ORI0(11) | plt_reloc;
+       }
+       else if (bfd_link_pic (info))
+       {
+-        plt0 = OR1K_LWZ(12,16) | got_offset;
+-        plt1 = OR1K_ORI0(11) | plt_reloc;
+-        plt2 = OR1K_NOP;
++        if (large_plt_entry)
++          {
++            unsigned gotha = ((got_offset + 0x8000) >> 16) & 0xffff;
++            unsigned got = got_offset & 0xffff;
++            unsigned pltrelhi = (plt_reloc >> 16) & 0xffff;
++            unsigned pltrello = plt_reloc & 0xffff;
++
++            plt[0] = OR1K_MOVHI(12) | gotha;
++            plt[1] = OR1K_ADD(12,12,16);
++            plt[2] = OR1K_LWZ(12,12) | got;
++            plt[3] = OR1K_MOVHI(11) | pltrelhi;
++            plt[4] = OR1K_ORI(11,11) | pltrello;
++            plt_insn_count = 5;
++          }
++        else
++          {
++            plt[0] = OR1K_LWZ(12,16) | got_offset;
++            plt[1] = OR1K_ORI0(11) | plt_reloc;
++            plt[2] = OR1K_NOP;
++          }
+       }
+       else
+       {
+         unsigned ha = ((got_addr + 0x8000) >> 16) & 0xffff;
+         unsigned lo = got_addr & 0xffff;
+-        plt0 = OR1K_MOVHI(12) | ha;
+-        plt1 = OR1K_LWZ(12,12) | lo;
+-        plt2 = OR1K_ORI0(11) | plt_reloc;
++        plt[0] = OR1K_MOVHI(12) | ha;
++        plt[1] = OR1K_LWZ(12,12) | lo;
++        plt[2] = OR1K_ORI0(11) | plt_reloc;
++      }
++
++      /* For large code model we fixup the non-PIC PLT relocation instructions
++       here.  */
++      if (large_plt_entry && !bfd_link_pic (info))
++      {
++        unsigned pltrelhi = (plt_reloc >> 16) & 0xffff;
++        unsigned pltrello = plt_reloc & 0xffff;
++
++        plt[2] = OR1K_MOVHI(11) | pltrelhi;
++        plt[3] = OR1K_ORI(11,11) | pltrello;
++        plt[4] = OR1K_NOP;
++        plt_insn_count = 5;
+       }
+       or1k_write_plt_entry (output_bfd, splt->contents + h->plt.offset,
+-                          plt0, plt1, plt2, OR1K_JR(12));
++                          OR1K_JR(12), plt, plt_insn_count);
+       /* Fill in the entry in the global offset table.  We initialize it to
+        point to the top of the plt.  This is done to lazy lookup the actual
+@@ -2777,11 +2843,16 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
+       if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, bfd_link_pic (info), h))
+       {
+         asection *splt = htab->root.splt;
++        bfd_vma plt_index;
++
++        /* Track the index of our plt entry for use in calculating size.  */
++        plt_index = htab->plt_count++;
++        ((struct elf_or1k_link_hash_entry *) h)->plt_index = plt_index;
+         /* If this is the first .plt entry, make room for the special
+            first entry.  */
+         if (splt->size == 0)
+-          splt->size = PLT_ENTRY_SIZE;
++          splt->size = elf_or1k_plt_entry_size (plt_index);
+         h->plt.offset = splt->size;
+@@ -2798,7 +2869,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
+           }
+         /* Make room for this entry.  */
+-        splt->size += PLT_ENTRY_SIZE;
++        splt->size += elf_or1k_plt_entry_size (plt_index);
+         /* We also need to make an entry in the .got.plt section, which
+            will be placed in the .got section by the linker script.  */
+diff --git a/ld/testsuite/ld-or1k/gotha1.dd b/ld/testsuite/ld-or1k/gotha1.dd
+new file mode 100644
+index 00000000000..0ad1f8f5399
+--- /dev/null
++++ b/ld/testsuite/ld-or1k/gotha1.dd
+@@ -0,0 +1,34 @@
++
++.*\.x:     file format elf32-or1k
++
++
++Disassembly of section \.plt:
++
++[0-9a-f]+ <\.plt>:
++ +[0-9a-f]+:  19 80 00 00     l\.movhi r12,0x0
++ +[0-9a-f]+:  85 ec [0-9a-f]+ [0-9a-f]+       l\.lwz r15,[0-9]+\(r12\)
++ +[0-9a-f]+:  44 00 78 00     l\.jr r15
++ +[0-9a-f]+:  85 8c [0-9a-f]+ [0-9a-f]+       l\.lwz r12,[0-9]+\(r12\)
++ +[0-9a-f]+:  19 80 00 00     l\.movhi r12,0x0
++ +[0-9a-f]+:  85 8c [0-9a-f]+ [0-9a-f]+       l\.lwz r12,[0-9]+\(r12\)
++ +[0-9a-f]+:  44 00 60 00     l\.jr r12
++ +[0-9a-f]+:  a9 60 00 00     l\.ori r11,r0,0x0
++
++Disassembly of section \.text:
++
++[0-9a-f]+ <_start>:
++ +[0-9a-f]+:  9c 21 ff fc     l\.addi r1,r1,-4
++ +[0-9a-f]+:  d4 01 48 00     l\.sw 0\(r1\),r9
++ +[0-9a-f]+:  04 00 00 02     l\.jal [0-9a-f]+ <_start\+0x10>
++ +[0-9a-f]+:  1a 60 00 00     l\.movhi r19,0x0
++ +[0-9a-f]+:  aa 73 [0-9a-f]+ [0-9a-f]+       l\.ori r19,r19,0x[0-9a-f]+
++ +[0-9a-f]+:  e2 73 48 00     l\.add r19,r19,r9
++ +[0-9a-f]+:  1a 20 00 00     l\.movhi r17,0x0
++ +[0-9a-f]+:  e2 31 98 00     l\.add r17,r17,r19
++ +[0-9a-f]+:  86 31 00 10     l\.lwz r17,16\(r17\)
++ +[0-9a-f]+:  84 71 00 00     l\.lwz r3,0\(r17\)
++ +[0-9a-f]+:  07 ff ff f2     l\.jal [0-9a-f]+ <\.plt\+0x10>
++ +[0-9a-f]+:  15 00 00 00     l\.nop 0x0
++ +[0-9a-f]+:  85 21 00 00     l\.lwz r9,0\(r1\)
++ +[0-9a-f]+:  44 00 48 00     l\.jr r9
++ +[0-9a-f]+:  9c 21 00 04     l\.addi r1,r1,4
+diff --git a/ld/testsuite/ld-or1k/gotha1.s b/ld/testsuite/ld-or1k/gotha1.s
+new file mode 100644
+index 00000000000..42b16db425c
+--- /dev/null
++++ b/ld/testsuite/ld-or1k/gotha1.s
+@@ -0,0 +1,24 @@
++      .data
++      .p2align 16
++
++      .text
++      .globl  _start
++_start:
++      l.addi  r1, r1, -4
++      l.sw    0(r1), r9
++
++      l.jal   8
++       l.movhi        r19, gotpchi(_GLOBAL_OFFSET_TABLE_-4)
++      l.ori   r19, r19, gotpclo(_GLOBAL_OFFSET_TABLE_+0)
++      l.add   r19, r19, r9
++
++      l.movhi r17, gotha(x)
++      l.add   r17, r17, r19
++      l.lwz   r17, got(x)(r17)
++      l.lwz   r3, 0(r17)
++
++      l.jal   plt(func)
++       l.nop
++      l.lwz   r9, 0(r1)
++      l.jr    r9
++       l.addi r1, r1, 4
+diff --git a/ld/testsuite/ld-or1k/gotha2.dd b/ld/testsuite/ld-or1k/gotha2.dd
+new file mode 100644
+index 00000000000..fe09da5466b
+--- /dev/null
++++ b/ld/testsuite/ld-or1k/gotha2.dd
+@@ -0,0 +1,21 @@
++
++.*\.x:     file format elf32-or1k
++
++
++Disassembly of section \.text:
++
++[0-9a-f]+ <test>:
++ +[0-9a-f]+:  9c 21 ff f8     l\.addi r1,r1,-8
++ +[0-9a-f]+:  d4 01 80 00     l\.sw 0\(r1\),r16
++ +[0-9a-f]+:  d4 01 48 04     l\.sw 4\(r1\),r9
++ +[0-9a-f]+:  04 00 [0-9a-f]+ [0-9a-f]+       l\.jal [0-9a-f]+ <test\+0x14>
++ +[0-9a-f]+:  1a 00 00 00     l\.movhi r16,0x0
++ +[0-9a-f]+:  aa 10 [0-9a-f]+ [0-9a-f]+       l\.ori r16,r16,0x[0-9a-f]+
++ +[0-9a-f]+:  e2 10 48 00     l\.add r16,r16,r9
++ +[0-9a-f]+:  1a 20 00 00     l\.movhi r17,0x0
++ +[0-9a-f]+:  e2 31 80 00     l\.add r17,r17,r16
++ +[0-9a-f]+:  86 31 00 0c     l\.lwz r17,12\(r17\)
++ +[0-9a-f]+:  85 21 00 04     l\.lwz r9,4\(r1\)
++ +[0-9a-f]+:  86 01 00 00     l\.lwz r16,0\(r1\)
++ +[0-9a-f]+:  44 00 48 00     l\.jr r9
++ +[0-9a-f]+:  9c 21 00 08     l\.addi r1,r1,8
+diff --git a/ld/testsuite/ld-or1k/gotha2.s b/ld/testsuite/ld-or1k/gotha2.s
+new file mode 100644
+index 00000000000..164b282f2dd
+--- /dev/null
++++ b/ld/testsuite/ld-or1k/gotha2.s
+@@ -0,0 +1,22 @@
++      .section        .text
++      .align 4
++      .global test
++      .type   test, @function
++test:
++      l.addi  r1, r1, -8
++      l.sw    0(r1), r16
++      l.sw    4(r1), r9
++
++      l.jal   8
++       l.movhi        r16, gotpchi(_GLOBAL_OFFSET_TABLE_-4)
++      l.ori   r16, r16, gotpclo(_GLOBAL_OFFSET_TABLE_+0)
++      l.add   r16, r16, r9
++
++      l.movhi r17, gotha(i)
++      l.add   r17, r17, r16
++      l.lwz   r17, got(i)(r17)
++
++      l.lwz   r9, 4(r1)
++      l.lwz   r16, 0(r1)
++      l.jr    r9
++       l.addi r1, r1, 8
+diff --git a/ld/testsuite/ld-or1k/or1k.exp b/ld/testsuite/ld-or1k/or1k.exp
+index 8bb943aacc9..f10949e89aa 100644
+--- a/ld/testsuite/ld-or1k/or1k.exp
++++ b/ld/testsuite/ld-or1k/or1k.exp
+@@ -53,6 +53,14 @@ set or1kplttests {
+      "" {plt1.s}
+      {{objdump -dr plt1.x.dd}}
+      "plt1.x"}
++    {"gotha exec plt" "tmpdir/libpltlib.so" ""
++     "" {gotha1.s}
++     {{objdump -dr gotha1.dd}}
++     "gotha1.x"}
++    {"gotha -fpic -shared" "-fpic -shared" ""
++     "" {gotha2.s}
++     {{objdump -dr gotha2.dd}}
++     "gotha2.x"}
+ }
+ # Not implemented yet
+diff --git a/ld/testsuite/ld-or1k/pltlib.s b/ld/testsuite/ld-or1k/pltlib.s
+index baf76ca1af7..8b4d7ba48fd 100644
+--- a/ld/testsuite/ld-or1k/pltlib.s
++++ b/ld/testsuite/ld-or1k/pltlib.s
+@@ -1,5 +1,6 @@
+       .section .data
+       .globl x, y
++      .size x, 4
+ x:    .long 33
+ y:    .long 44
+-- 
+2.25.1
+