--- /dev/null
+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
+
--- /dev/null
+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
+
--- /dev/null
+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
+
--- /dev/null
+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
+
--- /dev/null
+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
+
--- /dev/null
+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
+
--- /dev/null
+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
+
--- /dev/null
+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
+
--- /dev/null
+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
+
--- /dev/null
+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
+
--- /dev/null
+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
+
--- /dev/null
+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
+