Automatic date update in version.in
[binutils-gdb.git] / bfd / elf32-or1k.c
index cd4398da86246e264d69dae89f6369fecefe3ac5..2967a62fe03d81f7ff7613633660c45656078fef 100644 (file)
@@ -1,5 +1,5 @@
 /* Or1k-specific support for 32-bit ELF.
-   Copyright (C) 2001-2021 Free Software Foundation, Inc.
+   Copyright (C) 2001-2022 Free Software Foundation, Inc.
    Contributed for OR32 by Johan Rydberg, jrydberg@opencores.org
 
    PIC parts added by Stefan Kristiansson, stefan.kristiansson@saunalahti.fi,
 #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
@@ -45,7 +49,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
   /* This reloc does nothing.  */
   HOWTO (R_OR1K_NONE,          /* type */
         0,                     /* rightshift */
-        3,                     /* size (0 = byte, 1 = short, 2 = long) */
+        0,                     /* size */
         0,                     /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -59,7 +63,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_32,
         0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         32,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -73,7 +77,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_16,
         0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        2,                     /* size */
         16,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -87,7 +91,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_8,
         0,                     /* rightshift */
-        0,                     /* size (0 = byte, 1 = short, 2 = long) */
+        1,                     /* size */
         8,                     /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -101,7 +105,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_LO_16_IN_INSN, /* type */
         0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         16,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -115,7 +119,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_HI_16_IN_INSN, /* type */
         16,                    /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         16,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -130,7 +134,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
   /* A PC relative 26 bit relocation, right shifted by 2.  */
   HOWTO (R_OR1K_INSN_REL_26, /* type */
         2,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         26,                    /* bitsize */
         true,                  /* pc_relative */
         0,                     /* bitpos */
@@ -145,7 +149,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
   /* GNU extension to record C++ vtable hierarchy.  */
   HOWTO (R_OR1K_GNU_VTINHERIT, /* type */
         0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         0,                     /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -160,7 +164,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
   /* GNU extension to record C++ vtable member usage.  */
   HOWTO (R_OR1K_GNU_VTENTRY, /* type */
         0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         0,                     /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -174,7 +178,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_32_PCREL,
         0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         32,                    /* bitsize */
         true,                  /* pc_relative */
         0,                     /* bitpos */
@@ -188,7 +192,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_16_PCREL,
         0,                     /* rightshift */
-        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        2,                     /* size */
         16,                    /* bitsize */
         true,                  /* pc_relative */
         0,                     /* bitpos */
@@ -202,7 +206,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_8_PCREL,
         0,                     /* rightshift */
-        0,                     /* size (0 = byte, 1 = short, 2 = long) */
+        1,                     /* size */
         8,                     /* bitsize */
         true,                  /* pc_relative */
         0,                     /* bitpos */
@@ -216,7 +220,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
    HOWTO (R_OR1K_GOTPC_HI16,   /* Type.  */
         16,                    /* Rightshift.  */
-        2,                     /* Size (0 = byte, 1 = short, 2 = long).  */
+        4,                     /* Size.  */
         16,                    /* Bitsize.  */
         true,                  /* PC_relative.  */
         0,                     /* Bitpos.  */
@@ -230,7 +234,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
    HOWTO (R_OR1K_GOTPC_LO16,   /* Type.  */
         0,                     /* Rightshift.  */
-        2,                     /* Size (0 = byte, 1 = short, 2 = long).  */
+        4,                     /* Size.  */
         16,                    /* Bitsize.  */
         true,                  /* PC_relative.  */
         0,                     /* Bitpos.  */
@@ -244,7 +248,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_GOT16,         /* type */
         0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         16,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -259,7 +263,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
   /* A 26 bit PLT relocation.  Shifted by 2.  */
   HOWTO (R_OR1K_PLT26,         /* Type.  */
         2,                     /* Rightshift.  */
-        2,                     /* Size (0 = byte, 1 = short, 2 = long).  */
+        4,                     /* Size.  */
         26,                    /* Bitsize.  */
         true,                  /* pc_relative.  */
         0,                     /* Bitpos.  */
@@ -273,7 +277,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_GOTOFF_HI16,   /* type */
         16,                    /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         16,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -287,7 +291,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_GOTOFF_LO16,   /* type */
         0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         16,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -301,7 +305,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_COPY,          /* type */
         0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         32,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -315,7 +319,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_GLOB_DAT,      /* type */
         0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         32,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -329,7 +333,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_JMP_SLOT,      /* type */
         0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         32,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -343,7 +347,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_RELATIVE,      /* type */
         0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         32,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -357,7 +361,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_TLS_GD_HI16,   /* type */
         16,                    /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         16,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -371,7 +375,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_TLS_GD_LO16,   /* type */
         0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         16,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -385,7 +389,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_TLS_LDM_HI16,  /* type */
         16,                    /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         16,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -399,7 +403,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_TLS_LDM_LO16,  /* type */
         0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         16,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -413,7 +417,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_TLS_LDO_HI16,  /* type */
         16,                    /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         16,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -427,7 +431,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_TLS_LDO_LO16,  /* type */
         0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         16,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -441,7 +445,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_TLS_IE_HI16,   /* type */
         16,                    /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         16,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -455,7 +459,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_TLS_IE_LO16,   /* type */
         0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         16,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -469,7 +473,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_TLS_LE_HI16,   /* type */
         16,                    /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         16,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -483,7 +487,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_TLS_LE_LO16,   /* type */
         0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         16,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -497,7 +501,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_TLS_TPOFF,     /* type */
         0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         32,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -511,7 +515,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_TLS_DTPOFF,    /* type */
         0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         32,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -525,7 +529,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_TLS_DTPMOD,    /* type */
         0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         32,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -539,7 +543,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_AHI16,         /* type */
         16,                    /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         16,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -553,7 +557,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_GOTOFF_AHI16,  /* type */
         16,                    /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         16,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -567,7 +571,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_TLS_IE_AHI16,   /* type */
         16,                    /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         16,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -581,7 +585,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_TLS_LE_AHI16,  /* type */
         16,                    /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         16,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -595,7 +599,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_SLO16,         /* type */
         0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         16,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -609,7 +613,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_GOTOFF_SLO16,  /* type */
         0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         16,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -623,7 +627,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_TLS_LE_SLO16,   /* type */
         0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         16,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -642,7 +646,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
      pc-relative relocations to local symbols.  */
   HOWTO (R_OR1K_PCREL_PG21,    /* type */
         13,                    /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         21,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -656,7 +660,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_GOT_PG21,       /* type */
         13,                    /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         21,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -670,7 +674,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_TLS_GD_PG21,    /* type */
         13,                    /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         21,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -684,7 +688,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_TLS_LDM_PG21,   /* type */
         13,                    /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         21,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -698,7 +702,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_TLS_IE_PG21,    /* type */
         13,                    /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         21,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -712,7 +716,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_LO13,          /* type */
         0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         16,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -726,7 +730,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_GOT_LO13,       /* type */
         0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         16,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -740,7 +744,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_TLS_GD_LO13,    /* type */
         0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         16,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -754,7 +758,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_TLS_LDM_LO13,   /* type */
         0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         16,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -768,7 +772,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_TLS_IE_LO13,    /* type */
         0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         16,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -782,7 +786,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
 
   HOWTO (R_OR1K_SLO13,         /* type */
         0,                     /* rightshift */
-        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        4,                     /* size */
         16,                    /* bitsize */
         false,                 /* pc_relative */
         0,                     /* bitpos */
@@ -797,7 +801,7 @@ static reloc_howto_type or1k_elf_howto_table[] =
   /* A 26 bit PLT relocation, using ADRP.  Shifted by 2.  */
   HOWTO (R_OR1K_PLTA26,                /* Type.  */
         2,                     /* Rightshift.  */
-        2,                     /* Size (0 = byte, 1 = short, 2 = long).  */
+        4,                     /* Size.  */
         26,                    /* Bitsize.  */
         true,                  /* pc_relative.  */
         0,                     /* Bitpos.  */
@@ -808,8 +812,39 @@ 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 */
+        4,                     /* size */
+        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 */
 };
 
+/* A copy of the R_OR1K_GOT16 used in the presense of R_OR1K_GOT_AHI16
+   relocations when we know we can ignore overflows.  */
+static reloc_howto_type or1k_elf_got16_no_overflow_howto =
+  HOWTO (R_OR1K_GOT16,         /* type */
+        0,                     /* rightshift */
+        4,                     /* size */
+        16,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_OR1K_GOT16",        /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        false);                /* pcrel_offset */
+
 /* Map BFD reloc types to Or1k ELF reloc types.  */
 
 struct or1k_reloc_map
@@ -871,6 +906,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,
@@ -892,6 +928,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;
 };
@@ -916,9 +954,20 @@ struct elf_or1k_link_hash_table
 {
   struct elf_link_hash_table root;
 
+  bfd_vma plt_count;
   bool 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)                                      \
@@ -1111,6 +1160,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:
@@ -1262,6 +1312,7 @@ or1k_elf_relocate_section (bfd *output_bfd,
   asection *sgot, *splt;
   bfd_vma plt_base, got_base, got_sym_value;
   bool ret_val = true;
+  bool saw_gotha = false;
 
   if (htab == NULL)
     return false;
@@ -1373,6 +1424,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,9 +1516,19 @@ 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;
 
+           if (r_type == R_OR1K_GOT_AHI16)
+             saw_gotha = true;
+
+           /* If we have a R_OR1K_GOT16 following a R_OR1K_GOT_AHI16
+              relocation we assume the code is doing the right thing to avoid
+              overflows.  */
+           if (r_type == R_OR1K_GOT16 && saw_gotha)
+             howto = &or1k_elf_got16_no_overflow_howto;
+
          /* Addend should be zero.  */
          if (rel->r_addend != 0)
            {
@@ -1497,6 +1559,18 @@ or1k_elf_relocate_section (bfd *output_bfd,
          break;
 
        case R_OR1K_INSN_REL_26:
+         /* For a non-shared link, these will reference plt or call the
+            version of actual object.  */
+         if (bfd_link_pic (info) && !SYMBOL_CALLS_LOCAL (info, h))
+           {
+             _bfd_error_handler
+               (_("%pB: pc-relative relocation against dynamic symbol %s"),
+                input_bfd, name);
+             ret_val = false;
+             bfd_set_error (bfd_error_bad_value);
+           }
+         break;
+
        case R_OR1K_PCREL_PG21:
        case R_OR1K_LO13:
        case R_OR1K_SLO13:
@@ -1990,6 +2064,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:
@@ -2110,7 +2185,7 @@ or1k_elf_check_relocs (bfd *abfd,
                    if (name == NULL)
                      return false;
 
-                   if (strncmp (name, ".rela", 5) != 0
+                   if (!startswith (name, ".rela")
                        || strcmp (bfd_section_name (sec), name + 5) != 0)
                      {
                        _bfd_error_handler
@@ -2192,33 +2267,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.  */
@@ -2285,7 +2373,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
@@ -2296,27 +2385,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;
        }
@@ -2359,7 +2448,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;
@@ -2371,6 +2461,7 @@ or1k_elf_finish_dynamic_symbol (bfd *output_bfd,
       bfd_vma got_offset;
       bfd_vma got_addr;
       Elf_Internal_Rela rela;
+      bool large_plt_entry;
 
       /* This symbol has an entry in the procedure linkage table.  Set
         it up.  */
@@ -2388,10 +2479,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.  */
@@ -2403,27 +2497,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
@@ -2566,11 +2690,10 @@ or1k_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
   if (h->type == STT_FUNC
       || h->needs_plt)
     {
-      if (! bfd_link_pic (info)
-         && !h->def_dynamic
-         && !h->ref_dynamic
-         && h->root.type != bfd_link_hash_undefweak
-         && h->root.type != bfd_link_hash_undefined)
+      if (h->plt.refcount <= 0
+         || (SYMBOL_CALLS_LOCAL (info, h)
+         || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+             && h->root.type == bfd_link_hash_undefweak)))
        {
          /* This case can occur if we saw a PLT reloc in an input
             file, but the symbol was never referred to by a dynamic
@@ -2748,11 +2871,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;
 
@@ -2769,7 +2897,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.  */