gdb: fix vfork with multiple threads
[deliverable/binutils-gdb.git] / bfd / elf32-or1k.c
index 2f200b197b8a2d142b40785c5f4d09225c62042e..4ae7f324d33f6b0af3d0465145da4a52cbb2429f 100644 (file)
@@ -1,5 +1,5 @@
 /* Or1k-specific support for 32-bit ELF.
-   Copyright (C) 2001-2019 Free Software Foundation, Inc.
+   Copyright (C) 2001-2021 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
@@ -47,593 +51,593 @@ static reloc_howto_type or1k_elf_howto_table[] =
         0,                     /* rightshift */
         3,                     /* size (0 = byte, 1 = short, 2 = long) */
         0,                     /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_NONE",         /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0,                     /* src_mask */
         0,                     /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   HOWTO (R_OR1K_32,
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         32,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_unsigned, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_32",           /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   HOWTO (R_OR1K_16,
         0,                     /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_unsigned, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_16",           /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   HOWTO (R_OR1K_8,
         0,                     /* rightshift */
         0,                     /* size (0 = byte, 1 = short, 2 = long) */
         8,                     /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_unsigned, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_8",            /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0,                     /* src_mask */
         0xff,                  /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   HOWTO (R_OR1K_LO_16_IN_INSN, /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_LO_16_IN_INSN", /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0,                     /* src_mask */
         0x0000ffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   HOWTO (R_OR1K_HI_16_IN_INSN, /* type */
         16,                    /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_HI_16_IN_INSN", /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0,                     /* src_mask */
         0x0000ffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   /* 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) */
         26,                    /* bitsize */
-        TRUE,                  /* pc_relative */
+        true,                  /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_INSN_REL_26", /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0,                     /* src_mask */
         0x03ffffff,            /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+        true),                 /* pcrel_offset */
 
   /* GNU extension to record C++ vtable hierarchy.  */
   HOWTO (R_OR1K_GNU_VTINHERIT, /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         0,                     /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         NULL,                  /* special_function */
         "R_OR1K_GNU_VTINHERIT", /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0,                     /* src_mask */
         0,                     /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   /* GNU extension to record C++ vtable member usage.  */
   HOWTO (R_OR1K_GNU_VTENTRY, /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         0,                     /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         _bfd_elf_rel_vtable_reloc_fn, /* special_function */
         "R_OR1K_GNU_VTENTRY", /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0,                     /* src_mask */
         0,                     /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   HOWTO (R_OR1K_32_PCREL,
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         32,                    /* bitsize */
-        TRUE,                  /* pc_relative */
+        true,                  /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_32_PCREL",     /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffffffff,            /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+        true),                 /* pcrel_offset */
 
   HOWTO (R_OR1K_16_PCREL,
         0,                     /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        TRUE,                  /* pc_relative */
+        true,                  /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_16_PCREL",     /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffff,                /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+        true),                 /* pcrel_offset */
 
   HOWTO (R_OR1K_8_PCREL,
         0,                     /* rightshift */
         0,                     /* size (0 = byte, 1 = short, 2 = long) */
         8,                     /* bitsize */
-        TRUE,                  /* pc_relative */
+        true,                  /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_8_PCREL",      /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0,                     /* src_mask */
         0xff,                  /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+        true),                 /* pcrel_offset */
 
    HOWTO (R_OR1K_GOTPC_HI16,   /* Type.  */
         16,                    /* Rightshift.  */
         2,                     /* Size (0 = byte, 1 = short, 2 = long).  */
         16,                    /* Bitsize.  */
-        TRUE,                  /* PC_relative.  */
+        true,                  /* PC_relative.  */
         0,                     /* Bitpos.  */
         complain_overflow_dont, /* Complain on overflow.  */
         bfd_elf_generic_reloc, /* Special Function.  */
         "R_OR1K_GOTPC_HI16",   /* Name.  */
-        FALSE,         /* Partial Inplace.  */
+        false,         /* Partial Inplace.  */
         0,                     /* Source Mask.  */
         0xffff,                /* Dest Mask.  */
-        TRUE),                 /* PC relative offset?  */
+        true),                 /* PC relative offset?  */
 
    HOWTO (R_OR1K_GOTPC_LO16,   /* Type.  */
         0,                     /* Rightshift.  */
         2,                     /* Size (0 = byte, 1 = short, 2 = long).  */
         16,                    /* Bitsize.  */
-        TRUE,                  /* PC_relative.  */
+        true,                  /* PC_relative.  */
         0,                     /* Bitpos.  */
         complain_overflow_dont, /* Complain on overflow.  */
         bfd_elf_generic_reloc, /* Special Function.  */
         "R_OR1K_GOTPC_LO16",   /* Name.  */
-        FALSE,         /* Partial Inplace.  */
+        false,         /* Partial Inplace.  */
         0,                     /* Source Mask.  */
         0xffff,                /* Dest Mask.  */
-        TRUE),                 /* PC relative offset?  */
+        true),                 /* PC relative offset?  */
 
   HOWTO (R_OR1K_GOT16,         /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_GOT16",        /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0,                     /* src_mask */
         0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   /* A 26 bit PLT relocation.  Shifted by 2.  */
   HOWTO (R_OR1K_PLT26,         /* Type.  */
         2,                     /* Rightshift.  */
         2,                     /* Size (0 = byte, 1 = short, 2 = long).  */
         26,                    /* Bitsize.  */
-        TRUE,                  /* pc_relative.  */
+        true,                  /* pc_relative.  */
         0,                     /* Bitpos.  */
         complain_overflow_signed, /* Complain on overflow.  */
         bfd_elf_generic_reloc, /* Special Function.  */
         "R_OR1K_PLT26",        /* Name.  */
-        FALSE,                 /* Partial Inplace.  */
+        false,                 /* Partial Inplace.  */
         0,                     /* Source Mask.  */
         0x03ffffff,            /* Dest Mask.  */
-        TRUE),                 /* PC relative offset?  */
+        true),                 /* PC relative offset?  */
 
   HOWTO (R_OR1K_GOTOFF_HI16,   /* type */
         16,                    /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_GOTOFF_HI16",  /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0x0,                   /* src_mask */
         0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   HOWTO (R_OR1K_GOTOFF_LO16,   /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_GOTOFF_LO16",  /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0x0,                   /* src_mask */
         0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   HOWTO (R_OR1K_COPY,          /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         32,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_COPY",         /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0xffffffff,            /* src_mask */
         0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   HOWTO (R_OR1K_GLOB_DAT,      /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         32,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_GLOB_DAT",     /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0xffffffff,            /* src_mask */
         0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   HOWTO (R_OR1K_JMP_SLOT,      /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         32,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_JMP_SLOT",     /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0xffffffff,            /* src_mask */
         0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   HOWTO (R_OR1K_RELATIVE,      /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         32,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_RELATIVE",     /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0xffffffff,            /* src_mask */
         0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   HOWTO (R_OR1K_TLS_GD_HI16,   /* type */
         16,                    /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_TLS_GD_HI16",  /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0x0,                   /* src_mask */
         0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   HOWTO (R_OR1K_TLS_GD_LO16,   /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_TLS_GD_LO16",  /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0x0,                   /* src_mask */
         0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   HOWTO (R_OR1K_TLS_LDM_HI16,  /* type */
         16,                    /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_TLS_LDM_HI16", /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0x0,                   /* src_mask */
         0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   HOWTO (R_OR1K_TLS_LDM_LO16,  /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_TLS_LDM_LO16", /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0x0,                   /* src_mask */
         0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   HOWTO (R_OR1K_TLS_LDO_HI16,  /* type */
         16,                    /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_TLS_LDO_HI16", /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0x0,                   /* src_mask */
         0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   HOWTO (R_OR1K_TLS_LDO_LO16,  /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_TLS_LDO_LO16", /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0x0,                   /* src_mask */
         0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   HOWTO (R_OR1K_TLS_IE_HI16,   /* type */
         16,                    /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_TLS_IE_HI16",  /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0x0,                   /* src_mask */
         0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   HOWTO (R_OR1K_TLS_IE_LO16,   /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_TLS_IE_LO16",  /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0x0,                   /* src_mask */
         0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   HOWTO (R_OR1K_TLS_LE_HI16,   /* type */
         16,                    /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_TLS_LE_HI16",  /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0x0,                   /* src_mask */
         0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   HOWTO (R_OR1K_TLS_LE_LO16,   /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_TLS_LE_LO16",  /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0x0,                   /* src_mask */
         0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   HOWTO (R_OR1K_TLS_TPOFF,     /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         32,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_TLS_TPOFF",    /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0xffffffff,            /* src_mask */
         0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   HOWTO (R_OR1K_TLS_DTPOFF,    /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         32,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_TLS_DTPOFF",   /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0xffffffff,            /* src_mask */
         0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   HOWTO (R_OR1K_TLS_DTPMOD,    /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         32,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_TLS_DTPMOD",   /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0xffffffff,            /* src_mask */
         0xffffffff,            /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   HOWTO (R_OR1K_AHI16,         /* type */
         16,                    /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_AHI16",        /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0x0,                   /* src_mask */
         0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   HOWTO (R_OR1K_GOTOFF_AHI16,  /* type */
         16,                    /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_GOTOFF_AHI16", /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0x0,                   /* src_mask */
         0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   HOWTO (R_OR1K_TLS_IE_AHI16,   /* type */
         16,                    /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_TLS_IE_AHI16", /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0x0,                   /* src_mask */
         0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   HOWTO (R_OR1K_TLS_LE_AHI16,  /* type */
         16,                    /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_TLS_LE_AHI16", /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0x0,                   /* src_mask */
         0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   HOWTO (R_OR1K_SLO16,         /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_SLO16",        /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0x0,                   /* src_mask */
         0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   HOWTO (R_OR1K_GOTOFF_SLO16,  /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_GOTOFF_SLO16", /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0x0,                   /* src_mask */
         0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   HOWTO (R_OR1K_TLS_LE_SLO16,   /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_TLS_LE_SLO16", /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0x0,                   /* src_mask */
         0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   /* A page relative 21 bit relocation, right shifted by 13, aligned.
      Note that this is *page* relative, not pc relative.  The idea is
@@ -644,170 +648,184 @@ static reloc_howto_type or1k_elf_howto_table[] =
         13,                    /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         21,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_PCREL_PG21",   /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0,                     /* src_mask */
         0x001fffff,            /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+        true),                 /* pcrel_offset */
 
   HOWTO (R_OR1K_GOT_PG21,       /* type */
         13,                    /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         21,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_GOT_PG21",     /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0,                     /* src_mask */
         0x001fffff,            /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+        true),                 /* pcrel_offset */
 
   HOWTO (R_OR1K_TLS_GD_PG21,    /* type */
         13,                    /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         21,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_TLS_GD_PG21",  /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0,                     /* src_mask */
         0x001fffff,            /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+        true),                 /* pcrel_offset */
 
   HOWTO (R_OR1K_TLS_LDM_PG21,   /* type */
         13,                    /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         21,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_TLS_LDM_PG21", /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0,                     /* src_mask */
         0x001fffff,            /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+        true),                 /* pcrel_offset */
 
   HOWTO (R_OR1K_TLS_IE_PG21,    /* type */
         13,                    /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         21,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_TLS_IE_PG21",  /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0,                     /* src_mask */
         0x001fffff,            /* dst_mask */
-        TRUE),                 /* pcrel_offset */
+        true),                 /* pcrel_offset */
 
   HOWTO (R_OR1K_LO13,          /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_LO13",         /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0x0,                   /* src_mask */
         0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   HOWTO (R_OR1K_GOT_LO13,       /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_GOT_LO13",     /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0x0,                   /* src_mask */
         0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   HOWTO (R_OR1K_TLS_GD_LO13,    /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_TLS_GD_LO13",  /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0x0,                   /* src_mask */
         0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   HOWTO (R_OR1K_TLS_LDM_LO13,   /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_TLD_LDM_LO13", /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0x0,                   /* src_mask */
         0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   HOWTO (R_OR1K_TLS_IE_LO13,    /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_TLS_IE_LO13",  /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0x0,                   /* src_mask */
         0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   HOWTO (R_OR1K_SLO13,         /* type */
         0,                     /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
-        FALSE,                 /* pc_relative */
+        false,                 /* pc_relative */
         0,                     /* bitpos */
         complain_overflow_dont, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         "R_OR1K_SLO13",        /* name */
-        FALSE,                 /* partial_inplace */
+        false,                 /* partial_inplace */
         0x0,                   /* src_mask */
         0xffff,                /* dst_mask */
-        FALSE),                /* pcrel_offset */
+        false),                /* pcrel_offset */
 
   /* 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).  */
         26,                    /* Bitsize.  */
-        TRUE,                  /* pc_relative.  */
+        true,                  /* pc_relative.  */
         0,                     /* Bitpos.  */
         complain_overflow_signed, /* Complain on overflow.  */
         bfd_elf_generic_reloc, /* Special Function.  */
         "R_OR1K_PLTA26",       /* Name.  */
-        FALSE,                 /* Partial Inplace.  */
+        false,                 /* Partial Inplace.  */
         0,                     /* Source Mask.  */
         0x03ffffff,            /* Dest Mask.  */
-        TRUE),                 /* PC relative offset?  */
+        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,23 +889,30 @@ 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,
+   it may be accessed via multiple types of TLS access methods.
+   We track this for sizing (allocating got + relocation section space) and
+   for how to process relocations.  */
 #define TLS_UNKNOWN    0
 #define TLS_NONE       1
 #define TLS_GD        2
-#define TLS_LD        3
-#define TLS_IE        4
-#define TLS_LE        5
+#define TLS_LD        4
+#define TLS_IE        8
+#define TLS_LE       16
+
+/* The size of the TLS thread control block, used to offset LE access.  */
+#define TCB_SIZE      16
 
 /* ELF linker hash entry.  */
 struct elf_or1k_link_hash_entry
 {
   struct elf_link_hash_entry root;
 
-  /* 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;
 };
@@ -912,18 +937,27 @@ struct elf_or1k_link_hash_table
 {
   struct elf_link_hash_table root;
 
-  /* Small local sym to section mapping cache.  */
-  struct sym_cache sym_sec;
-
-  bfd_boolean saw_plta;
+  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) \
-  (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \
-   == OR1K_ELF_DATA ? ((struct elf_or1k_link_hash_table *) ((p)->hash)) : NULL)
+  ((is_elf_hash_table ((p)->hash)                                      \
+    && elf_hash_table_id (elf_hash_table (p)) == OR1K_ELF_DATA)                \
+   ? (struct elf_or1k_link_hash_table *) (p)->hash : NULL)
 
-static bfd_boolean
+static bool
 elf_or1k_mkobject (bfd *abfd)
 {
   return bfd_elf_allocate_object (abfd, sizeof (struct elf_or1k_obj_tdata),
@@ -957,7 +991,6 @@ or1k_elf_link_hash_newfunc (struct bfd_hash_entry *entry,
       struct elf_or1k_link_hash_entry *eh;
 
       eh = (struct elf_or1k_link_hash_entry *) ret;
-      eh->dyn_relocs = NULL;
       eh->tls_type = TLS_UNKNOWN;
     }
 
@@ -970,7 +1003,7 @@ static struct bfd_link_hash_table *
 or1k_elf_link_hash_table_create (bfd *abfd)
 {
   struct elf_or1k_link_hash_table *ret;
-  bfd_size_type amt = sizeof (struct elf_or1k_link_hash_table);
+  size_t amt = sizeof (struct elf_or1k_link_hash_table);
 
   ret = bfd_zmalloc (amt);
   if (ret == NULL)
@@ -1023,7 +1056,7 @@ or1k_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
 
 /* Set the howto pointer for an Or1k ELF reloc.  */
 
-static bfd_boolean
+static bool
 or1k_info_to_howto_rela (bfd * abfd,
                         arelent * cache_ptr,
                         Elf_Internal_Rela * dst)
@@ -1037,25 +1070,55 @@ or1k_info_to_howto_rela (bfd * abfd,
       _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
                          abfd, r_type);
       bfd_set_error (bfd_error_bad_value);
-      return FALSE;
+      return false;
     }
   cache_ptr->howto = & or1k_elf_howto_table[r_type];
-  return TRUE;
+  return true;
 }
 
-
 /* Return the relocation value for @tpoff relocations..  */
 static bfd_vma
-tpoff (struct bfd_link_info *info, bfd_vma address)
+tpoff (struct bfd_link_info *info, bfd_vma address, bool dynamic)
 {
+  struct elf_link_hash_table *htab = elf_hash_table (info);
+  bfd_vma base;
+
   /* If tls_sec is NULL, we should have signalled an error already.  */
-  if (elf_hash_table (info)->tls_sec == NULL)
+  if (htab->tls_sec == NULL)
     return 0;
 
-  /* The thread pointer on or1k stores the address after the TCB where
-     the data is, just compute the difference. No need to compensate
-     for the size of TCB.  */
-  return (address - elf_hash_table (info)->tls_sec->vma);
+  if (dynamic)
+    return address - htab->tls_sec->vma;
+  else
+    {
+      /* On or1k, the tp points to just after the tcb, if we have an alignment
+        greater than the tcb size we need to offset by the alignment difference.  */
+      base = align_power ((bfd_vma) TCB_SIZE, htab->tls_sec->alignment_power)
+            - TCB_SIZE;
+
+      /* The thread pointer on or1k stores the address after the TCB where
+        the data is, just compute the difference. No need to compensate
+        for the size of TCB.  */
+      return address - htab->tls_sec->vma + base;
+    }
+}
+
+/* If we have both IE and GD accesses to a symbol the IE relocations should be
+   offset by 8 bytes because the got contains both GD and IE entries.  */
+static bfd_vma
+or1k_initial_exec_offset (reloc_howto_type *howto, unsigned char tls_type_mask)
+{
+   switch (howto->type)
+     {
+     case R_OR1K_TLS_IE_HI16:
+     case R_OR1K_TLS_IE_LO16:
+     case R_OR1K_TLS_IE_PG21:
+     case R_OR1K_TLS_IE_LO13:
+     case R_OR1K_TLS_IE_AHI16:
+       return (tls_type_mask & TLS_GD) != 0 ? 8 : 0;
+     default:
+       return 0;
+     }
 }
 
 /* Like _bfd_final_link_relocate, but handles non-contiguous fields.  */
@@ -1080,6 +1143,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:
@@ -1211,7 +1275,7 @@ or1k_final_link_relocate (reloc_howto_type *howto, bfd *input_bfd,
    section, which means that the addend must be adjusted
    accordingly.  */
 
-static bfd_boolean
+static int
 or1k_elf_relocate_section (bfd *output_bfd,
                           struct bfd_link_info *info,
                           bfd *input_bfd,
@@ -1226,17 +1290,16 @@ or1k_elf_relocate_section (bfd *output_bfd,
   Elf_Internal_Rela *rel;
   Elf_Internal_Rela *relend;
   struct elf_or1k_link_hash_table *htab = or1k_elf_hash_table (info);
-  bfd *dynobj;
   asection *sreloc;
   bfd_vma *local_got_offsets;
   asection *sgot, *splt;
   bfd_vma plt_base, got_base, got_sym_value;
-  bfd_boolean ret_val = TRUE;
+  bool ret_val = true;
+  bool saw_gotha = false;
 
   if (htab == NULL)
-    return FALSE;
+    return false;
 
-  dynobj = htab->root.dynobj;
   local_got_offsets = elf_local_got_offsets (input_bfd);
 
   sreloc = elf_section_data (input_section)->sreloc;
@@ -1254,7 +1317,7 @@ or1k_elf_relocate_section (bfd *output_bfd,
       got_sym_value = (hgot->root.u.def.value
                       + hgot->root.u.def.section->output_section->vma
                       + hgot->root.u.def.section->output_offset);
-    got_base = sgot->output_section->vma + sgot->output_offset;
+      got_base = sgot->output_section->vma + sgot->output_offset;
     }
 
   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
@@ -1286,7 +1349,7 @@ or1k_elf_relocate_section (bfd *output_bfd,
            (_("%pB: unknown relocation type %d"),
             input_bfd, (int) r_type);
          bfd_set_error (bfd_error_bad_value);
-         ret_val = FALSE;
+         ret_val = false;
          continue;
        }
 
@@ -1303,11 +1366,11 @@ or1k_elf_relocate_section (bfd *output_bfd,
 
          name = bfd_elf_string_from_elf_section
            (input_bfd, symtab_hdr->sh_link, sym->st_name);
-         name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
+         name = name == NULL ? bfd_section_name (sec) : name;
        }
       else
        {
-         bfd_boolean unresolved_reloc, warned, ignored;
+         bool unresolved_reloc, warned, ignored;
 
          RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
                                   r_symndx, symtab_hdr, sym_hashes,
@@ -1340,10 +1403,11 @@ or1k_elf_relocate_section (bfd *output_bfd,
                (_("%pB: addend should be zero for plt relocations"),
                 input_bfd);
              bfd_set_error (bfd_error_bad_value);
-             ret_val = FALSE;
+             ret_val = false;
            }
          break;
 
+       case R_OR1K_GOT_AHI16:
        case R_OR1K_GOT16:
        case R_OR1K_GOT_PG21:
        case R_OR1K_GOT_LO13:
@@ -1355,7 +1419,7 @@ or1k_elf_relocate_section (bfd *output_bfd,
          BFD_ASSERT (sgot != NULL);
          if (h != NULL)
            {
-             bfd_boolean dyn;
+             bool dyn;
 
              off = h->got.offset;
              BFD_ASSERT (off != (bfd_vma) -1);
@@ -1416,16 +1480,16 @@ or1k_elf_relocate_section (bfd *output_bfd,
 
                      /* We need to generate a R_OR1K_RELATIVE reloc
                         for the dynamic linker.  */
-                       srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+                     srelgot = htab->root.srelgot;
                      BFD_ASSERT (srelgot != NULL);
 
                      outrel.r_offset = got_base + off;
                      outrel.r_info = ELF32_R_INFO (0, R_OR1K_RELATIVE);
                      outrel.r_addend = relocation;
                      loc = srelgot->contents;
-                       loc += (srelgot->reloc_count
-                               * sizeof (Elf32_External_Rela));
-                     bfd_elf32_swap_reloca_out (output_bfd, &outrel,loc);
+                     loc += (srelgot->reloc_count
+                             * sizeof (Elf32_External_Rela));
+                     bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
                      ++srelgot->reloc_count;
                    }
                  local_got_offsets[r_symndx] |= 1;
@@ -1435,9 +1499,20 @@ 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 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)
            {
@@ -1445,7 +1520,7 @@ or1k_elf_relocate_section (bfd *output_bfd,
                (_("%pB: addend should be zero for got relocations"),
                 input_bfd);
              bfd_set_error (bfd_error_bad_value);
-             ret_val = FALSE;
+             ret_val = false;
            }
          }
          break;
@@ -1461,7 +1536,7 @@ or1k_elf_relocate_section (bfd *output_bfd,
              _bfd_error_handler
                (_("%pB: gotoff relocation against dynamic symbol %s"),
                 input_bfd, h->root.root.string);
-             ret_val = FALSE;
+             ret_val = false;
              bfd_set_error (bfd_error_bad_value);
            }
          relocation -= got_sym_value;
@@ -1478,7 +1553,7 @@ or1k_elf_relocate_section (bfd *output_bfd,
              _bfd_error_handler
                (_("%pB: pc-relative relocation against dynamic symbol %s"),
                 input_bfd, name);
-             ret_val = FALSE;
+             ret_val = false;
              bfd_set_error (bfd_error_bad_value);
            }
          break;
@@ -1492,7 +1567,7 @@ or1k_elf_relocate_section (bfd *output_bfd,
              _bfd_error_handler
                (_("%pB: non-pic relocation against symbol %s"),
                 input_bfd, name);
-             ret_val = FALSE;
+             ret_val = false;
              bfd_set_error (bfd_error_bad_value);
            }
          break;
@@ -1523,7 +1598,7 @@ or1k_elf_relocate_section (bfd *output_bfd,
              {
                Elf_Internal_Rela outrel;
                bfd_byte *loc;
-               bfd_boolean skip;
+               bool skip;
 
                /* When generating a shared object, these relocations
                   are copied into the output file to be resolved at run
@@ -1531,15 +1606,15 @@ or1k_elf_relocate_section (bfd *output_bfd,
 
                BFD_ASSERT (sreloc != NULL);
 
-               skip = FALSE;
+               skip = false;
 
                outrel.r_offset =
                  _bfd_elf_section_offset (output_bfd, info, input_section,
                                           rel->r_offset);
                if (outrel.r_offset == (bfd_vma) -1)
-                 skip = TRUE;
+                 skip = true;
                else if (outrel.r_offset == (bfd_vma) -2)
-                 skip = TRUE;
+                 skip = true;
                outrel.r_offset += (input_section->output_section->vma
                                    + input_section->output_offset);
 
@@ -1577,7 +1652,7 @@ or1k_elf_relocate_section (bfd *output_bfd,
            (_("%pB: support for local dynamic not implemented"),
             input_bfd);
          bfd_set_error (bfd_error_bad_value);
-         return FALSE;
+         return false;
 
        case R_OR1K_TLS_GD_HI16:
        case R_OR1K_TLS_GD_LO16:
@@ -1591,54 +1666,80 @@ or1k_elf_relocate_section (bfd *output_bfd,
          {
            bfd_vma gotoff;
            Elf_Internal_Rela rela;
+           asection *srelgot;
            bfd_byte *loc;
-           int dynamic;
+           bool dynamic;
+           int indx = 0;
+           unsigned char tls_type;
 
-           sreloc = bfd_get_section_by_name (dynobj, ".rela.got");
+           srelgot = htab->root.srelgot;
 
            /* Mark as TLS related GOT entry by setting
-              bit 2 as well as bit 1.  */
+              bit 2 to indcate TLS and bit 1 to indicate GOT.  */
            if (h != NULL)
              {
                gotoff = h->got.offset;
+               tls_type = ((struct elf_or1k_link_hash_entry *) h)->tls_type;
                h->got.offset |= 3;
              }
            else
              {
+               unsigned char *local_tls_type;
+
                gotoff = local_got_offsets[r_symndx];
+               local_tls_type = (unsigned char *) elf_or1k_local_tls_type (input_bfd);
+               tls_type = local_tls_type == NULL ? TLS_NONE
+                                                 : local_tls_type[r_symndx];
                local_got_offsets[r_symndx] |= 3;
              }
 
            /* Only process the relocation once.  */
-           if (gotoff & 1)
+           if ((gotoff & 1) != 0)
              {
-               relocation = sgot->output_offset + (gotoff  & ~3);
+               gotoff += or1k_initial_exec_offset (howto, tls_type);
+
+               /* The PG21 and LO13 relocs are pc-relative, while the
+                  rest are GOT relative.  */
+               relocation = got_base + (gotoff & ~3);
+               if (!(r_type == R_OR1K_TLS_GD_PG21
+                   || r_type == R_OR1K_TLS_GD_LO13
+                   || r_type == R_OR1K_TLS_IE_PG21
+                   || r_type == R_OR1K_TLS_IE_LO13))
+                 relocation -= got_sym_value;
                break;
              }
 
            BFD_ASSERT (elf_hash_table (info)->hgot == NULL
                        || elf_hash_table (info)->hgot->root.u.def.value == 0);
 
-           /* Dynamic entries will require relocations. if we do not need
+           if (h != NULL)
+             {
+               bool dyn = htab->root.dynamic_sections_created;
+               bool pic = bfd_link_pic (info);
+
+               if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, pic, h)
+                   && (!pic || !SYMBOL_REFERENCES_LOCAL (info, h)))
+                 indx = h->dynindx;
+             }
+
+           /* Dynamic entries will require relocations.  If we do not need
               them we will just use the default R_OR1K_NONE and
               not set anything.  */
-           dynamic = bfd_link_pic (info)
-             || (sec && (sec->flags & SEC_ALLOC) != 0
-                 && h != NULL
-                 && (h->root.type == bfd_link_hash_defweak || !h->def_regular));
+           dynamic = (bfd_link_pic (info) || indx != 0)
+                      && (h == NULL
+                          || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+                          || h->root.type != bfd_link_hash_undefweak);
 
            /* Shared GD.  */
-           if (dynamic
-               && (howto->type == R_OR1K_TLS_GD_HI16
-                   || howto->type == R_OR1K_TLS_GD_LO16
-                   || howto->type == R_OR1K_TLS_GD_PG21
-                   || howto->type == R_OR1K_TLS_GD_LO13))
+           if (dynamic && ((tls_type & TLS_GD) != 0))
              {
                int i;
 
                /* Add DTPMOD and DTPOFF GOT and rela entries.  */
                for (i = 0; i < 2; ++i)
                  {
+                   BFD_ASSERT (srelgot->contents != NULL);
+
                    rela.r_offset = got_base + gotoff + i*4;
                    if (h != NULL && h->dynindx != -1)
                      {
@@ -1650,30 +1751,33 @@ or1k_elf_relocate_section (bfd *output_bfd,
                      {
                        rela.r_info = ELF32_R_INFO (0,
                            (i == 0 ? R_OR1K_TLS_DTPMOD : R_OR1K_TLS_DTPOFF));
-                       rela.r_addend = tpoff (info, relocation);
+                       rela.r_addend =
+                           (i == 0 ? 0 : tpoff (info, relocation, dynamic));
                      }
 
-                   loc = sreloc->contents;
-                   loc += sreloc->reloc_count++ *
-                     sizeof (Elf32_External_Rela);
+                   loc = srelgot->contents;
+                   loc += (srelgot->reloc_count++
+                           * sizeof (Elf32_External_Rela));
 
                    bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
                    bfd_put_32 (output_bfd, 0, sgot->contents + gotoff + i*4);
                  }
              }
            /* Static GD.  */
-           else if (howto->type == R_OR1K_TLS_GD_HI16
-                    || howto->type == R_OR1K_TLS_GD_LO16
-                    || howto->type == R_OR1K_TLS_GD_PG21
-                    || howto->type == R_OR1K_TLS_GD_LO13)
+           else if ((tls_type & TLS_GD) != 0)
              {
                bfd_put_32 (output_bfd, 1, sgot->contents + gotoff);
-               bfd_put_32 (output_bfd, tpoff (info, relocation),
+               bfd_put_32 (output_bfd, tpoff (info, relocation, dynamic),
                    sgot->contents + gotoff + 4);
              }
+
+           gotoff += or1k_initial_exec_offset (howto, tls_type);
+
            /* Shared IE.  */
-           else if (dynamic)
+           if (dynamic && ((tls_type & TLS_IE) != 0))
              {
+               BFD_ASSERT (srelgot->contents != NULL);
+
                /* Add TPOFF GOT and rela entries.  */
                rela.r_offset = got_base + gotoff;
                if (h != NULL && h->dynindx != -1)
@@ -1684,21 +1788,19 @@ or1k_elf_relocate_section (bfd *output_bfd,
                else
                  {
                    rela.r_info = ELF32_R_INFO (0, R_OR1K_TLS_TPOFF);
-                   rela.r_addend = tpoff (info, relocation);
+                   rela.r_addend = tpoff (info, relocation, dynamic);
                  }
 
-               loc = sreloc->contents;
-               loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rela);
+               loc = srelgot->contents;
+               loc += srelgot->reloc_count++ * sizeof (Elf32_External_Rela);
 
                bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
                bfd_put_32 (output_bfd, 0, sgot->contents + gotoff);
              }
            /* Static IE.  */
-           else
-             {
-               bfd_put_32 (output_bfd, tpoff (info, relocation),
-                           sgot->contents + gotoff);
-             }
+           else if ((tls_type & TLS_IE) != 0)
+             bfd_put_32 (output_bfd, tpoff (info, relocation, dynamic),
+                         sgot->contents + gotoff);
 
            /* The PG21 and LO13 relocs are pc-relative, while the
               rest are GOT relative.  */
@@ -1716,7 +1818,7 @@ or1k_elf_relocate_section (bfd *output_bfd,
        case R_OR1K_TLS_LE_AHI16:
        case R_OR1K_TLS_LE_SLO16:
          /* Relocation is offset from TP.  */
-         relocation = tpoff (info, relocation);
+         relocation = tpoff (info, relocation, 0);
          break;
 
        case R_OR1K_TLS_DTPMOD:
@@ -1729,7 +1831,7 @@ or1k_elf_relocate_section (bfd *output_bfd,
            (_("%pB: will not resolve runtime TLS relocation"),
             input_bfd);
          bfd_set_error (bfd_error_bad_value);
-         return FALSE;
+         return false;
 
        default:
          break;
@@ -1752,7 +1854,7 @@ or1k_elf_relocate_section (bfd *output_bfd,
 
            case bfd_reloc_undefined:
              (*info->callbacks->undefined_symbol)
-               (info, name, input_bfd, input_section, rel->r_offset, TRUE);
+               (info, name, input_bfd, input_section, rel->r_offset, true);
              break;
 
            case bfd_reloc_outofrange:
@@ -1804,7 +1906,7 @@ or1k_elf_gc_mark_hook (asection *sec,
 
 /* Look through the relocs for a section during the first phase.  */
 
-static bfd_boolean
+static bool
 or1k_elf_check_relocs (bfd *abfd,
                       struct bfd_link_info *info,
                       asection *sec,
@@ -1820,23 +1922,14 @@ or1k_elf_check_relocs (bfd *abfd,
   asection *sreloc = NULL;
 
   if (bfd_link_relocatable (info))
-    return TRUE;
-
-  /* Don't do anything special with non-loaded, non-alloced sections.
-     In particular, any relocs in such sections should not affect GOT
-     and PLT reference counting (ie. we don't allow them to create GOT
-     or PLT entries), there's no possibility or desire to optimize TLS
-     relocs, and there's not much point in propagating relocs to shared
-     libs that the dynamic linker won't relocate.  */
-  if ((sec->flags & SEC_ALLOC) == 0)
-    return TRUE;
+    return true;
 
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
   sym_hashes = elf_sym_hashes (abfd);
 
   htab = or1k_elf_hash_table (info);
   if (htab == NULL)
-    return FALSE;
+    return false;
 
   dynobj = htab->root.dynobj;
 
@@ -1895,7 +1988,7 @@ or1k_elf_check_relocs (bfd *abfd,
 
       /* Record TLS type.  */
       if (h != NULL)
-         ((struct elf_or1k_link_hash_entry *) h)->tls_type = tls_type;
+         ((struct elf_or1k_link_hash_entry *) h)->tls_type |= tls_type;
       else
        {
          unsigned char *local_tls_type;
@@ -1909,10 +2002,10 @@ or1k_elf_check_relocs (bfd *abfd,
              size = symtab_hdr->sh_info;
              local_tls_type = bfd_zalloc (abfd, size);
              if (local_tls_type == NULL)
-               return FALSE;
+               return false;
              elf_or1k_local_tls_type (abfd) = local_tls_type;
            }
-         local_tls_type[r_symndx] = tls_type;
+         local_tls_type[r_symndx] |= tls_type;
        }
 
       switch (r_type)
@@ -1921,21 +2014,19 @@ or1k_elf_check_relocs (bfd *abfd,
             Reconstruct it for later use during GC.  */
        case R_OR1K_GNU_VTINHERIT:
          if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
-           return FALSE;
+           return false;
          break;
 
          /* This relocation describes which C++ vtable entries are actually
             used.  Record for later use during GC.  */
        case R_OR1K_GNU_VTENTRY:
-         BFD_ASSERT (h != NULL);
-         if (h != NULL
-             && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
-           return FALSE;
+         if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
+           return false;
          break;
 
          /* This relocation requires .plt entry.  */
        case R_OR1K_PLTA26:
-         htab->saw_plta = TRUE;
+         htab->saw_plta = true;
          /* FALLTHRU */
        case R_OR1K_PLT26:
          if (h != NULL)
@@ -1945,6 +2036,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:
@@ -1973,7 +2065,7 @@ or1k_elf_check_relocs (bfd *abfd,
                      size *= sizeof (bfd_signed_vma);
                      local_got_refcounts = bfd_zalloc (abfd, size);
                      if (local_got_refcounts == NULL)
-                       return FALSE;
+                       return false;
                      elf_local_got_refcounts (abfd) = local_got_refcounts;
                    }
                  local_got_refcounts[r_symndx] += 1;
@@ -1989,7 +2081,7 @@ or1k_elf_check_relocs (bfd *abfd,
              if (dynobj == NULL)
                htab->root.dynobj = dynobj = abfd;
              if (!_bfd_elf_create_got_section (dynobj, info))
-               return FALSE;
+               return false;
            }
          break;
 
@@ -2049,7 +2141,7 @@ or1k_elf_check_relocs (bfd *abfd,
                    && (h->root.type == bfd_link_hash_defweak
                        || !h->def_regular)))
              {
-               struct elf_dyn_relocs *p;
+               struct elf_dyn_relocs *sec_relocs;
                struct elf_dyn_relocs **head;
 
                /* When creating a shared object, we must copy these
@@ -2063,11 +2155,10 @@ or1k_elf_check_relocs (bfd *abfd,
 
                    name = bfd_elf_string_from_elf_section (abfd, strndx, shnam);
                    if (name == NULL)
-                     return FALSE;
+                     return false;
 
-                   if (strncmp (name, ".rela", 5) != 0
-                       || strcmp (bfd_get_section_name (abfd, sec),
-                                  name + 5) != 0)
+                   if (!startswith (name, ".rela")
+                       || strcmp (bfd_section_name (sec), name + 5) != 0)
                      {
                        _bfd_error_handler
                          /* xgettext:c-format */
@@ -2083,10 +2174,10 @@ or1k_elf_check_relocs (bfd *abfd,
                    if (sreloc == NULL)
                      {
                        sreloc = _bfd_elf_make_dynamic_reloc_section
-                         (sec, dynobj, 2, abfd, /*rela?*/ TRUE);
+                         (sec, dynobj, 2, abfd, /*rela?*/ true);
 
                        if (sreloc == NULL)
-                         return FALSE;
+                         return false;
                      }
                    elf_section_data (sec)->sreloc = sreloc;
                  }
@@ -2094,7 +2185,7 @@ or1k_elf_check_relocs (bfd *abfd,
                /* If this is a global symbol, we count the number of
                   relocations we need for this symbol.  */
                if (h != NULL)
-                 head = &((struct elf_or1k_link_hash_entry *) h)->dyn_relocs;
+                 head = &h->dyn_relocs;
                else
                  {
                    /* Track dynamic relocs needed for local syms too.
@@ -2105,79 +2196,94 @@ or1k_elf_check_relocs (bfd *abfd,
                    Elf_Internal_Sym *isym;
                    void *vpp;
 
-                   isym = bfd_sym_from_r_symndx (&htab->sym_sec,
+                   isym = bfd_sym_from_r_symndx (&htab->root.sym_cache,
                                                  abfd, r_symndx);
                    if (isym == NULL)
-                     return FALSE;
+                     return false;
 
                    s = bfd_section_from_elf_index (abfd, isym->st_shndx);
                    if (s == NULL)
-                     return FALSE;
+                     return false;
 
                    vpp = &elf_section_data (s)->local_dynrel;
                    head = (struct elf_dyn_relocs **) vpp;
                  }
 
-               p = *head;
-               if (p == NULL || p->sec != sec)
+               sec_relocs = *head;
+               /* Allocate this sections dynamic reolcations structure if this
+                  is a new section.  */
+               if (sec_relocs == NULL || sec_relocs->sec != sec)
                  {
-                   bfd_size_type amt = sizeof *p;
-                   p = ((struct elf_dyn_relocs *)
-                        bfd_alloc (htab->root.dynobj, amt));
-                   if (p == NULL)
-                     return FALSE;
-                   p->next = *head;
-                   *head = p;
-                   p->sec = sec;
-                   p->count = 0;
-                   p->pc_count = 0;
+                   size_t amt = sizeof *sec_relocs;
+                   sec_relocs = ((struct elf_dyn_relocs *)
+                                 bfd_alloc (htab->root.dynobj, amt));
+                   if (sec_relocs == NULL)
+                     return false;
+                   sec_relocs->next = *head;
+                   *head = sec_relocs;
+                   sec_relocs->sec = sec;
+                   sec_relocs->count = 0;
+                   sec_relocs->pc_count = 0;
                  }
 
-               p->count += 1;
+               sec_relocs->count += 1;
                if (r_type == R_OR1K_INSN_REL_26)
-                 p->pc_count += 1;
+                 sec_relocs->pc_count += 1;
              }
          }
          break;
        }
     }
 
-  return TRUE;
+  return true;
 }
 
 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.  */
 
-static bfd_boolean
+static bool
 or1k_elf_finish_dynamic_sections (bfd *output_bfd,
                                  struct bfd_link_info *info)
 {
@@ -2187,7 +2293,7 @@ or1k_elf_finish_dynamic_sections (bfd *output_bfd,
 
   htab = or1k_elf_hash_table (info);
   if (htab == NULL)
-    return FALSE;
+    return false;
 
   dynobj = htab->root.dynobj;
 
@@ -2239,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
@@ -2250,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;
        }
@@ -2292,13 +2399,13 @@ or1k_elf_finish_dynamic_sections (bfd *output_bfd,
   if (htab->root.sgot && htab->root.sgot->size > 0)
     elf_section_data (htab->root.sgot->output_section)->this_hdr.sh_entsize = 4;
 
-  return TRUE;
+  return true;
 }
 
 /* Finish up dynamic symbol handling.  We set the contents of various
    dynamic sections here.  */
 
-static bfd_boolean
+static bool
 or1k_elf_finish_dynamic_symbol (bfd *output_bfd,
                                struct bfd_link_info *info,
                                struct elf_link_hash_entry *h,
@@ -2309,11 +2416,12 @@ or1k_elf_finish_dynamic_symbol (bfd *output_bfd,
 
   htab = or1k_elf_hash_table (info);
   if (htab == NULL)
-    return FALSE;
+    return false;
 
   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;
@@ -2325,6 +2433,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.  */
@@ -2342,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.  */
@@ -2357,30 +2469,63 @@ 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);
+      /* 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
+        symbol as the first plt entry will be setup by libc to call the
+        runtime dynamic linker.  */
+      bfd_put_32 (output_bfd, plt_base_addr, sgot->contents + got_offset);
 
       /* Fill in the entry in the .rela.plt section.  */
       rela.r_offset = got_addr;
@@ -2402,14 +2547,14 @@ or1k_elf_finish_dynamic_symbol (bfd *output_bfd,
       && (h->got.offset & 2) == 0) /* Homemade TLS check.  */
     {
       asection *sgot;
-      asection *srela;
+      asection *srelgot;
       Elf_Internal_Rela rela;
 
       /* This symbol has an entry in the global offset table.  Set it
         up.  */
       sgot = htab->root.sgot;
-      srela = htab->root.srelgot;
-      BFD_ASSERT (sgot != NULL && srela != NULL);
+      srelgot = htab->root.srelgot;
+      BFD_ASSERT (sgot != NULL && srelgot != NULL);
 
       rela.r_offset = (sgot->output_section->vma
                       + sgot->output_offset
@@ -2435,10 +2580,10 @@ or1k_elf_finish_dynamic_symbol (bfd *output_bfd,
          rela.r_addend = 0;
        }
 
-      loc = srela->contents;
-      loc += srela->reloc_count * sizeof (Elf32_External_Rela);
+      loc = srelgot->contents;
+      loc += srelgot->reloc_count * sizeof (Elf32_External_Rela);
       bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
-      ++srela->reloc_count;
+      ++srelgot->reloc_count;
     }
 
   if (h->needs_copy)
@@ -2470,7 +2615,7 @@ or1k_elf_finish_dynamic_symbol (bfd *output_bfd,
       || h == htab->root.hgot)
     sym->st_shndx = SHN_ABS;
 
-  return TRUE;
+  return true;
 }
 
 static enum elf_reloc_type_class
@@ -2487,31 +2632,13 @@ or1k_elf_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED,
     }
 }
 
-/* Find dynamic relocs for H that apply to read-only sections.  */
-
-static asection *
-readonly_dynrelocs (struct elf_link_hash_entry *h)
-{
-  struct elf_dyn_relocs *p;
-  struct elf_or1k_link_hash_entry *eh = (struct elf_or1k_link_hash_entry *) h;
-
-  for (p = eh->dyn_relocs; p != NULL; p = p->next)
-    {
-      asection *s = p->sec->output_section;
-
-      if (s != NULL && (s->flags & SEC_READONLY) != 0)
-       return p->sec;
-    }
-  return NULL;
-}
-
 /* Adjust a symbol defined by a dynamic object and referenced by a
    regular object.  The current definition is in some section of the
    dynamic object, but we're not including those sections.  We have to
    change the definition to something the rest of the link can
    understand.  */
 
-static bfd_boolean
+static bool
 or1k_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
                                struct elf_link_hash_entry *h)
 {
@@ -2535,11 +2662,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
@@ -2550,7 +2676,7 @@ or1k_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
          h->needs_plt = 0;
        }
 
-      return TRUE;
+      return true;
     }
   else
     h->plt.offset = (bfd_vma) -1;
@@ -2564,7 +2690,7 @@ or1k_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
       BFD_ASSERT (def->root.type == bfd_link_hash_defined);
       h->root.u.def.section = def->root.u.def.section;
       h->root.u.def.value = def->root.u.def.value;
-      return TRUE;
+      return true;
     }
 
   /* This is a reference to a symbol defined by a dynamic object which
@@ -2575,26 +2701,26 @@ or1k_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
      For such cases we need not do anything here; the relocations will
      be handled correctly by relocate_section.  */
   if (bfd_link_pic (info))
-    return TRUE;
+    return true;
 
   /* If there are no references to this symbol that do not use the
      GOT, we don't need to generate a copy reloc.  */
   if (!h->non_got_ref)
-    return TRUE;
+    return true;
 
   /* If -z nocopyreloc was given, we won't generate them either.  */
   if (info->nocopyreloc)
     {
       h->non_got_ref = 0;
-      return TRUE;
+      return true;
     }
 
   /* If we don't find any dynamic relocs in read-only sections, then
      we'll be keeping the dynamic relocs and avoiding the copy reloc.  */
-  if (!readonly_dynrelocs (h))
+  if (!_bfd_elf_readonly_dynrelocs (h))
     {
       h->non_got_ref = 0;
-      return TRUE;
+      return true;
     }
 
   /* We must allocate the symbol in our .dynbss section, which will
@@ -2609,7 +2735,7 @@ or1k_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
 
   htab = or1k_elf_hash_table (info);
   if (htab == NULL)
-    return FALSE;
+    return false;
 
   /* We must generate a R_OR1K_COPY reloc to tell the dynamic linker
      to copy the initial value out of the dynamic object and into the
@@ -2634,26 +2760,73 @@ or1k_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
   return _bfd_elf_adjust_dynamic_copy (info, h, s);
 }
 
+/* Caclulate an update the sizes required for a symbol in the GOT and
+   RELA relocation section based on the TLS_TYPE and whether or not the symbol
+   is DYNAMIC.
+
+   Symbols with TLS_GD access require 8 bytes in the GOT and, if dynamic,
+   require two relocation entries.  Symbols with TLS_IE access require 4 bytes
+   in the GOT and, if dynamic, require one relocation entry.  Symbols may have
+   both TLS_GD and TLS_IE access to be accounted for.
+
+   Other symbols require 4 bytes in the GOT table and, if dynamic, require one
+   relocation entry.  */
+
+static void
+or1k_set_got_and_rela_sizes (const unsigned char tls_type,
+                            const bool dynamic,
+                            bfd_vma *got_size,
+                            bfd_vma *rela_size)
+{
+  bool is_tls_entry = false;
+
+  /* TLS GD requires two GOT entries and two relocs.  */
+  if ((tls_type & TLS_GD) != 0)
+    {
+      *got_size += 8;
+      is_tls_entry = true;
+    }
+
+  if ((tls_type & TLS_IE) != 0)
+    {
+      *got_size += 4;
+      is_tls_entry = true;
+    }
+
+  if (!is_tls_entry)
+    *got_size += 4;
+
+  if (dynamic)
+    {
+      if ((tls_type & TLS_GD) != 0)
+       *rela_size += 2 * sizeof (Elf32_External_Rela);
+
+      if ((tls_type & TLS_IE) != 0)
+       *rela_size += sizeof (Elf32_External_Rela);
+
+      if (!is_tls_entry)
+       *rela_size += sizeof (Elf32_External_Rela);
+    }
+}
+
+
 /* Allocate space in .plt, .got and associated reloc sections for
    dynamic relocs.  */
 
-static bfd_boolean
+static bool
 allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
 {
   struct bfd_link_info *info;
   struct elf_or1k_link_hash_table *htab;
-  struct elf_or1k_link_hash_entry *eh;
-  struct elf_dyn_relocs *p;
+  struct elf_dyn_relocs *sec_relocs;
 
   if (h->root.type == bfd_link_hash_indirect)
-    return TRUE;
+    return true;
 
   info = (struct bfd_link_info *) inf;
   htab = or1k_elf_hash_table (info);
   if (htab == NULL)
-    return FALSE;
-
-  eh = (struct elf_or1k_link_hash_entry *) h;
+    return false;
 
   if (htab->root.dynamic_sections_created
       && h->plt.refcount > 0)
@@ -2664,19 +2837,24 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
          && !h->forced_local)
        {
          if (! bfd_elf_link_record_dynamic_symbol (info, h))
-           return FALSE;
+           return false;
        }
 
       if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, bfd_link_pic (info), h))
        {
-         asection *s = htab->root.splt;
+         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 (s->size == 0)
-           s->size = PLT_ENTRY_SIZE;
+         if (splt->size == 0)
+           splt->size = elf_or1k_plt_entry_size (plt_index);
 
-         h->plt.offset = s->size;
+         h->plt.offset = splt->size;
 
          /* If this symbol is not defined in a regular file, and we are
             not generating a shared library, then set the symbol to this
@@ -2686,12 +2864,12 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
          if (! bfd_link_pic (info)
              && !h->def_regular)
            {
-             h->root.u.def.section = s;
+             h->root.u.def.section = splt;
              h->root.u.def.value = h->plt.offset;
            }
 
          /* Make room for this entry.  */
-         s->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.  */
@@ -2714,8 +2892,8 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
 
   if (h->got.refcount > 0)
     {
-      asection *s;
-      bfd_boolean dyn;
+      asection *sgot;
+      bool dyn;
       unsigned char tls_type;
 
       /* Make sure this symbol is output as a dynamic symbol.
@@ -2724,34 +2902,25 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
          && !h->forced_local)
        {
          if (! bfd_elf_link_record_dynamic_symbol (info, h))
-           return FALSE;
+           return false;
        }
 
-      s = htab->root.sgot;
+      sgot = htab->root.sgot;
 
-      h->got.offset = s->size;
+      h->got.offset = sgot->size;
 
       tls_type = ((struct elf_or1k_link_hash_entry *) h)->tls_type;
 
-      /* TLS GD requires two GOT and two relocs.  */
-      if (tls_type == TLS_GD)
-       s->size += 8;
-      else
-       s->size += 4;
       dyn = htab->root.dynamic_sections_created;
-      if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h))
-       {
-         if (tls_type == TLS_GD)
-           htab->root.srelgot->size += 2 * sizeof (Elf32_External_Rela);
-         else
-           htab->root.srelgot->size += sizeof (Elf32_External_Rela);
-       }
+      dyn = WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info), h);
+      or1k_set_got_and_rela_sizes (tls_type, dyn,
+                                  &sgot->size, &htab->root.srelgot->size);
     }
   else
     h->got.offset = (bfd_vma) -1;
 
-  if (eh->dyn_relocs == NULL)
-    return TRUE;
+  if (h->dyn_relocs == NULL)
+    return true;
 
   /* In the shared -Bsymbolic case, discard space allocated for
      dynamic pc-relative relocs against symbols which turn out to be
@@ -2765,24 +2934,24 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
        {
          struct elf_dyn_relocs **pp;
 
-         for (pp = &eh->dyn_relocs; (p = *pp) != NULL;)
+         for (pp = &h->dyn_relocs; (sec_relocs = *pp) != NULL;)
            {
-             p->count -= p->pc_count;
-             p->pc_count = 0;
-             if (p->count == 0)
-               *pp = p->next;
+             sec_relocs->count -= sec_relocs->pc_count;
+             sec_relocs->pc_count = 0;
+             if (sec_relocs->count == 0)
+               *pp = sec_relocs->next;
              else
-               pp = &p->next;
+               pp = &sec_relocs->next;
            }
        }
 
       /* Also discard relocs on undefined weak syms with non-default
         visibility.  */
-      if (eh->dyn_relocs != NULL
+      if (h->dyn_relocs != NULL
          && h->root.type == bfd_link_hash_undefweak)
        {
          if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
-           eh->dyn_relocs = NULL;
+           h->dyn_relocs = NULL;
 
          /* Make sure undefined weak symbols are output as a dynamic
             symbol in PIEs.  */
@@ -2790,7 +2959,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
                   && !h->forced_local)
            {
              if (! bfd_elf_link_record_dynamic_symbol (info, h))
-               return FALSE;
+               return false;
            }
        }
     }
@@ -2813,7 +2982,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
              && !h->forced_local)
            {
              if (! bfd_elf_link_record_dynamic_symbol (info, h))
-               return FALSE;
+               return false;
            }
 
          /* If that succeeded, we know we'll be keeping all the
@@ -2822,63 +2991,38 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
            goto keep;
        }
 
-      eh->dyn_relocs = NULL;
+      h->dyn_relocs = NULL;
 
     keep: ;
     }
 
   /* Finally, allocate space.  */
-  for (p = eh->dyn_relocs; p != NULL; p = p->next)
+  for (sec_relocs = h->dyn_relocs;
+       sec_relocs != NULL;
+       sec_relocs = sec_relocs->next)
     {
-      asection *sreloc = elf_section_data (p->sec)->sreloc;
-      sreloc->size += p->count * sizeof (Elf32_External_Rela);
+      asection *sreloc = elf_section_data (sec_relocs->sec)->sreloc;
+      sreloc->size += sec_relocs->count * sizeof (Elf32_External_Rela);
     }
 
-  return TRUE;
-}
-
-/* Set DF_TEXTREL if we find any dynamic relocs that apply to
-   read-only sections.  */
-
-static bfd_boolean
-maybe_set_textrel (struct elf_link_hash_entry *h, void *info_p)
-{
-  asection *sec;
-
-  if (h->root.type == bfd_link_hash_indirect)
-    return TRUE;
-
-  sec = readonly_dynrelocs (h);
-  if (sec != NULL)
-    {
-      struct bfd_link_info *info = (struct bfd_link_info *) info_p;
-
-      info->flags |= DF_TEXTREL;
-      info->callbacks->minfo
-       (_("%pB: dynamic relocation against `%pT' in read-only section `%pA'\n"),
-        sec->owner, h->root.root.string, sec);
-
-      /* Not an error, just cut short the traversal.  */
-      return FALSE;
-    }
-  return TRUE;
+  return true;
 }
 
 /* Set the sizes of the dynamic sections.  */
 
-static bfd_boolean
+static bool
 or1k_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
                                struct bfd_link_info *info)
 {
   struct elf_or1k_link_hash_table *htab;
   bfd *dynobj;
   asection *s;
-  bfd_boolean relocs;
+  bool relocs;
   bfd *ibfd;
 
   htab = or1k_elf_hash_table (info);
   if (htab == NULL)
-    return FALSE;
+    return false;
 
   dynobj = htab->root.dynobj;
   BFD_ASSERT (dynobj != NULL);
@@ -2911,26 +3055,28 @@ or1k_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
 
       for (s = ibfd->sections; s != NULL; s = s->next)
        {
-         struct elf_dyn_relocs *p;
+         struct elf_dyn_relocs *sec_relocs;
 
-         for (p = ((struct elf_dyn_relocs *)
-                   elf_section_data (s)->local_dynrel);
-              p != NULL;
-              p = p->next)
+         for (sec_relocs = ((struct elf_dyn_relocs *)
+                            elf_section_data (s)->local_dynrel);
+              sec_relocs != NULL;
+              sec_relocs = sec_relocs->next)
            {
-             if (! bfd_is_abs_section (p->sec)
-                 && bfd_is_abs_section (p->sec->output_section))
+             if (! bfd_is_abs_section (sec_relocs->sec)
+                 && bfd_is_abs_section (sec_relocs->sec->output_section))
                {
                  /* Input section has been discarded, either because
                     it is a copy of a linkonce section or due to
                     linker script /DISCARD/, so we'll be discarding
                     the relocs too.  */
                }
-             else if (p->count != 0)
+             else if (sec_relocs->count != 0)
                {
-                 srel = elf_section_data (p->sec)->sreloc;
-                 srel->size += p->count * sizeof (Elf32_External_Rela);
-                 if ((p->sec->output_section->flags & SEC_READONLY) != 0)
+                 srel = elf_section_data (sec_relocs->sec)->sreloc;
+                 srel->size += sec_relocs->count
+                               * sizeof (Elf32_External_Rela);
+                 if ((sec_relocs->sec->output_section->flags & SEC_READONLY)
+                     != 0)
                    info->flags |= DF_TEXTREL;
                }
            }
@@ -2950,20 +3096,13 @@ or1k_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
        {
          if (*local_got > 0)
            {
-             *local_got = s->size;
+             unsigned char tls_type = (local_tls_type == NULL)
+                                       ? TLS_UNKNOWN
+                                       : *local_tls_type;
 
-             /* TLS GD requires two GOT and two relocs.  */
-             if (local_tls_type != NULL && *local_tls_type == TLS_GD)
-               s->size += 8;
-             else
-               s->size += 4;
-             if (bfd_link_pic (info))
-               {
-                 if (local_tls_type != NULL && *local_tls_type == TLS_GD)
-                   srel->size += 2 * sizeof (Elf32_External_Rela);
-                 else
-                   srel->size += sizeof (Elf32_External_Rela);
-               }
+             *local_got = s->size;
+             or1k_set_got_and_rela_sizes (tls_type, bfd_link_pic (info),
+                                          &s->size, &srel->size);
            }
          else
 
@@ -2980,7 +3119,7 @@ or1k_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
 
   /* We now have determined the sizes of the various dynamic sections.
      Allocate memory for them.  */
-  relocs = FALSE;
+  relocs = false;
   for (s = dynobj->sections; s != NULL; s = s->next)
     {
       if ((s->flags & SEC_LINKER_CREATED) == 0)
@@ -2995,10 +3134,10 @@ or1k_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
          /* Strip this section if we don't need it; see the
             comment below.  */
        }
-      else if (CONST_STRNEQ (bfd_get_section_name (dynobj, s), ".rela"))
+      else if (startswith (bfd_section_name (s), ".rela"))
        {
          if (s->size != 0 && s != htab->root.srelplt)
-           relocs = TRUE;
+           relocs = true;
 
          /* We use the reloc_count field as a counter if we need
             to copy relocs into the output file.  */
@@ -3034,57 +3173,10 @@ or1k_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
       s->contents = bfd_zalloc (dynobj, s->size);
 
       if (s->contents == NULL)
-       return FALSE;
+       return false;
     }
 
-  if (htab->root.dynamic_sections_created)
-    {
-      /* Add some entries to the .dynamic section.  We fill in the
-        values later, in or1k_elf_finish_dynamic_sections, but we
-        must add the entries now so that we get the correct size for
-        the .dynamic section.  The DT_DEBUG entry is filled in by the
-        dynamic linker and used by the debugger.  */
-#define add_dynamic_entry(TAG, VAL) \
-  _bfd_elf_add_dynamic_entry (info, TAG, VAL)
-
-     if (bfd_link_executable (info))
-       {
-        if (! add_dynamic_entry (DT_DEBUG, 0))
-          return FALSE;
-       }
-
-     if (htab->root.splt->size != 0)
-       {
-        if (! add_dynamic_entry (DT_PLTGOT, 0)
-            || ! add_dynamic_entry (DT_PLTRELSZ, 0)
-            || ! add_dynamic_entry (DT_PLTREL, DT_RELA)
-            || ! add_dynamic_entry (DT_JMPREL, 0))
-          return FALSE;
-       }
-
-     if (relocs)
-       {
-        if (! add_dynamic_entry (DT_RELA, 0)
-            || ! add_dynamic_entry (DT_RELASZ, 0)
-            || ! add_dynamic_entry (DT_RELAENT,
-                                    sizeof (Elf32_External_Rela)))
-          return FALSE;
-
-        /* If any dynamic relocs apply to a read-only section,
-           then we need a DT_TEXTREL entry.  */
-        if ((info->flags & DF_TEXTREL) == 0)
-          elf_link_hash_traverse (&htab->root, maybe_set_textrel, info);
-
-        if ((info->flags & DF_TEXTREL) != 0)
-          {
-            if (! add_dynamic_entry (DT_TEXTREL, 0))
-              return FALSE;
-          }
-       }
-    }
-
-#undef add_dynamic_entry
-  return TRUE;
+  return _bfd_elf_add_dynamic_tags (output_bfd, info, relocs);
 }
 
 /* Copy the extra info we tack onto an elf_link_hash_entry.  */
@@ -3100,37 +3192,6 @@ or1k_elf_copy_indirect_symbol (struct bfd_link_info *info,
   edir = (struct elf_or1k_link_hash_entry *) dir;
   eind = (struct elf_or1k_link_hash_entry *) ind;
 
-  if (eind->dyn_relocs != NULL)
-    {
-      if (edir->dyn_relocs != NULL)
-       {
-         struct elf_dyn_relocs **pp;
-         struct elf_dyn_relocs *p;
-
-         /* Add reloc counts against the indirect sym to the direct sym
-            list.  Merge any entries against the same section.  */
-         for (pp = &eind->dyn_relocs; (p = *pp) != NULL;)
-           {
-             struct elf_dyn_relocs *q;
-
-             for (q = edir->dyn_relocs; q != NULL; q = q->next)
-               if (q->sec == p->sec)
-                 {
-                   q->pc_count += p->pc_count;
-                   q->count += p->count;
-                   *pp = p->next;
-                   break;
-                 }
-             if (q == NULL)
-               pp = &p->next;
-           }
-         *pp = edir->dyn_relocs;
-       }
-
-      edir->dyn_relocs = eind->dyn_relocs;
-      eind->dyn_relocs = NULL;
-    }
-
   if (ind->root.type == bfd_link_hash_indirect)
     {
       if (dir->got.refcount <= 0)
@@ -3145,7 +3206,7 @@ or1k_elf_copy_indirect_symbol (struct bfd_link_info *info,
 
 /* Set the right machine number.  */
 
-static bfd_boolean
+static bool
 or1k_elf_object_p (bfd *abfd)
 {
   unsigned long mach = bfd_mach_or1k;
@@ -3158,9 +3219,8 @@ or1k_elf_object_p (bfd *abfd)
 
 /* Store the machine number in the flags field.  */
 
-static void
-or1k_elf_final_write_processing (bfd *abfd,
-                                bfd_boolean linker ATTRIBUTE_UNUSED)
+static bool
+or1k_elf_final_write_processing (bfd *abfd)
 {
   switch (bfd_get_mach (abfd))
     {
@@ -3171,23 +3231,24 @@ or1k_elf_final_write_processing (bfd *abfd,
       elf_elfheader (abfd)->e_flags |= EF_OR1K_NODELAY;
       break;
     }
+  return _bfd_elf_final_write_processing (abfd);
 }
 
-static bfd_boolean
+static bool
 or1k_elf_set_private_flags (bfd *abfd, flagword flags)
 {
   BFD_ASSERT (!elf_flags_init (abfd)
              || elf_elfheader (abfd)->e_flags == flags);
 
   elf_elfheader (abfd)->e_flags = flags;
-  elf_flags_init (abfd) = TRUE;
-  return TRUE;
+  elf_flags_init (abfd) = true;
+  return true;
 }
 
 /* Make sure all input files are consistent with respect to
    EF_OR1K_NODELAY flag setting.  */
 
-static bfd_boolean
+static bool
 elf32_or1k_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
 {
   bfd *obfd = info->output_bfd;
@@ -3199,18 +3260,18 @@ elf32_or1k_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
 
   if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
       || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
-    return TRUE;
+    return true;
 
   if (!elf_flags_init (obfd))
     {
-      elf_flags_init (obfd) = TRUE;
+      elf_flags_init (obfd) = true;
       elf_elfheader (obfd)->e_flags = in_flags;
 
-      return TRUE;
+      return true;
     }
 
   if (in_flags == out_flags)
-    return TRUE;
+    return true;
 
   if ((in_flags & EF_OR1K_NODELAY) != (out_flags & EF_OR1K_NODELAY))
     {
@@ -3219,16 +3280,16 @@ elf32_or1k_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
         ibfd, "EF_OR1K_NODELAY");
 
       bfd_set_error (bfd_error_bad_value);
-      return FALSE;
+      return false;
     }
 
-  return TRUE;
+  return true;
 
 }
 
 /* Implement elf_backend_grok_prstatus:
    Support for core dump NOTE sections.  */
-static bfd_boolean
+static bool
 or1k_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
 {
   int offset;
@@ -3237,7 +3298,7 @@ or1k_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
   switch (note->descsz)
     {
     default:
-      return FALSE;
+      return false;
 
     case 212:        /* Linux/OpenRISC */
       /* pr_cursig */
@@ -3259,13 +3320,13 @@ or1k_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
 }
 
 /* Implement elf_backend_grok_psinfo.  */
-static bfd_boolean
+static bool
 or1k_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
 {
   switch (note->descsz)
     {
     default:
-      return FALSE;
+      return false;
 
     case 128:        /* Linux/OpenRISC elf_prpsinfo */
       elf_tdata (abfd)->core->program
@@ -3274,7 +3335,7 @@ or1k_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
        = _bfd_elfcore_strndup (abfd, note->descdata + 48, 80);
     }
 
-  return TRUE;
+  return true;
 }
 
 
This page took 0.078111 seconds and 4 git commands to generate.