]> oss.titaniummirror.com Git - msp430-binutils.git/blobdiff - bfd/elf32-bfin.c
Imported binutils-2.20
[msp430-binutils.git] / bfd / elf32-bfin.c
index f3d94804ea90363e000ff6cfca413f8696c35c2b..a767749012fc236413cafbb5b4c4bf92e7ad4316 100644 (file)
@@ -1,5 +1,5 @@
 /* ADI Blackfin BFD support for 32-bit ELF.
-   Copyright 2005, 2006, 2007 Free Software Foundation, Inc.
+   Copyright 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
@@ -23,7 +23,7 @@
 #include "libbfd.h"
 #include "elf-bfd.h"
 #include "elf/bfin.h"
-#include "elf/dwarf2.h"
+#include "dwarf2.h"
 #include "hashtab.h"
 
 /* FUNCTION : bfin_pltpc_reloc
@@ -421,7 +421,7 @@ bfin_bfd_reloc (bfd *abfd,
 static reloc_howto_type bfin_howto_table [] =
 {
   /* This reloc does nothing. .  */
-  HOWTO (R_unused0,            /* type.  */
+  HOWTO (R_BFIN_UNUSED0,       /* type.  */
         0,                     /* rightshift.  */
         2,                     /* size (0 = byte, 1 = short, 2 = long).  */
         32,                    /* bitsize.  */
@@ -429,13 +429,13 @@ static reloc_howto_type bfin_howto_table [] =
         0,                     /* bitpos.  */
         complain_overflow_bitfield, /* complain_on_overflow.  */
         bfd_elf_generic_reloc, /* special_function.  */
-        "R_unused0",           /* name.  */
+        "R_BFIN_UNUSED0",      /* name.  */
         FALSE,                 /* partial_inplace.  */
         0,                     /* src_mask.  */
         0,                     /* dst_mask.  */
         FALSE),                /* pcrel_offset.  */
 
-  HOWTO (R_pcrel5m2,           /* type.  */
+  HOWTO (R_BFIN_PCREL5M2,      /* type.  */
         1,                     /* rightshift.  */
         1,                     /* size (0 = byte, 1 = short, 2 = long)..  */
         4,                     /* bitsize.  */
@@ -443,13 +443,13 @@ static reloc_howto_type bfin_howto_table [] =
         0,                     /* bitpos.  */
         complain_overflow_unsigned, /* complain_on_overflow.  */
         bfin_bfd_reloc,        /* special_function.  */
-        "R_pcrel5m2",          /* name.  */
+        "R_BFIN_PCREL5M2",     /* name.  */
         FALSE,                 /* partial_inplace.  */
         0,                     /* src_mask.  */
         0x0000000F,            /* dst_mask.  */
         FALSE),                /* pcrel_offset.  */
 
-  HOWTO (R_unused1,            /* type.  */
+  HOWTO (R_BFIN_UNUSED1,       /* type.  */
         0,                     /* rightshift.  */
         2,                     /* size (0 = byte, 1 = short, 2 = long).  */
         32,                    /* bitsize.  */
@@ -457,13 +457,13 @@ static reloc_howto_type bfin_howto_table [] =
         0,                     /* bitpos.  */
         complain_overflow_bitfield, /* complain_on_overflow.  */
         bfd_elf_generic_reloc, /* special_function.  */
-        "R_unused1",           /* name.  */
+        "R_BFIN_UNUSED1",      /* name.  */
         FALSE,                 /* partial_inplace.  */
         0,                     /* src_mask.  */
         0,                     /* dst_mask.  */
         FALSE),                /* pcrel_offset.  */
 
-  HOWTO (R_pcrel10,            /* type.  */
+  HOWTO (R_BFIN_PCREL10,       /* type.  */
         1,                     /* rightshift.  */
         1,                     /* size (0 = byte, 1 = short, 2 = long).  */
         10,                    /* bitsize.  */
@@ -471,13 +471,13 @@ static reloc_howto_type bfin_howto_table [] =
         0,                     /* bitpos.  */
         complain_overflow_signed, /* complain_on_overflow.  */
         bfin_bfd_reloc,        /* special_function.  */
-        "R_pcrel10",           /* name.  */
+        "R_BFIN_PCREL10",      /* name.  */
         FALSE,                 /* partial_inplace.  */
         0,                     /* src_mask.  */
         0x000003FF,            /* dst_mask.  */
         TRUE),                 /* pcrel_offset.  */
 
-  HOWTO (R_pcrel12_jump,       /* type.  */
+  HOWTO (R_BFIN_PCREL12_JUMP,  /* type.  */
         1,                     /* rightshift.  */
                                /* the offset is actually 13 bit
                                   aligned on a word boundary so
@@ -489,13 +489,13 @@ static reloc_howto_type bfin_howto_table [] =
         0,                     /* bitpos.  */
         complain_overflow_signed, /* complain_on_overflow.  */
         bfin_bfd_reloc,        /* special_function.  */
-        "R_pcrel12_jump",      /* name.  */
+        "R_BFIN_PCREL12_JUMP", /* name.  */
         FALSE,                 /* partial_inplace.  */
         0,                     /* src_mask.  */
         0x0FFF,                /* dst_mask.  */
         TRUE),                 /* pcrel_offset.  */
 
-  HOWTO (R_rimm16,             /* type.  */
+  HOWTO (R_BFIN_RIMM16,                /* type.  */
         0,                     /* rightshift.  */
         1,                     /* size (0 = byte, 1 = short, 2 = long).  */
         16,                    /* bitsize.  */
@@ -503,13 +503,13 @@ static reloc_howto_type bfin_howto_table [] =
         0,                     /* bitpos.  */
         complain_overflow_signed, /* complain_on_overflow.  */
         bfin_imm16_reloc,      /* special_function.  */
-        "R_rimm16",            /* name.  */
+        "R_BFIN_RIMM16",       /* name.  */
         FALSE,                 /* partial_inplace.  */
         0,                     /* src_mask.  */
         0x0000FFFF,            /* dst_mask.  */
         TRUE),                 /* pcrel_offset.  */
 
-  HOWTO (R_luimm16,            /* type.  */
+  HOWTO (R_BFIN_LUIMM16,       /* type.  */
         0,                     /* rightshift.  */
         1,                     /* size (0 = byte, 1 = short, 2 = long).  */
         16,                    /* bitsize.  */
@@ -517,13 +517,13 @@ static reloc_howto_type bfin_howto_table [] =
         0,                     /* bitpos.  */
         complain_overflow_dont, /* complain_on_overflow.  */
         bfin_imm16_reloc,      /* special_function.  */
-        "R_luimm16",           /* name.  */
+        "R_BFIN_LUIMM16",      /* name.  */
         FALSE,                 /* partial_inplace.  */
         0,                     /* src_mask.  */
         0x0000FFFF,            /* dst_mask.  */
         TRUE),                 /* pcrel_offset.  */
 
-  HOWTO (R_huimm16,            /* type.  */
+  HOWTO (R_BFIN_HUIMM16,       /* type.  */
         16,                    /* rightshift.  */
         1,                     /* size (0 = byte, 1 = short, 2 = long).  */
         16,                    /* bitsize.  */
@@ -531,13 +531,13 @@ static reloc_howto_type bfin_howto_table [] =
         0,                     /* bitpos.  */
         complain_overflow_unsigned, /* complain_on_overflow.  */
         bfin_imm16_reloc,      /* special_function.  */
-        "R_huimm16",           /* name.  */
+        "R_BFIN_HUIMM16",      /* name.  */
         FALSE,                 /* partial_inplace.  */
         0,                     /* src_mask.  */
         0x0000FFFF,            /* dst_mask.  */
         TRUE),                 /* pcrel_offset.  */
 
-  HOWTO (R_pcrel12_jump_s,     /* type.  */
+  HOWTO (R_BFIN_PCREL12_JUMP_S,        /* type.  */
         1,                     /* rightshift.  */
         1,                     /* size (0 = byte, 1 = short, 2 = long).  */
         12,                    /* bitsize.  */
@@ -545,13 +545,13 @@ static reloc_howto_type bfin_howto_table [] =
         0,                     /* bitpos.  */
         complain_overflow_signed, /* complain_on_overflow.  */
         bfin_bfd_reloc,        /* special_function.  */
-        "R_pcrel12_jump_s",    /* name.  */
+        "R_BFIN_PCREL12_JUMP_S", /* name.  */
         FALSE,                 /* partial_inplace.  */
         0,                     /* src_mask.  */
         0x00000FFF,            /* dst_mask.  */
         TRUE),                 /* pcrel_offset.  */
 
-  HOWTO (R_pcrel24_jump_x,     /* type.  */
+  HOWTO (R_BFIN_PCREL24_JUMP_X,        /* type.  */
          1,                    /* rightshift.  */
          2,                    /* size (0 = byte, 1 = short, 2 = long).  */
          24,                   /* bitsize.  */
@@ -559,13 +559,13 @@ static reloc_howto_type bfin_howto_table [] =
          0,                    /* bitpos.  */
          complain_overflow_signed, /* complain_on_overflow.  */
          bfin_pcrel24_reloc,   /* special_function.  */
-         "R_pcrel24_jump_x",   /* name.  */
+       "R_BFIN_PCREL24_JUMP_X", /* name.  */
         FALSE,                 /* partial_inplace.  */
         0,                     /* src_mask.  */
         0x00FFFFFF,            /* dst_mask.  */
         TRUE),                 /* pcrel_offset.  */
 
-  HOWTO (R_pcrel24,            /* type.  */
+  HOWTO (R_BFIN_PCREL24,       /* type.  */
         1,                     /* rightshift.  */
         2,                     /* size (0 = byte, 1 = short, 2 = long).  */
         24,                    /* bitsize.  */
@@ -573,13 +573,13 @@ static reloc_howto_type bfin_howto_table [] =
         0,                     /* bitpos.  */
         complain_overflow_signed, /* complain_on_overflow.  */
         bfin_pcrel24_reloc,    /* special_function.  */
-        "R_pcrel24",           /* name.  */
+        "R_BFIN_PCREL24",      /* name.  */
         FALSE,                 /* partial_inplace.  */
         0,                     /* src_mask.  */
         0x00FFFFFF,            /* dst_mask.  */
         TRUE),                 /* pcrel_offset.  */
 
-  HOWTO (R_unusedb,            /* type.  */
+  HOWTO (R_BFIN_UNUSEDB,       /* type.  */
         0,                     /* rightshift.  */
         2,                     /* size (0 = byte, 1 = short, 2 = long).  */
         32,                    /* bitsize.  */
@@ -587,13 +587,13 @@ static reloc_howto_type bfin_howto_table [] =
         0,                     /* bitpos.  */
         complain_overflow_dont, /* complain_on_overflow.  */
         bfd_elf_generic_reloc, /* special_function.  */
-        "R_unusedb",           /* name.  */
+        "R_BFIN_UNUSEDB",      /* name.  */
         FALSE,                 /* partial_inplace.  */
         0,                     /* src_mask.  */
         0,                     /* dst_mask.  */
         FALSE),                /* pcrel_offset.  */
 
-  HOWTO (R_unusedc,            /* type.  */
+  HOWTO (R_BFIN_UNUSEDC,       /* type.  */
         0,                     /* rightshift.  */
         2,                     /* size (0 = byte, 1 = short, 2 = long).  */
         32,                    /* bitsize.  */
@@ -601,13 +601,13 @@ static reloc_howto_type bfin_howto_table [] =
         0,                     /* bitpos.  */
         complain_overflow_dont, /* complain_on_overflow.  */
         bfd_elf_generic_reloc, /* special_function.  */
-        "R_unusedc",           /* name.  */
+        "R_BFIN_UNUSEDC",      /* name.  */
         FALSE,                 /* partial_inplace.  */
         0,                     /* src_mask.  */
         0,                     /* dst_mask.  */
         FALSE),                /* pcrel_offset.  */
 
-  HOWTO (R_pcrel24_jump_l,     /* type.  */
+  HOWTO (R_BFIN_PCREL24_JUMP_L,        /* type.  */
         1,                     /* rightshift.  */
         2,                     /* size (0 = byte, 1 = short, 2 = long).  */
         24,                    /* bitsize.  */
@@ -615,13 +615,13 @@ static reloc_howto_type bfin_howto_table [] =
         0,                     /* bitpos.  */
         complain_overflow_signed, /* complain_on_overflow.  */
         bfin_pcrel24_reloc,    /* special_function.  */
-        "R_pcrel24_jump_l",    /* name.  */
+        "R_BFIN_PCREL24_JUMP_L", /* name.  */
         FALSE,                 /* partial_inplace.  */
         0,                     /* src_mask.  */
         0x00FFFFFF,            /* dst_mask.  */
         TRUE),                 /* pcrel_offset.  */
 
-  HOWTO (R_pcrel24_call_x,     /* type.  */
+  HOWTO (R_BFIN_PCREL24_CALL_X,        /* type.  */
         1,                     /* rightshift.  */
         2,                     /* size (0 = byte, 1 = short, 2 = long).  */
         24,                    /* bitsize.  */
@@ -629,13 +629,13 @@ static reloc_howto_type bfin_howto_table [] =
         0,                     /* bitpos.  */
         complain_overflow_signed, /* complain_on_overflow.  */
         bfin_pcrel24_reloc,    /* special_function.  */
-        "R_pcrel24_call_x",    /* name.  */
+        "R_BFIN_PCREL24_CALL_X", /* name.  */
         FALSE,                 /* partial_inplace.  */
         0,                     /* src_mask.  */
         0x00FFFFFF,            /* dst_mask.  */
         TRUE),                 /* pcrel_offset.  */
 
-  HOWTO (R_var_eq_symb,                /* type.  */
+  HOWTO (R_BFIN_VAR_EQ_SYMB,   /* type.  */
         0,                     /* rightshift.  */
         2,                     /* size (0 = byte, 1 = short, 2 = long).  */
         32,                    /* bitsize.  */
@@ -643,13 +643,13 @@ static reloc_howto_type bfin_howto_table [] =
         0,                     /* bitpos.  */
         complain_overflow_bitfield, /* complain_on_overflow.  */
         bfin_bfd_reloc,        /* special_function.  */
-        "R_var_eq_symb",               /* name.  */
+        "R_BFIN_VAR_EQ_SYMB",  /* name.  */
         FALSE,                 /* partial_inplace.  */
         0,                     /* src_mask.  */
         0,                     /* dst_mask.  */
         FALSE),                /* pcrel_offset.  */
 
-  HOWTO (R_byte_data,          /* type.  */
+  HOWTO (R_BFIN_BYTE_DATA,     /* type.  */
         0,                     /* rightshift.  */
         0,                     /* size (0 = byte, 1 = short, 2 = long).  */
         8,                     /* bitsize.  */
@@ -657,13 +657,13 @@ static reloc_howto_type bfin_howto_table [] =
         0,                     /* bitpos.  */
         complain_overflow_unsigned, /* complain_on_overflow.  */
         bfin_bfd_reloc,        /* special_function.  */
-        "R_byte_data",         /* name.  */
+        "R_BFIN_BYTE_DATA",    /* name.  */
         FALSE,                 /* partial_inplace.  */
         0,                     /* src_mask.  */
         0xFF,                  /* dst_mask.  */
         TRUE),                 /* pcrel_offset.  */
 
-  HOWTO (R_byte2_data,         /* type.  */
+  HOWTO (R_BFIN_BYTE2_DATA,    /* type.  */
         0,                     /* rightshift.  */
         1,                     /* size (0 = byte, 1 = short, 2 = long).  */
         16,                    /* bitsize.  */
@@ -671,13 +671,13 @@ static reloc_howto_type bfin_howto_table [] =
         0,                     /* bitpos.  */
         complain_overflow_signed, /* complain_on_overflow.  */
         bfin_bfd_reloc,        /* special_function.  */
-        "R_byte2_data",        /* name.  */
+        "R_BFIN_BYTE2_DATA",   /* name.  */
         FALSE,                 /* partial_inplace.  */
         0,                     /* src_mask.  */
         0xFFFF,                /* dst_mask.  */
         TRUE),                 /* pcrel_offset.  */
 
-  HOWTO (R_byte4_data,         /* type.  */
+  HOWTO (R_BFIN_BYTE4_DATA,    /* type.  */
         0,                     /* rightshift.  */
         2,                     /* size (0 = byte, 1 = short, 2 = long).  */
         32,                    /* bitsize.  */
@@ -685,13 +685,13 @@ static reloc_howto_type bfin_howto_table [] =
         0,                     /* bitpos.  */
         complain_overflow_unsigned, /* complain_on_overflow.  */
         bfin_byte4_reloc,      /* special_function.  */
-        "R_byte4_data",        /* name.  */
+        "R_BFIN_BYTE4_DATA",   /* name.  */
         FALSE,                 /* partial_inplace.  */
         0,                     /* src_mask.  */
         0xFFFFFFFF,            /* dst_mask.  */
         TRUE),                 /* pcrel_offset.  */
 
-  HOWTO (R_pcrel11,            /* type.  */
+  HOWTO (R_BFIN_PCREL11,       /* type.  */
         1,                     /* rightshift.  */
         1,                     /* size (0 = byte, 1 = short, 2 = long).  */
         10,                    /* bitsize.  */
@@ -699,7 +699,7 @@ static reloc_howto_type bfin_howto_table [] =
         0,                     /* bitpos.  */
         complain_overflow_unsigned, /* complain_on_overflow.  */
         bfin_bfd_reloc,        /* special_function.  */
-        "R_pcrel11",           /* name.  */
+        "R_BFIN_PCREL11",      /* name.  */
         FALSE,                 /* partial_inplace.  */
         0,                     /* src_mask.  */
         0x000003FF,            /* dst_mask.  */
@@ -716,7 +716,7 @@ static reloc_howto_type bfin_howto_table [] =
         0,                     /* bitpos */
         complain_overflow_signed, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
-        "R_BFIN_GOT12",                /* name */
+        "R_BFIN_GOT17M4",      /* name */
         FALSE,                 /* partial_inplace */
         0xffff,                /* src_mask */
         0xffff,                /* dst_mask */
@@ -931,7 +931,7 @@ static reloc_howto_type bfin_howto_table [] =
 
 static reloc_howto_type bfin_gnuext_howto_table [] =
 {
-  HOWTO (R_pltpc,              /* type.  */
+  HOWTO (R_BFIN_PLTPC,         /* type.  */
         0,                     /* rightshift.  */
         1,                     /* size (0 = byte, 1 = short, 2 = long).  */
         16,                    /* bitsize.  */
@@ -939,13 +939,13 @@ static reloc_howto_type bfin_gnuext_howto_table [] =
         0,                     /* bitpos.  */
         complain_overflow_bitfield, /* complain_on_overflow.  */
         bfin_pltpc_reloc,      /* special_function.  */
-        "R_pltpc",             /* name.  */
+        "R_BFIN_PLTPC",        /* name.  */
         FALSE,                 /* partial_inplace.  */
         0xffff,                /* src_mask.  */
         0xffff,                /* dst_mask.  */
         FALSE),                /* pcrel_offset.  */
 
-  HOWTO (R_got,                        /* type.  */
+  HOWTO (R_BFIN_GOT,           /* type.  */
         0,                     /* rightshift.  */
         1,                     /* size (0 = byte, 1 = short, 2 = long).  */
         16,                    /* bitsize.  */
@@ -953,7 +953,7 @@ static reloc_howto_type bfin_gnuext_howto_table [] =
         0,                     /* bitpos.  */
         complain_overflow_bitfield, /* complain_on_overflow.  */
         bfd_elf_generic_reloc, /* special_function.  */
-        "R_got",               /* name.  */
+        "R_BFIN_GOT",          /* name.  */
         FALSE,                 /* partial_inplace.  */
         0x7fff,                /* src_mask.  */
         0x7fff,                /* dst_mask.  */
@@ -998,27 +998,27 @@ struct bfin_reloc_map
 
 static const struct bfin_reloc_map bfin_reloc_map [] =
 {
-  { BFD_RELOC_NONE,                    R_unused0 },
-  { BFD_RELOC_BFIN_5_PCREL,            R_pcrel5m2 },
-  { BFD_RELOC_NONE,                    R_unused1 },
-  { BFD_RELOC_BFIN_10_PCREL,           R_pcrel10 },
-  { BFD_RELOC_BFIN_12_PCREL_JUMP,      R_pcrel12_jump },
-  { BFD_RELOC_BFIN_16_IMM,             R_rimm16 },
-  { BFD_RELOC_BFIN_16_LOW,             R_luimm16 },
-  { BFD_RELOC_BFIN_16_HIGH,            R_huimm16 },
-  { BFD_RELOC_BFIN_12_PCREL_JUMP_S,    R_pcrel12_jump_s },
-  { BFD_RELOC_24_PCREL,                        R_pcrel24 },
-  { BFD_RELOC_24_PCREL,                        R_pcrel24 },
-  { BFD_RELOC_BFIN_24_PCREL_JUMP_L,    R_pcrel24_jump_l },
-  { BFD_RELOC_NONE,                    R_unusedb },
-  { BFD_RELOC_NONE,                    R_unusedc },
-  { BFD_RELOC_BFIN_24_PCREL_CALL_X,    R_pcrel24_call_x },
-  { BFD_RELOC_8,                       R_byte_data },
-  { BFD_RELOC_16,                      R_byte2_data },
-  { BFD_RELOC_32,                      R_byte4_data },
-  { BFD_RELOC_BFIN_11_PCREL,           R_pcrel11 },
-  { BFD_RELOC_BFIN_GOT,                        R_got },
-  { BFD_RELOC_BFIN_PLTPC,              R_pltpc },
+  { BFD_RELOC_NONE,                    R_BFIN_UNUSED0 },
+  { BFD_RELOC_BFIN_5_PCREL,            R_BFIN_PCREL5M2 },
+  { BFD_RELOC_NONE,                    R_BFIN_UNUSED1 },
+  { BFD_RELOC_BFIN_10_PCREL,           R_BFIN_PCREL10 },
+  { BFD_RELOC_BFIN_12_PCREL_JUMP,      R_BFIN_PCREL12_JUMP },
+  { BFD_RELOC_BFIN_16_IMM,             R_BFIN_RIMM16 },
+  { BFD_RELOC_BFIN_16_LOW,             R_BFIN_LUIMM16 },
+  { BFD_RELOC_BFIN_16_HIGH,            R_BFIN_HUIMM16 },
+  { BFD_RELOC_BFIN_12_PCREL_JUMP_S,    R_BFIN_PCREL12_JUMP_S },
+  { BFD_RELOC_24_PCREL,                        R_BFIN_PCREL24 },
+  { BFD_RELOC_24_PCREL,                        R_BFIN_PCREL24 },
+  { BFD_RELOC_BFIN_24_PCREL_JUMP_L,    R_BFIN_PCREL24_JUMP_L },
+  { BFD_RELOC_NONE,                    R_BFIN_UNUSEDB },
+  { BFD_RELOC_NONE,                    R_BFIN_UNUSEDC },
+  { BFD_RELOC_BFIN_24_PCREL_CALL_X,    R_BFIN_PCREL24_CALL_X },
+  { BFD_RELOC_8,                       R_BFIN_BYTE_DATA },
+  { BFD_RELOC_16,                      R_BFIN_BYTE2_DATA },
+  { BFD_RELOC_32,                      R_BFIN_BYTE4_DATA },
+  { BFD_RELOC_BFIN_11_PCREL,           R_BFIN_PCREL11 },
+  { BFD_RELOC_BFIN_GOT,                        R_BFIN_GOT },
+  { BFD_RELOC_BFIN_PLTPC,              R_BFIN_PLTPC },
 
   { BFD_RELOC_BFIN_GOT17M4,      R_BFIN_GOT17M4 },
   { BFD_RELOC_BFIN_GOTHI,      R_BFIN_GOTHI },
@@ -1123,7 +1123,7 @@ bfin_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED,
    bfin local labels begin with L$.  */
 static bfd_boolean
 bfin_is_local_label_name (
-     bfd *abfd ATTRIBUTE_UNUSED,
+     bfd *abfd,
      const char *label)
 {
   if (label[0] == 'L' && label[1] == '$' )
@@ -1131,2087 +1131,2213 @@ bfin_is_local_label_name (
 
   return _bfd_elf_is_local_label_name (abfd, label);
 }
+\f
+/* Look through the relocs for a section during the first phase, and
+   allocate space in the global offset table or procedure linkage
+   table.  */
 
-extern const bfd_target bfd_elf32_bfinfdpic_vec;
-#define IS_FDPIC(bfd) ((bfd)->xvec == &bfd_elf32_bfinfdpic_vec)
-
-/* An extension of the elf hash table data structure, containing some
-   additional Blackfin-specific data.  */
-struct bfinfdpic_elf_link_hash_table
+static bfd_boolean
+bfin_check_relocs (bfd * abfd,
+                  struct bfd_link_info *info,
+                  asection *sec,
+                   const Elf_Internal_Rela *relocs)
 {
-  struct elf_link_hash_table elf;
-
-  /* A pointer to the .got section.  */
+  bfd *dynobj;
+  Elf_Internal_Shdr *symtab_hdr;
+  struct elf_link_hash_entry **sym_hashes;
+  bfd_signed_vma *local_got_refcounts;
+  const Elf_Internal_Rela *rel;
+  const Elf_Internal_Rela *rel_end;
   asection *sgot;
-  /* A pointer to the .rel.got section.  */
-  asection *sgotrel;
-  /* A pointer to the .rofixup section.  */
-  asection *sgotfixup;
-  /* A pointer to the .plt section.  */
-  asection *splt;
-  /* A pointer to the .rel.plt section.  */
-  asection *spltrel;
-  /* GOT base offset.  */
-  bfd_vma got0;
-  /* Location of the first non-lazy PLT entry, i.e., the number of
-     bytes taken by lazy PLT entries.  */
-  bfd_vma plt0;
-  /* A hash table holding information about which symbols were
-     referenced with which PIC-related relocations.  */
-  struct htab *relocs_info;
-};
-
-/* Get the Blackfin ELF linker hash table from a link_info structure.  */
-
-#define bfinfdpic_hash_table(info) \
-  ((struct bfinfdpic_elf_link_hash_table *) ((info)->hash))
-
-#define bfinfdpic_got_section(info) \
-  (bfinfdpic_hash_table (info)->sgot)
-#define bfinfdpic_gotrel_section(info) \
-  (bfinfdpic_hash_table (info)->sgotrel)
-#define bfinfdpic_gotfixup_section(info) \
-  (bfinfdpic_hash_table (info)->sgotfixup)
-#define bfinfdpic_plt_section(info) \
-  (bfinfdpic_hash_table (info)->splt)
-#define bfinfdpic_pltrel_section(info) \
-  (bfinfdpic_hash_table (info)->spltrel)
-#define bfinfdpic_relocs_info(info) \
-  (bfinfdpic_hash_table (info)->relocs_info)
-#define bfinfdpic_got_initial_offset(info) \
-  (bfinfdpic_hash_table (info)->got0)
-#define bfinfdpic_plt_initial_offset(info) \
-  (bfinfdpic_hash_table (info)->plt0)
-
-/* Create a Blackfin ELF linker hash table.  */
+  asection *srelgot;
+  if (info->relocatable)
+    return TRUE;
 
-static struct bfd_link_hash_table *
-bfinfdpic_elf_link_hash_table_create (bfd *abfd)
-{
-  struct bfinfdpic_elf_link_hash_table *ret;
-  bfd_size_type amt = sizeof (struct bfinfdpic_elf_link_hash_table);
+  dynobj = elf_hash_table (info)->dynobj;
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  sym_hashes = elf_sym_hashes (abfd);
+  local_got_refcounts = elf_local_got_refcounts (abfd);
 
-  ret = bfd_zalloc (abfd, amt);
-  if (ret == NULL)
-    return NULL;
+  sgot = NULL;
+  srelgot = NULL;
 
-  if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd,
-                                     _bfd_elf_link_hash_newfunc,
-                                     sizeof (struct elf_link_hash_entry)))
+  rel_end = relocs + sec->reloc_count;
+  for (rel = relocs; rel < rel_end; rel++)
     {
-      free (ret);
-      return NULL;
-    }
+      unsigned long r_symndx;
+      struct elf_link_hash_entry *h;
 
-  return &ret->elf.root;
-}
+      r_symndx = ELF32_R_SYM (rel->r_info);
+      if (r_symndx < symtab_hdr->sh_info)
+       h = NULL;
+      else
+       h = sym_hashes[r_symndx - symtab_hdr->sh_info];
 
-/* Decide whether a reference to a symbol can be resolved locally or
-   not.  If the symbol is protected, we want the local address, but
-   its function descriptor must be assigned by the dynamic linker.  */
-#define BFINFDPIC_SYM_LOCAL(INFO, H) \
-  (_bfd_elf_symbol_refs_local_p ((H), (INFO), 1) \
-   || ! elf_hash_table (INFO)->dynamic_sections_created)
-#define BFINFDPIC_FUNCDESC_LOCAL(INFO, H) \
-  ((H)->dynindx == -1 || ! elf_hash_table (INFO)->dynamic_sections_created)
+      switch (ELF32_R_TYPE (rel->r_info))
+       {
+       /* This relocation describes the C++ object vtable hierarchy.
+           Reconstruct it for later use during GC.  */
+        case R_BFIN_GNU_VTINHERIT:
+          if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
+            return FALSE;
+          break;
 
-/* This structure collects information on what kind of GOT, PLT or
-   function descriptors are required by relocations that reference a
-   certain symbol.  */
-struct bfinfdpic_relocs_info
-{
-  /* The index of the symbol, as stored in the relocation r_info, if
-     we have a local symbol; -1 otherwise.  */
-  long symndx;
-  union
-  {
-    /* The input bfd in which the symbol is defined, if it's a local
-       symbol.  */
-    bfd *abfd;
-    /* If symndx == -1, the hash table entry corresponding to a global
-       symbol (even if it turns out to bind locally, in which case it
-       should ideally be replaced with section's symndx + addend).  */
-    struct elf_link_hash_entry *h;
-  } d;
-  /* The addend of the relocation that references the symbol.  */
-  bfd_vma addend;
+        /* This relocation describes which C++ vtable entries
+           are actually used.  Record for later use during GC.  */
+        case R_BFIN_GNU_VTENTRY:
+          BFD_ASSERT (h != NULL);
+          if (h != NULL
+              && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
+            return FALSE;
+          break;
 
-  /* The fields above are used to identify an entry.  The fields below
-     contain information on how an entry is used and, later on, which
-     locations it was assigned.  */
-  /* The following 2 fields record whether the symbol+addend above was
-     ever referenced with a GOT relocation.  The 17M4 suffix indicates a
-     GOT17M4 relocation; hilo is used for GOTLO/GOTHI pairs.  */
-  unsigned got17m4:1;
-  unsigned gothilo:1;
-  /* Whether a FUNCDESC relocation references symbol+addend.  */
-  unsigned fd:1;
-  /* Whether a FUNCDESC_GOT relocation references symbol+addend.  */
-  unsigned fdgot17m4:1;
-  unsigned fdgothilo:1;
-  /* Whether a FUNCDESC_GOTOFF relocation references symbol+addend.  */
-  unsigned fdgoff17m4:1;
-  unsigned fdgoffhilo:1;
-  /* Whether symbol+addend is referenced with GOTOFF17M4, GOTOFFLO or
-     GOTOFFHI relocations.  The addend doesn't really matter, since we
-     envision that this will only be used to check whether the symbol
-     is mapped to the same segment as the got.  */
-  unsigned gotoff:1;
-  /* Whether symbol+addend is referenced by a LABEL24 relocation.  */
-  unsigned call:1;
-  /* Whether symbol+addend is referenced by a 32 or FUNCDESC_VALUE
-     relocation.  */
-  unsigned sym:1;
-  /* Whether we need a PLT entry for a symbol.  Should be implied by
-     something like:
-     (call && symndx == -1 && ! BFINFDPIC_SYM_LOCAL (info, d.h))  */
-  unsigned plt:1;
-  /* Whether a function descriptor should be created in this link unit
-     for symbol+addend.  Should be implied by something like:
-     (plt || fdgotoff17m4 || fdgotofflohi
-      || ((fd || fdgot17m4 || fdgothilo)
-          && (symndx != -1 || BFINFDPIC_FUNCDESC_LOCAL (info, d.h))))  */
-  unsigned privfd:1;
-  /* Whether a lazy PLT entry is needed for this symbol+addend.
-     Should be implied by something like:
-     (privfd && symndx == -1 && ! BFINFDPIC_SYM_LOCAL (info, d.h)
-      && ! (info->flags & DF_BIND_NOW))  */
-  unsigned lazyplt:1;
-  /* Whether we've already emitted GOT relocations and PLT entries as
-     needed for this symbol.  */
-  unsigned done:1;
+       case R_BFIN_GOT:
+         if (h != NULL
+             && strcmp (h->root.root.string, "__GLOBAL_OFFSET_TABLE_") == 0)
+           break;
+         /* Fall through.  */
 
-  /* The number of R_byte4_data, R_BFIN_FUNCDESC and R_BFIN_FUNCDESC_VALUE
-     relocations referencing the symbol.  */
-  unsigned relocs32, relocsfd, relocsfdv;
+         if (dynobj == NULL)
+           {
+             /* Create the .got section.  */
+             elf_hash_table (info)->dynobj = dynobj = abfd;
+             if (!_bfd_elf_create_got_section (dynobj, info))
+               return FALSE;
+           }
 
-  /* The number of .rofixups entries and dynamic relocations allocated
-     for this symbol, minus any that might have already been used.  */
-  unsigned fixups, dynrelocs;
+         if (sgot == NULL)
+           {
+             sgot = bfd_get_section_by_name (dynobj, ".got");
+             BFD_ASSERT (sgot != NULL);
+           }
 
-  /* The offsets of the GOT entries assigned to symbol+addend, to the
-     function descriptor's address, and to a function descriptor,
-     respectively.  Should be zero if unassigned.  The offsets are
-     counted from the value that will be assigned to the PIC register,
-     not from the beginning of the .got section.  */
-  bfd_signed_vma got_entry, fdgot_entry, fd_entry;
-  /* The offsets of the PLT entries assigned to symbol+addend,
-     non-lazy and lazy, respectively.  If unassigned, should be
-     (bfd_vma)-1.  */
-  bfd_vma plt_entry, lzplt_entry;
-};
+         if (srelgot == NULL && (h != NULL || info->shared))
+           {
+             srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+             if (srelgot == NULL)
+               {
+                 flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
+                                   | SEC_IN_MEMORY | SEC_LINKER_CREATED
+                                   | SEC_READONLY);
+                 srelgot = bfd_make_section_with_flags (dynobj, ".rela.got",
+                                                        flags);
+                 if (srelgot == NULL
+                     || !bfd_set_section_alignment (dynobj, srelgot, 2))
+                   return FALSE;
+               }
+           }
 
-/* Compute a hash with the key fields of an bfinfdpic_relocs_info entry.  */
-static hashval_t
-bfinfdpic_relocs_info_hash (const void *entry_)
-{
-  const struct bfinfdpic_relocs_info *entry = entry_;
+         if (h != NULL)
+           {
+             if (h->got.refcount == 0)
+               {
+                 /* Make sure this symbol is output as a dynamic symbol.  */
+                 if (h->dynindx == -1 && !h->forced_local)
+                   {
+                     if (!bfd_elf_link_record_dynamic_symbol (info, h))
+                       return FALSE;
+                   }
 
-  return (entry->symndx == -1
-         ? (long) entry->d.h->root.root.hash
-         : entry->symndx + (long) entry->d.abfd->id * 257) + entry->addend;
-}
+                 /* Allocate space in the .got section.  */
+                 sgot->size += 4;
+                 /* Allocate relocation space.  */
+                 srelgot->size += sizeof (Elf32_External_Rela);
+               }
+             h->got.refcount++;
+           }
+         else
+           {
+             /* This is a global offset table entry for a local symbol.  */
+             if (local_got_refcounts == NULL)
+               {
+                 bfd_size_type size;
 
-/* Test whether the key fields of two bfinfdpic_relocs_info entries are
-   identical.  */
-static int
-bfinfdpic_relocs_info_eq (const void *entry1, const void *entry2)
-{
-  const struct bfinfdpic_relocs_info *e1 = entry1;
-  const struct bfinfdpic_relocs_info *e2 = entry2;
+                 size = symtab_hdr->sh_info;
+                 size *= sizeof (bfd_signed_vma);
+                 local_got_refcounts = ((bfd_signed_vma *)
+                                        bfd_zalloc (abfd, size));
+                 if (local_got_refcounts == NULL)
+                   return FALSE;
+                 elf_local_got_refcounts (abfd) = local_got_refcounts;
+               }
+             if (local_got_refcounts[r_symndx] == 0)
+               {
+                 sgot->size += 4;
+                 if (info->shared)
+                   {
+                     /* If we are generating a shared object, we need to
+                        output a R_68K_RELATIVE reloc so that the dynamic
+                        linker can adjust this GOT entry.  */
+                     srelgot->size += sizeof (Elf32_External_Rela);
+                   }
+               }
+             local_got_refcounts[r_symndx]++;
+           }
+         break;
 
-  return e1->symndx == e2->symndx && e1->addend == e2->addend
-    && (e1->symndx == -1 ? e1->d.h == e2->d.h : e1->d.abfd == e2->d.abfd);
+       default:
+         break;
+       }
+    }
+
+  return TRUE;
 }
 
-/* Find or create an entry in a hash table HT that matches the key
-   fields of the given ENTRY.  If it's not found, memory for a new
-   entry is allocated in ABFD's obstack.  */
-static struct bfinfdpic_relocs_info *
-bfinfdpic_relocs_info_find (struct htab *ht,
-                          bfd *abfd,
-                          const struct bfinfdpic_relocs_info *entry,
-                          enum insert_option insert)
+static enum elf_reloc_type_class
+elf32_bfin_reloc_type_class (const Elf_Internal_Rela * rela)
+{
+  switch ((int) ELF32_R_TYPE (rela->r_info))
+    {
+    default:
+      return reloc_class_normal;
+    }
+}
+\f
+static bfd_reloc_status_type
+bfin_final_link_relocate (Elf_Internal_Rela *rel, reloc_howto_type *howto,
+                         bfd *input_bfd, asection *input_section,
+                         bfd_byte *contents, bfd_vma address,
+                         bfd_vma value, bfd_vma addend)
 {
-  struct bfinfdpic_relocs_info **loc =
-    (struct bfinfdpic_relocs_info **) htab_find_slot (ht, entry, insert);
+  int r_type = ELF32_R_TYPE (rel->r_info);
 
-  if (! loc)
-    return NULL;
+  if (r_type == R_BFIN_PCREL24 || r_type == R_BFIN_PCREL24_JUMP_L)
+    {
+      bfd_reloc_status_type r = bfd_reloc_ok;
+      bfd_vma x;
 
-  if (*loc)
-    return *loc;
+      if (address > bfd_get_section_limit (input_bfd, input_section))
+       return bfd_reloc_outofrange;
 
-  *loc = bfd_zalloc (abfd, sizeof (**loc));
+      value += addend;
 
-  if (! *loc)
-    return *loc;
+      /* Perform usual pc-relative correction.  */
+      value -= input_section->output_section->vma + input_section->output_offset;
+      value -= address;
 
-  (*loc)->symndx = entry->symndx;
-  (*loc)->d = entry->d;
-  (*loc)->addend = entry->addend;
-  (*loc)->plt_entry = (bfd_vma)-1;
-  (*loc)->lzplt_entry = (bfd_vma)-1;
+      /* We are getting reloc_entry->address 2 byte off from
+        the start of instruction. Assuming absolute postion
+        of the reloc data. But, following code had been written assuming
+        reloc address is starting at begining of instruction.
+        To compensate that I have increased the value of
+        relocation by 1 (effectively 2) and used the addr -2 instead of addr.  */
 
-  return *loc;
-}
+      value += 2;
+      address -= 2;
 
-/* Obtain the address of the entry in HT associated with H's symbol +
-   addend, creating a new entry if none existed.  ABFD is only used
-   for memory allocation purposes.  */
-inline static struct bfinfdpic_relocs_info *
-bfinfdpic_relocs_info_for_global (struct htab *ht,
-                                bfd *abfd,
-                                struct elf_link_hash_entry *h,
-                                bfd_vma addend,
-                                enum insert_option insert)
-{
-  struct bfinfdpic_relocs_info entry;
+      if ((value & 0xFF000000) != 0
+         && (value & 0xFF000000) != 0xFF000000)
+       r = bfd_reloc_overflow;
 
-  entry.symndx = -1;
-  entry.d.h = h;
-  entry.addend = addend;
+      value >>= 1;
 
-  return bfinfdpic_relocs_info_find (ht, abfd, &entry, insert);
-}
+      x = bfd_get_16 (input_bfd, contents + address);
+      x = (x & 0xff00) | ((value >> 16) & 0xff);
+      bfd_put_16 (input_bfd, x, contents + address);
 
-/* Obtain the address of the entry in HT associated with the SYMNDXth
-   local symbol of the input bfd ABFD, plus the addend, creating a new
-   entry if none existed.  */
-inline static struct bfinfdpic_relocs_info *
-bfinfdpic_relocs_info_for_local (struct htab *ht,
-                               bfd *abfd,
-                               long symndx,
-                               bfd_vma addend,
-                               enum insert_option insert)
-{
-  struct bfinfdpic_relocs_info entry;
+      x = bfd_get_16 (input_bfd, contents + address + 2);
+      x = value & 0xFFFF;
+      bfd_put_16 (input_bfd, x, contents + address + 2);
+      return r;
+    }
 
-  entry.symndx = symndx;
-  entry.d.abfd = abfd;
-  entry.addend = addend;
+  return _bfd_final_link_relocate (howto, input_bfd, input_section, contents,
+                                  rel->r_offset, value, addend);
 
-  return bfinfdpic_relocs_info_find (ht, abfd, &entry, insert);
 }
 
-/* Merge fields set by check_relocs() of two entries that end up being
-   mapped to the same (presumably global) symbol.  */
-
-inline static void
-bfinfdpic_pic_merge_early_relocs_info (struct bfinfdpic_relocs_info *e2,
-                                     struct bfinfdpic_relocs_info const *e1)
+static bfd_boolean
+bfin_relocate_section (bfd * output_bfd,
+                      struct bfd_link_info *info,
+                      bfd * input_bfd,
+                      asection * input_section,
+                      bfd_byte * contents,
+                      Elf_Internal_Rela * relocs,
+                      Elf_Internal_Sym * local_syms,
+                      asection ** local_sections)
 {
-  e2->got17m4 |= e1->got17m4;
-  e2->gothilo |= e1->gothilo;
-  e2->fd |= e1->fd;
-  e2->fdgot17m4 |= e1->fdgot17m4;
-  e2->fdgothilo |= e1->fdgothilo;
-  e2->fdgoff17m4 |= e1->fdgoff17m4;
-  e2->fdgoffhilo |= e1->fdgoffhilo;
-  e2->gotoff |= e1->gotoff;
-  e2->call |= e1->call;
-  e2->sym |= e1->sym;
-}
+  bfd *dynobj;
+  Elf_Internal_Shdr *symtab_hdr;
+  struct elf_link_hash_entry **sym_hashes;
+  bfd_vma *local_got_offsets;
+  asection *sgot;
+  Elf_Internal_Rela *rel;
+  Elf_Internal_Rela *relend;
+  int i = 0;
 
-/* Every block of 65535 lazy PLT entries shares a single call to the
-   resolver, inserted in the 32768th lazy PLT entry (i.e., entry #
-   32767, counting from 0).  All other lazy PLT entries branch to it
-   in a single instruction.  */
+  dynobj = elf_hash_table (info)->dynobj;
+  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+  sym_hashes = elf_sym_hashes (input_bfd);
+  local_got_offsets = elf_local_got_offsets (input_bfd);
 
-#define LZPLT_RESOLVER_EXTRA 10
-#define LZPLT_NORMAL_SIZE 6
-#define LZPLT_ENTRIES 1362
+  sgot = NULL;
 
-#define BFINFDPIC_LZPLT_BLOCK_SIZE ((bfd_vma) LZPLT_NORMAL_SIZE * LZPLT_ENTRIES + LZPLT_RESOLVER_EXTRA)
-#define BFINFDPIC_LZPLT_RESOLV_LOC (LZPLT_NORMAL_SIZE * LZPLT_ENTRIES / 2)
+  rel = relocs;
+  relend = relocs + input_section->reloc_count;
+  for (; rel < relend; rel++, i++)
+    {
+      int r_type;
+      reloc_howto_type *howto;
+      unsigned long r_symndx;
+      struct elf_link_hash_entry *h;
+      Elf_Internal_Sym *sym;
+      asection *sec;
+      bfd_vma relocation = 0;
+      bfd_boolean unresolved_reloc;
+      bfd_reloc_status_type r;
+      bfd_vma address;
 
-/* Add a dynamic relocation to the SRELOC section.  */
+      r_type = ELF32_R_TYPE (rel->r_info);
+      if (r_type < 0 || r_type >= 243)
+       {
+         bfd_set_error (bfd_error_bad_value);
+         return FALSE;
+       }
 
-inline static bfd_vma
-_bfinfdpic_add_dyn_reloc (bfd *output_bfd, asection *sreloc, bfd_vma offset,
-                        int reloc_type, long dynindx, bfd_vma addend,
-                        struct bfinfdpic_relocs_info *entry)
-{
-  Elf_Internal_Rela outrel;
-  bfd_vma reloc_offset;
+      if (r_type == R_BFIN_GNU_VTENTRY
+          || r_type == R_BFIN_GNU_VTINHERIT)
+       continue;
 
-  outrel.r_offset = offset;
-  outrel.r_info = ELF32_R_INFO (dynindx, reloc_type);
-  outrel.r_addend = addend;
+      howto = bfin_reloc_type_lookup (input_bfd, r_type);
+      if (howto == NULL)
+       {
+         bfd_set_error (bfd_error_bad_value);
+         return FALSE;
+       }
+      r_symndx = ELF32_R_SYM (rel->r_info);
 
-  reloc_offset = sreloc->reloc_count * sizeof (Elf32_External_Rel);
-  BFD_ASSERT (reloc_offset < sreloc->size);
-  bfd_elf32_swap_reloc_out (output_bfd, &outrel,
-                           sreloc->contents + reloc_offset);
-  sreloc->reloc_count++;
+      h = NULL;
+      sym = NULL;
+      sec = NULL;
+      unresolved_reloc = FALSE;
 
-  /* If the entry's index is zero, this relocation was probably to a
-     linkonce section that got discarded.  We reserved a dynamic
-     relocation, but it was for another entry than the one we got at
-     the time of emitting the relocation.  Unfortunately there's no
-     simple way for us to catch this situation, since the relocation
-     is cleared right before calling relocate_section, at which point
-     we no longer know what the relocation used to point to.  */
-  if (entry->symndx)
-    {
-      BFD_ASSERT (entry->dynrelocs > 0);
-      entry->dynrelocs--;
-    }
+      if (r_symndx < symtab_hdr->sh_info)
+       {
+         sym = local_syms + r_symndx;
+         sec = local_sections[r_symndx];
+         relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
+       }
+      else
+       {
+         bfd_boolean warned;
 
-  return reloc_offset;
-}
+         RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
+                                  r_symndx, symtab_hdr, sym_hashes,
+                                  h, sec, relocation,
+                                  unresolved_reloc, warned);
+       }
 
-/* Add a fixup to the ROFIXUP section.  */
+      if (sec != NULL && elf_discarded_section (sec))
+       {
+         /* For relocs against symbols from removed linkonce sections,
+            or sections discarded by a linker script, we just want the
+            section contents zeroed.  Avoid any special processing.  */
+         _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
+         rel->r_info = 0;
+         rel->r_addend = 0;
+         continue;
+       }
 
-static bfd_vma
-_bfinfdpic_add_rofixup (bfd *output_bfd, asection *rofixup, bfd_vma offset,
-                      struct bfinfdpic_relocs_info *entry)
-{
-  bfd_vma fixup_offset;
+      if (info->relocatable)
+       continue;
 
-  if (rofixup->flags & SEC_EXCLUDE)
-    return -1;
+      address = rel->r_offset;
 
-  fixup_offset = rofixup->reloc_count * 4;
-  if (rofixup->contents)
-    {
-      BFD_ASSERT (fixup_offset < rofixup->size);
-      bfd_put_32 (output_bfd, offset, rofixup->contents + fixup_offset);
-    }
-  rofixup->reloc_count++;
+      /* Then, process normally.  */
+      switch (r_type)
+       {
+       case R_BFIN_GNU_VTINHERIT:
+       case R_BFIN_GNU_VTENTRY:
+         return bfd_reloc_ok;
 
-  if (entry && entry->symndx)
-    {
-      /* See discussion about symndx == 0 in _bfinfdpic_add_dyn_reloc
-        above.  */
-      BFD_ASSERT (entry->fixups > 0);
-      entry->fixups--;
-    }
+       case R_BFIN_GOT:
+         /* Relocation is to the address of the entry for this symbol
+            in the global offset table.  */
+         if (h != NULL
+             && strcmp (h->root.root.string, "__GLOBAL_OFFSET_TABLE_") == 0)
+           goto do_default;
+         /* Fall through.  */
+         /* Relocation is the offset of the entry for this symbol in
+            the global offset table.  */
 
-  return fixup_offset;
-}
+         {
+           bfd_vma off;
 
-/* Find the segment number in which OSEC, and output section, is
-   located.  */
+         if (dynobj == NULL)
+           {
+             /* Create the .got section.  */
+             elf_hash_table (info)->dynobj = dynobj = output_bfd;
+             if (!_bfd_elf_create_got_section (dynobj, info))
+               return FALSE;
+           }
 
-static unsigned
-_bfinfdpic_osec_to_segment (bfd *output_bfd, asection *osec)
-{
-  struct elf_segment_map *m;
-  Elf_Internal_Phdr *p;
+           if (sgot == NULL)
+             {
+               sgot = bfd_get_section_by_name (dynobj, ".got");
+               BFD_ASSERT (sgot != NULL);
+             }
 
-  /* Find the segment that contains the output_section.  */
-  for (m = elf_tdata (output_bfd)->segment_map,
-        p = elf_tdata (output_bfd)->phdr;
-       m != NULL;
-       m = m->next, p++)
-    {
-      int i;
+           if (h != NULL)
+             {
+               bfd_boolean dyn;
 
-      for (i = m->count - 1; i >= 0; i--)
-       if (m->sections[i] == osec)
-         break;
+               off = h->got.offset;
+               BFD_ASSERT (off != (bfd_vma) - 1);
+               dyn = elf_hash_table (info)->dynamic_sections_created;
 
-      if (i >= 0)
-       break;
-    }
+               if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
+                   || (info->shared
+                       && (info->symbolic
+                           || h->dynindx == -1
+                           || h->forced_local)
+                       && h->def_regular))
+                 {
+                   /* This is actually a static link, or it is a
+                      -Bsymbolic link and the symbol is defined
+                      locally, or the symbol was forced to be local
+                      because of a version file..  We must initialize
+                      this entry in the global offset table.  Since
+                      the offset must always be a multiple of 4, we
+                      use the least significant bit to record whether
+                      we have initialized it already.
 
-  return p - elf_tdata (output_bfd)->phdr;
-}
+                      When doing a dynamic link, we create a .rela.got
+                      relocation entry to initialize the value.  This
+                      is done in the finish_dynamic_symbol routine.  */
+                   if ((off & 1) != 0)
+                     off &= ~1;
+                   else
+                     {
+                       bfd_put_32 (output_bfd, relocation,
+                                   sgot->contents + off);
+                       h->got.offset |= 1;
+                     }
+                 }
+               else
+                 unresolved_reloc = FALSE;
+             }
+           else
+             {
+               BFD_ASSERT (local_got_offsets != NULL);
+               off = local_got_offsets[r_symndx];
+               BFD_ASSERT (off != (bfd_vma) - 1);
 
-inline static bfd_boolean
-_bfinfdpic_osec_readonly_p (bfd *output_bfd, asection *osec)
-{
-  unsigned seg = _bfinfdpic_osec_to_segment (output_bfd, osec);
+               /* The offset must always be a multiple of 4.  We use
+                  the least significant bit to record whether we have
+                  already generated the necessary reloc.  */
+               if ((off & 1) != 0)
+                 off &= ~1;
+               else
+                 {
+                   bfd_put_32 (output_bfd, relocation, sgot->contents + off);
 
-  return ! (elf_tdata (output_bfd)->phdr[seg].p_flags & PF_W);
-}
+                   if (info->shared)
+                     {
+                       asection *s;
+                       Elf_Internal_Rela outrel;
+                       bfd_byte *loc;
 
-/* Generate relocations for GOT entries, function descriptors, and
-   code for PLT and lazy PLT entries.  */
+                       s = bfd_get_section_by_name (dynobj, ".rela.got");
+                       BFD_ASSERT (s != NULL);
 
-inline static bfd_boolean
-_bfinfdpic_emit_got_relocs_plt_entries (struct bfinfdpic_relocs_info *entry,
-                                       bfd *output_bfd,
-                                       struct bfd_link_info *info,
-                                       asection *sec,
-                                       Elf_Internal_Sym *sym,
-                                       bfd_vma addend)
+                       outrel.r_offset = (sgot->output_section->vma
+                                          + sgot->output_offset + off);
+                       outrel.r_info =
+                         ELF32_R_INFO (0, R_BFIN_PCREL24);
+                       outrel.r_addend = relocation;
+                       loc = s->contents;
+                       loc +=
+                         s->reloc_count++ * sizeof (Elf32_External_Rela);
+                       bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
+                     }
 
-{
-  bfd_vma fd_lazy_rel_offset = (bfd_vma)-1;
-  int dynindx = -1;
+                   local_got_offsets[r_symndx] |= 1;
+                 }
+             }
 
-  if (entry->done)
-    return TRUE;
-  entry->done = 1;
+           relocation = sgot->output_offset + off;
+           rel->r_addend = 0;
+            /* bfin : preg = [preg + 17bitdiv4offset] relocation is div by 4.  */
+            relocation /= 4;
+         }
+         goto do_default;
 
-  if (entry->got_entry || entry->fdgot_entry || entry->fd_entry)
-    {
-      /* If the symbol is dynamic, consider it for dynamic
-        relocations, otherwise decay to section + offset.  */
-      if (entry->symndx == -1 && entry->d.h->dynindx != -1)
-       dynindx = entry->d.h->dynindx;
-      else
-       {
-         if (sec->output_section
-             && ! bfd_is_abs_section (sec->output_section)
-             && ! bfd_is_und_section (sec->output_section))
-           dynindx = elf_section_data (sec->output_section)->dynindx;
-         else
-           dynindx = 0;
-       }
-    }
+       default:
+       do_default:
+         r = bfin_final_link_relocate (rel, howto, input_bfd, input_section,
+                                       contents, address,
+                                       relocation, rel->r_addend);
 
-  /* Generate relocation for GOT entry pointing to the symbol.  */
-  if (entry->got_entry)
-    {
-      int idx = dynindx;
-      bfd_vma ad = addend;
+         break;
+       }
 
-      /* If the symbol is dynamic but binds locally, use
-        section+offset.  */
-      if (sec && (entry->symndx != -1
-                 || BFINFDPIC_SYM_LOCAL (info, entry->d.h)))
+      /* Dynamic relocs are not propagated for SEC_DEBUGGING sections
+         because such sections are not SEC_ALLOC and thus ld.so will
+         not process them.  */
+      if (unresolved_reloc
+         && !((input_section->flags & SEC_DEBUGGING) != 0 && h->def_dynamic))
        {
-         if (entry->symndx == -1)
-           ad += entry->d.h->root.u.def.value;
-         else
-           ad += sym->st_value;
-         ad += sec->output_offset;
-         if (sec->output_section && elf_section_data (sec->output_section))
-           idx = elf_section_data (sec->output_section)->dynindx;
-         else
-           idx = 0;
+         (*_bfd_error_handler)
+           (_("%B(%A+0x%lx): unresolvable relocation against symbol `%s'"),
+            input_bfd,
+            input_section, (long) rel->r_offset, h->root.root.string);
+         return FALSE;
        }
 
-      /* If we're linking an executable at a fixed address, we can
-        omit the dynamic relocation as long as the symbol is local to
-        this module.  */
-      if (info->executable && !info->pie
-         && (entry->symndx != -1
-             || BFINFDPIC_SYM_LOCAL (info, entry->d.h)))
+      if (r != bfd_reloc_ok)
        {
-         if (sec)
-           ad += sec->output_section->vma;
-         if (entry->symndx != -1
-             || entry->d.h->root.type != bfd_link_hash_undefweak)
-           _bfinfdpic_add_rofixup (output_bfd,
-                                  bfinfdpic_gotfixup_section (info),
-                                  bfinfdpic_got_section (info)->output_section
-                                  ->vma
-                                  + bfinfdpic_got_section (info)->output_offset
-                                  + bfinfdpic_got_initial_offset (info)
-                                  + entry->got_entry, entry);
-       }
-      else
-       _bfinfdpic_add_dyn_reloc (output_bfd, bfinfdpic_gotrel_section (info),
-                                _bfd_elf_section_offset
-                                (output_bfd, info,
-                                 bfinfdpic_got_section (info),
-                                 bfinfdpic_got_initial_offset (info)
-                                 + entry->got_entry)
-                                + bfinfdpic_got_section (info)
-                                ->output_section->vma
-                                + bfinfdpic_got_section (info)->output_offset,
-                                R_byte4_data, idx, ad, entry);
+         const char *name;
 
-      bfd_put_32 (output_bfd, ad,
-                 bfinfdpic_got_section (info)->contents
-                 + bfinfdpic_got_initial_offset (info)
-                 + entry->got_entry);
+         if (h != NULL)
+           name = h->root.root.string;
+         else
+           {
+             name = bfd_elf_string_from_elf_section (input_bfd,
+                                                     symtab_hdr->sh_link,
+                                                     sym->st_name);
+             if (name == NULL)
+               return FALSE;
+             if (*name == '\0')
+               name = bfd_section_name (input_bfd, sec);
+           }
+
+         if (r == bfd_reloc_overflow)
+           {
+             if (!(info->callbacks->reloc_overflow
+                   (info, (h ? &h->root : NULL), name, howto->name,
+                    (bfd_vma) 0, input_bfd, input_section, rel->r_offset)))
+               return FALSE;
+           }
+         else
+           {
+             (*_bfd_error_handler)
+               (_("%B(%A+0x%lx): reloc against `%s': error %d"),
+                input_bfd, input_section,
+                (long) rel->r_offset, name, (int) r);
+             return FALSE;
+           }
+       }
     }
 
-  /* Generate relocation for GOT entry pointing to a canonical
-     function descriptor.  */
-  if (entry->fdgot_entry)
-    {
-      int reloc, idx;
-      bfd_vma ad = 0;
+  return TRUE;
+}
 
-      if (! (entry->symndx == -1
-            && entry->d.h->root.type == bfd_link_hash_undefweak
-            && BFINFDPIC_SYM_LOCAL (info, entry->d.h)))
-       {
-         /* If the symbol is dynamic and there may be dynamic symbol
-            resolution because we are, or are linked with, a shared
-            library, emit a FUNCDESC relocation such that the dynamic
-            linker will allocate the function descriptor.  If the
-            symbol needs a non-local function descriptor but binds
-            locally (e.g., its visibility is protected, emit a
-            dynamic relocation decayed to section+offset.  */
-         if (entry->symndx == -1
-             && ! BFINFDPIC_FUNCDESC_LOCAL (info, entry->d.h)
-             && BFINFDPIC_SYM_LOCAL (info, entry->d.h)
-             && !(info->executable && !info->pie))
-           {
-             reloc = R_BFIN_FUNCDESC;
-             idx = elf_section_data (entry->d.h->root.u.def.section
-                                     ->output_section)->dynindx;
-             ad = entry->d.h->root.u.def.section->output_offset
-               + entry->d.h->root.u.def.value;
-           }
-         else if (entry->symndx == -1
-                  && ! BFINFDPIC_FUNCDESC_LOCAL (info, entry->d.h))
-           {
-             reloc = R_BFIN_FUNCDESC;
-             idx = dynindx;
-             ad = addend;
-             if (ad)
-               return FALSE;
-           }
-         else
-           {
-             /* Otherwise, we know we have a private function descriptor,
-                so reference it directly.  */
-             if (elf_hash_table (info)->dynamic_sections_created)
-               BFD_ASSERT (entry->privfd);
-             reloc = R_byte4_data;
-             idx = elf_section_data (bfinfdpic_got_section (info)
-                                     ->output_section)->dynindx;
-             ad = bfinfdpic_got_section (info)->output_offset
-               + bfinfdpic_got_initial_offset (info) + entry->fd_entry;
-           }
+static asection *
+bfin_gc_mark_hook (asection * sec,
+                  struct bfd_link_info *info,
+                  Elf_Internal_Rela * rel,
+                  struct elf_link_hash_entry *h,
+                   Elf_Internal_Sym * sym)
+{
+  if (h != NULL)
+    switch (ELF32_R_TYPE (rel->r_info))
+      {
+      case R_BFIN_GNU_VTINHERIT:
+      case R_BFIN_GNU_VTENTRY:
+       return NULL;
+      }
 
-         /* If there is room for dynamic symbol resolution, emit the
-            dynamic relocation.  However, if we're linking an
-            executable at a fixed location, we won't have emitted a
-            dynamic symbol entry for the got section, so idx will be
-            zero, which means we can and should compute the address
-            of the private descriptor ourselves.  */
-         if (info->executable && !info->pie
-             && (entry->symndx != -1
-                 || BFINFDPIC_FUNCDESC_LOCAL (info, entry->d.h)))
-           {
-             ad += bfinfdpic_got_section (info)->output_section->vma;
-             _bfinfdpic_add_rofixup (output_bfd,
-                                    bfinfdpic_gotfixup_section (info),
-                                    bfinfdpic_got_section (info)
-                                    ->output_section->vma
-                                    + bfinfdpic_got_section (info)
-                                    ->output_offset
-                                    + bfinfdpic_got_initial_offset (info)
-                                    + entry->fdgot_entry, entry);
-           }
-         else
-           _bfinfdpic_add_dyn_reloc (output_bfd,
-                                    bfinfdpic_gotrel_section (info),
-                                    _bfd_elf_section_offset
-                                    (output_bfd, info,
-                                     bfinfdpic_got_section (info),
-                                     bfinfdpic_got_initial_offset (info)
-                                     + entry->fdgot_entry)
-                                    + bfinfdpic_got_section (info)
-                                    ->output_section->vma
-                                    + bfinfdpic_got_section (info)
-                                    ->output_offset,
-                                    reloc, idx, ad, entry);
-       }
+  return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
+}
 
-      bfd_put_32 (output_bfd, ad,
-                 bfinfdpic_got_section (info)->contents
-                 + bfinfdpic_got_initial_offset (info)
-                 + entry->fdgot_entry);
-    }
+/* Update the got entry reference counts for the section being removed.  */
 
-  /* Generate relocation to fill in a private function descriptor in
-     the GOT.  */
-  if (entry->fd_entry)
-    {
-      int idx = dynindx;
-      bfd_vma ad = addend;
-      bfd_vma ofst;
-      long lowword, highword;
+static bfd_boolean
+bfin_gc_sweep_hook (bfd * abfd,
+                   struct bfd_link_info *info,
+                   asection * sec,
+                    const Elf_Internal_Rela * relocs)
+{
+  Elf_Internal_Shdr *symtab_hdr;
+  struct elf_link_hash_entry **sym_hashes;
+  bfd_signed_vma *local_got_refcounts;
+  const Elf_Internal_Rela *rel, *relend;
+  bfd *dynobj;
+  asection *sgot;
+  asection *srelgot;
 
-      /* If the symbol is dynamic but binds locally, use
-        section+offset.  */
-      if (sec && (entry->symndx != -1
-                 || BFINFDPIC_SYM_LOCAL (info, entry->d.h)))
-       {
-         if (entry->symndx == -1)
-           ad += entry->d.h->root.u.def.value;
-         else
-           ad += sym->st_value;
-         ad += sec->output_offset;
-         if (sec->output_section && elf_section_data (sec->output_section))
-           idx = elf_section_data (sec->output_section)->dynindx;
-         else
-           idx = 0;
-       }
+  dynobj = elf_hash_table (info)->dynobj;
+  if (dynobj == NULL)
+    return TRUE;
 
-      /* If we're linking an executable at a fixed address, we can
-        omit the dynamic relocation as long as the symbol is local to
-        this module.  */
-      if (info->executable && !info->pie
-         && (entry->symndx != -1 || BFINFDPIC_SYM_LOCAL (info, entry->d.h)))
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  sym_hashes = elf_sym_hashes (abfd);
+  local_got_refcounts = elf_local_got_refcounts (abfd);
+
+  sgot = bfd_get_section_by_name (dynobj, ".got");
+  srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+
+  relend = relocs + sec->reloc_count;
+  for (rel = relocs; rel < relend; rel++)
+    {
+      unsigned long r_symndx;
+      struct elf_link_hash_entry *h;
+
+      switch (ELF32_R_TYPE (rel->r_info))
        {
-         if (sec)
-           ad += sec->output_section->vma;
-         ofst = 0;
-         if (entry->symndx != -1
-             || entry->d.h->root.type != bfd_link_hash_undefweak)
+       case R_BFIN_GOT:
+         r_symndx = ELF32_R_SYM (rel->r_info);
+         if (r_symndx >= symtab_hdr->sh_info)
            {
-             _bfinfdpic_add_rofixup (output_bfd,
-                                    bfinfdpic_gotfixup_section (info),
-                                    bfinfdpic_got_section (info)
-                                    ->output_section->vma
-                                    + bfinfdpic_got_section (info)
-                                    ->output_offset
-                                    + bfinfdpic_got_initial_offset (info)
-                                    + entry->fd_entry, entry);
-             _bfinfdpic_add_rofixup (output_bfd,
-                                    bfinfdpic_gotfixup_section (info),
-                                    bfinfdpic_got_section (info)
-                                    ->output_section->vma
-                                    + bfinfdpic_got_section (info)
-                                    ->output_offset
-                                    + bfinfdpic_got_initial_offset (info)
-                                    + entry->fd_entry + 4, entry);
+             h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+             if (h->got.refcount > 0)
+               {
+                 --h->got.refcount;
+                 if (h->got.refcount == 0)
+                   {
+                     /* We don't need the .got entry any more.  */
+                     sgot->size -= 4;
+                     srelgot->size -= sizeof (Elf32_External_Rela);
+                   }
+               }
            }
+         else if (local_got_refcounts != NULL)
+           {
+             if (local_got_refcounts[r_symndx] > 0)
+               {
+                 --local_got_refcounts[r_symndx];
+                 if (local_got_refcounts[r_symndx] == 0)
+                   {
+                     /* We don't need the .got entry any more.  */
+                     sgot->size -= 4;
+                     if (info->shared)
+                       srelgot->size -= sizeof (Elf32_External_Rela);
+                   }
+               }
+           }
+         break;
+       default:
+         break;
        }
-      else
-       {
-         ofst
-           = _bfinfdpic_add_dyn_reloc (output_bfd,
-                                       entry->lazyplt
-                                       ? bfinfdpic_pltrel_section (info)
-                                       : bfinfdpic_gotrel_section (info),
-                                       _bfd_elf_section_offset
-                                       (output_bfd, info,
-                                        bfinfdpic_got_section (info),
-                                        bfinfdpic_got_initial_offset (info)
-                                        + entry->fd_entry)
-                                       + bfinfdpic_got_section (info)
-                                       ->output_section->vma
-                                       + bfinfdpic_got_section (info)
-                                       ->output_offset,
-                                       R_BFIN_FUNCDESC_VALUE, idx, ad, entry);
-       }
+    }
+  return TRUE;
+}
+\f
+extern const bfd_target bfd_elf32_bfinfdpic_vec;
+#define IS_FDPIC(bfd) ((bfd)->xvec == &bfd_elf32_bfinfdpic_vec)
 
-      /* If we've omitted the dynamic relocation, just emit the fixed
-        addresses of the symbol and of the local GOT base offset.  */
-      if (info->executable && !info->pie && sec && sec->output_section)
-       {
-         lowword = ad;
-         highword = bfinfdpic_got_section (info)->output_section->vma
-           + bfinfdpic_got_section (info)->output_offset
-           + bfinfdpic_got_initial_offset (info);
-       }
-      else if (entry->lazyplt)
-       {
-         if (ad)
-           return FALSE;
+/* An extension of the elf hash table data structure, containing some
+   additional Blackfin-specific data.  */
+struct bfinfdpic_elf_link_hash_table
+{
+  struct elf_link_hash_table elf;
 
-         fd_lazy_rel_offset = ofst;
-
-         /* A function descriptor used for lazy or local resolving is
-            initialized such that its high word contains the output
-            section index in which the PLT entries are located, and
-            the low word contains the address of the lazy PLT entry
-            entry point, that must be within the memory region
-            assigned to that section.  */
-         lowword = entry->lzplt_entry + 4
-           + bfinfdpic_plt_section (info)->output_offset
-           + bfinfdpic_plt_section (info)->output_section->vma;
-         highword = _bfinfdpic_osec_to_segment
-           (output_bfd, bfinfdpic_plt_section (info)->output_section);
-       }
-      else
-       {
-         /* A function descriptor for a local function gets the index
-            of the section.  For a non-local function, it's
-            disregarded.  */
-         lowword = ad;
-         if (entry->symndx == -1 && entry->d.h->dynindx != -1
-             && entry->d.h->dynindx == idx)
-           highword = 0;
-         else
-           highword = _bfinfdpic_osec_to_segment
-             (output_bfd, sec->output_section);
-       }
-
-      bfd_put_32 (output_bfd, lowword,
-                 bfinfdpic_got_section (info)->contents
-                 + bfinfdpic_got_initial_offset (info)
-                 + entry->fd_entry);
-      bfd_put_32 (output_bfd, highword,
-                 bfinfdpic_got_section (info)->contents
-                 + bfinfdpic_got_initial_offset (info)
-                 + entry->fd_entry + 4);
-    }
-
-  /* Generate code for the PLT entry.  */
-  if (entry->plt_entry != (bfd_vma) -1)
-    {
-      bfd_byte *plt_code = bfinfdpic_plt_section (info)->contents
-       + entry->plt_entry;
-
-      BFD_ASSERT (entry->fd_entry);
+  /* A pointer to the .got section.  */
+  asection *sgot;
+  /* A pointer to the .rel.got section.  */
+  asection *sgotrel;
+  /* A pointer to the .rofixup section.  */
+  asection *sgotfixup;
+  /* A pointer to the .plt section.  */
+  asection *splt;
+  /* A pointer to the .rel.plt section.  */
+  asection *spltrel;
+  /* GOT base offset.  */
+  bfd_vma got0;
+  /* Location of the first non-lazy PLT entry, i.e., the number of
+     bytes taken by lazy PLT entries.  */
+  bfd_vma plt0;
+  /* A hash table holding information about which symbols were
+     referenced with which PIC-related relocations.  */
+  struct htab *relocs_info;
+  /* Summary reloc information collected by
+     _bfinfdpic_count_got_plt_entries.  */
+  struct _bfinfdpic_dynamic_got_info *g;
+};
 
-      /* Figure out what kind of PLT entry we need, depending on the
-        location of the function descriptor within the GOT.  */
-      if (entry->fd_entry >= -(1 << (18 - 1))
-         && entry->fd_entry + 4 < (1 << (18 - 1)))
-       {
-         /* P1 = [P3 + fd_entry]; P3 = [P3 + fd_entry + 4] */
-         bfd_put_32 (output_bfd,
-                     0xe519 | ((entry->fd_entry << 14) & 0xFFFF0000),
-                     plt_code);
-         bfd_put_32 (output_bfd,
-                     0xe51b | (((entry->fd_entry + 4) << 14) & 0xFFFF0000),
-                     plt_code + 4);
-         plt_code += 8;
-       }
-      else
-       {
-         /* P1.L = fd_entry; P1.H = fd_entry;
-            P3 = P3 + P1;
-            P1 = [P3];
-            P3 = [P3 + 4];  */
-         bfd_put_32 (output_bfd,
-                     0xe109 | (entry->fd_entry << 16),
-                     plt_code);
-         bfd_put_32 (output_bfd,
-                     0xe149 | (entry->fd_entry & 0xFFFF0000),
-                     plt_code + 4);
-         bfd_put_16 (output_bfd, 0x5ad9, plt_code + 8);
-         bfd_put_16 (output_bfd, 0x9159, plt_code + 10);
-         bfd_put_16 (output_bfd, 0xac5b, plt_code + 12);
-         plt_code += 14;
-       }
-      /* JUMP (P1) */
-      bfd_put_16 (output_bfd, 0x0051, plt_code);
-    }
+/* Get the Blackfin ELF linker hash table from a link_info structure.  */
 
-  /* Generate code for the lazy PLT entry.  */
-  if (entry->lzplt_entry != (bfd_vma) -1)
-    {
-      bfd_byte *lzplt_code = bfinfdpic_plt_section (info)->contents
-       + entry->lzplt_entry;
-      bfd_vma resolverStub_addr;
+#define bfinfdpic_hash_table(info) \
+  ((struct bfinfdpic_elf_link_hash_table *) ((info)->hash))
 
-      bfd_put_32 (output_bfd, fd_lazy_rel_offset, lzplt_code);
-      lzplt_code += 4;
+#define bfinfdpic_got_section(info) \
+  (bfinfdpic_hash_table (info)->sgot)
+#define bfinfdpic_gotrel_section(info) \
+  (bfinfdpic_hash_table (info)->sgotrel)
+#define bfinfdpic_gotfixup_section(info) \
+  (bfinfdpic_hash_table (info)->sgotfixup)
+#define bfinfdpic_plt_section(info) \
+  (bfinfdpic_hash_table (info)->splt)
+#define bfinfdpic_pltrel_section(info) \
+  (bfinfdpic_hash_table (info)->spltrel)
+#define bfinfdpic_relocs_info(info) \
+  (bfinfdpic_hash_table (info)->relocs_info)
+#define bfinfdpic_got_initial_offset(info) \
+  (bfinfdpic_hash_table (info)->got0)
+#define bfinfdpic_plt_initial_offset(info) \
+  (bfinfdpic_hash_table (info)->plt0)
+#define bfinfdpic_dynamic_got_plt_info(info) \
+  (bfinfdpic_hash_table (info)->g)
 
-      resolverStub_addr = entry->lzplt_entry / BFINFDPIC_LZPLT_BLOCK_SIZE
-       * BFINFDPIC_LZPLT_BLOCK_SIZE + BFINFDPIC_LZPLT_RESOLV_LOC;
-      if (resolverStub_addr >= bfinfdpic_plt_initial_offset (info))
-       resolverStub_addr = bfinfdpic_plt_initial_offset (info) - LZPLT_NORMAL_SIZE - LZPLT_RESOLVER_EXTRA;
+/* The name of the dynamic interpreter.  This is put in the .interp
+   section.  */
 
-      if (entry->lzplt_entry == resolverStub_addr)
-       {
-         /* This is a lazy PLT entry that includes a resolver call.
-            P2 = [P3];
-            R3 = [P3 + 4];
-            JUMP (P2);  */
-         bfd_put_32 (output_bfd,
-                     0xa05b915a,
-                     lzplt_code);
-         bfd_put_16 (output_bfd, 0x0052, lzplt_code + 4);
-       }
-      else
-       {
-         /* JUMP.S  resolverStub */
-         bfd_put_16 (output_bfd,
-                     0x2000
-                     | (((resolverStub_addr - entry->lzplt_entry)
-                         / 2) & (((bfd_vma)1 << 12) - 1)),
-                     lzplt_code);
-       }
-    }
+#define ELF_DYNAMIC_INTERPRETER "/lib/ld.so.1"
 
-  return TRUE;
-}
+#define DEFAULT_STACK_SIZE 0x20000
 
+/* This structure is used to collect the number of entries present in
+   each addressable range of the got.  */
+struct _bfinfdpic_dynamic_got_info
+{
+  /* Several bits of information about the current link.  */
+  struct bfd_link_info *info;
+  /* Total size needed for GOT entries within the 18- or 32-bit
+     ranges.  */
+  bfd_vma got17m4, gothilo;
+  /* Total size needed for function descriptor entries within the 18-
+     or 32-bit ranges.  */
+  bfd_vma fd17m4, fdhilo;
+  /* Total size needed function descriptor entries referenced in PLT
+     entries, that would be profitable to place in offsets close to
+     the PIC register.  */
+  bfd_vma fdplt;
+  /* Total size needed by lazy PLT entries.  */
+  bfd_vma lzplt;
+  /* Number of relocations carried over from input object files.  */
+  unsigned long relocs;
+  /* Number of fixups introduced by relocations in input object files.  */
+  unsigned long fixups;
+};
 
-/* Look through the relocs for a section during the first phase, and
-   allocate space in the global offset table or procedure linkage
-   table.  */
+/* Create a Blackfin ELF linker hash table.  */
 
-static bfd_boolean
-bfin_check_relocs (bfd * abfd,
-                  struct bfd_link_info *info,
-                  asection *sec,
-                   const Elf_Internal_Rela *relocs)
+static struct bfd_link_hash_table *
+bfinfdpic_elf_link_hash_table_create (bfd *abfd)
 {
-  bfd *dynobj;
-  Elf_Internal_Shdr *symtab_hdr;
-  struct elf_link_hash_entry **sym_hashes;
-  bfd_signed_vma *local_got_refcounts;
-  const Elf_Internal_Rela *rel;
-  const Elf_Internal_Rela *rel_end;
-  asection *sgot;
-  asection *srelgot;
-  asection *sreloc;
-  if (info->relocatable)
-    return TRUE;
-
-  dynobj = elf_hash_table (info)->dynobj;
-  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
-  sym_hashes = elf_sym_hashes (abfd);
-  local_got_refcounts = elf_local_got_refcounts (abfd);
+  struct bfinfdpic_elf_link_hash_table *ret;
+  bfd_size_type amt = sizeof (struct bfinfdpic_elf_link_hash_table);
 
-  sgot = NULL;
-  srelgot = NULL;
-  sreloc = NULL;
+  ret = bfd_zalloc (abfd, amt);
+  if (ret == NULL)
+    return NULL;
 
-  rel_end = relocs + sec->reloc_count;
-  for (rel = relocs; rel < rel_end; rel++)
+  if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd,
+                                     _bfd_elf_link_hash_newfunc,
+                                     sizeof (struct elf_link_hash_entry)))
     {
-      unsigned long r_symndx;
-      struct elf_link_hash_entry *h;
-
-      r_symndx = ELF32_R_SYM (rel->r_info);
-      if (r_symndx < symtab_hdr->sh_info)
-       h = NULL;
-      else
-       h = sym_hashes[r_symndx - symtab_hdr->sh_info];
-
-      switch (ELF32_R_TYPE (rel->r_info))
-       {
-       /* This relocation describes the C++ object vtable hierarchy.
-           Reconstruct it for later use during GC.  */
-        case R_BFIN_GNU_VTINHERIT:
-          if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
-            return FALSE;
-          break;
+      free (ret);
+      return NULL;
+    }
 
-        /* This relocation describes which C++ vtable entries
-           are actually used.  Record for later use during GC.  */
-        case R_BFIN_GNU_VTENTRY:
-          if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
-            return FALSE;
-          break;
+  return &ret->elf.root;
+}
 
-       case R_got:
-         if (h != NULL
-             && strcmp (h->root.root.string, "__GLOBAL_OFFSET_TABLE_") == 0)
-           break;
-         /* Fall through.  */
+/* Decide whether a reference to a symbol can be resolved locally or
+   not.  If the symbol is protected, we want the local address, but
+   its function descriptor must be assigned by the dynamic linker.  */
+#define BFINFDPIC_SYM_LOCAL(INFO, H) \
+  (_bfd_elf_symbol_refs_local_p ((H), (INFO), 1) \
+   || ! elf_hash_table (INFO)->dynamic_sections_created)
+#define BFINFDPIC_FUNCDESC_LOCAL(INFO, H) \
+  ((H)->dynindx == -1 || ! elf_hash_table (INFO)->dynamic_sections_created)
 
-         if (dynobj == NULL)
-           {
-             /* Create the .got section.  */
-             elf_hash_table (info)->dynobj = dynobj = abfd;
-             if (!_bfd_elf_create_got_section (dynobj, info))
-               return FALSE;
-           }
-
-         if (sgot == NULL)
-           {
-             sgot = bfd_get_section_by_name (dynobj, ".got");
-             BFD_ASSERT (sgot != NULL);
-           }
+/* This structure collects information on what kind of GOT, PLT or
+   function descriptors are required by relocations that reference a
+   certain symbol.  */
+struct bfinfdpic_relocs_info
+{
+  /* The index of the symbol, as stored in the relocation r_info, if
+     we have a local symbol; -1 otherwise.  */
+  long symndx;
+  union
+  {
+    /* The input bfd in which the symbol is defined, if it's a local
+       symbol.  */
+    bfd *abfd;
+    /* If symndx == -1, the hash table entry corresponding to a global
+       symbol (even if it turns out to bind locally, in which case it
+       should ideally be replaced with section's symndx + addend).  */
+    struct elf_link_hash_entry *h;
+  } d;
+  /* The addend of the relocation that references the symbol.  */
+  bfd_vma addend;
 
-         if (srelgot == NULL && (h != NULL || info->shared))
-           {
-             srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
-             if (srelgot == NULL)
-               {
-                 flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
-                                   | SEC_IN_MEMORY | SEC_LINKER_CREATED
-                                   | SEC_READONLY);
-                 srelgot = bfd_make_section_with_flags (dynobj, ".rela.got",
-                                                        flags);
-                 if (srelgot == NULL
-                     || !bfd_set_section_alignment (dynobj, srelgot, 2))
-                   return FALSE;
-               }
-           }
+  /* The fields above are used to identify an entry.  The fields below
+     contain information on how an entry is used and, later on, which
+     locations it was assigned.  */
+  /* The following 2 fields record whether the symbol+addend above was
+     ever referenced with a GOT relocation.  The 17M4 suffix indicates a
+     GOT17M4 relocation; hilo is used for GOTLO/GOTHI pairs.  */
+  unsigned got17m4;
+  unsigned gothilo;
+  /* Whether a FUNCDESC relocation references symbol+addend.  */
+  unsigned fd;
+  /* Whether a FUNCDESC_GOT relocation references symbol+addend.  */
+  unsigned fdgot17m4;
+  unsigned fdgothilo;
+  /* Whether a FUNCDESC_GOTOFF relocation references symbol+addend.  */
+  unsigned fdgoff17m4;
+  unsigned fdgoffhilo;
+  /* Whether symbol+addend is referenced with GOTOFF17M4, GOTOFFLO or
+     GOTOFFHI relocations.  The addend doesn't really matter, since we
+     envision that this will only be used to check whether the symbol
+     is mapped to the same segment as the got.  */
+  unsigned gotoff;
+  /* Whether symbol+addend is referenced by a LABEL24 relocation.  */
+  unsigned call;
+  /* Whether symbol+addend is referenced by a 32 or FUNCDESC_VALUE
+     relocation.  */
+  unsigned sym;
+  /* Whether we need a PLT entry for a symbol.  Should be implied by
+     something like:
+     (call && symndx == -1 && ! BFINFDPIC_SYM_LOCAL (info, d.h))  */
+  unsigned plt:1;
+  /* Whether a function descriptor should be created in this link unit
+     for symbol+addend.  Should be implied by something like:
+     (plt || fdgotoff17m4 || fdgotofflohi
+      || ((fd || fdgot17m4 || fdgothilo)
+          && (symndx != -1 || BFINFDPIC_FUNCDESC_LOCAL (info, d.h))))  */
+  unsigned privfd:1;
+  /* Whether a lazy PLT entry is needed for this symbol+addend.
+     Should be implied by something like:
+     (privfd && symndx == -1 && ! BFINFDPIC_SYM_LOCAL (info, d.h)
+      && ! (info->flags & DF_BIND_NOW))  */
+  unsigned lazyplt:1;
+  /* Whether we've already emitted GOT relocations and PLT entries as
+     needed for this symbol.  */
+  unsigned done:1;
 
-         if (h != NULL)
-           {
-             if (h->got.refcount == 0)
-               {
-                 /* Make sure this symbol is output as a dynamic symbol.  */
-                 if (h->dynindx == -1 && !h->forced_local)
-                   {
-                     if (!bfd_elf_link_record_dynamic_symbol (info, h))
-                       return FALSE;
-                   }
+  /* The number of R_BFIN_BYTE4_DATA, R_BFIN_FUNCDESC and R_BFIN_FUNCDESC_VALUE
+     relocations referencing the symbol.  */
+  unsigned relocs32, relocsfd, relocsfdv;
 
-                 /* Allocate space in the .got section.  */
-                 sgot->size += 4;
-                 /* Allocate relocation space.  */
-                 srelgot->size += sizeof (Elf32_External_Rela);
-               }
-             h->got.refcount++;
-           }
-         else
-           {
-             /* This is a global offset table entry for a local symbol.  */
-             if (local_got_refcounts == NULL)
-               {
-                 bfd_size_type size;
+  /* The number of .rofixups entries and dynamic relocations allocated
+     for this symbol, minus any that might have already been used.  */
+  unsigned fixups, dynrelocs;
 
-                 size = symtab_hdr->sh_info;
-                 size *= sizeof (bfd_signed_vma);
-                 local_got_refcounts = ((bfd_signed_vma *)
-                                        bfd_zalloc (abfd, size));
-                 if (local_got_refcounts == NULL)
-                   return FALSE;
-                 elf_local_got_refcounts (abfd) = local_got_refcounts;
-               }
-             if (local_got_refcounts[r_symndx] == 0)
-               {
-                 sgot->size += 4;
-                 if (info->shared)
-                   {
-                     /* If we are generating a shared object, we need to
-                        output a R_68K_RELATIVE reloc so that the dynamic
-                        linker can adjust this GOT entry.  */
-                     srelgot->size += sizeof (Elf32_External_Rela);
-                   }
-               }
-             local_got_refcounts[r_symndx]++;
-           }
-         break;
+  /* The offsets of the GOT entries assigned to symbol+addend, to the
+     function descriptor's address, and to a function descriptor,
+     respectively.  Should be zero if unassigned.  The offsets are
+     counted from the value that will be assigned to the PIC register,
+     not from the beginning of the .got section.  */
+  bfd_signed_vma got_entry, fdgot_entry, fd_entry;
+  /* The offsets of the PLT entries assigned to symbol+addend,
+     non-lazy and lazy, respectively.  If unassigned, should be
+     (bfd_vma)-1.  */
+  bfd_vma plt_entry, lzplt_entry;
+};
 
-       default:
-         break;
-       }
-    }
+/* Compute a hash with the key fields of an bfinfdpic_relocs_info entry.  */
+static hashval_t
+bfinfdpic_relocs_info_hash (const void *entry_)
+{
+  const struct bfinfdpic_relocs_info *entry = entry_;
 
-  return TRUE;
+  return (entry->symndx == -1
+         ? (long) entry->d.h->root.root.hash
+         : entry->symndx + (long) entry->d.abfd->id * 257) + entry->addend;
 }
 
-static enum elf_reloc_type_class
-elf32_bfin_reloc_type_class (const Elf_Internal_Rela * rela)
+/* Test whether the key fields of two bfinfdpic_relocs_info entries are
+   identical.  */
+static int
+bfinfdpic_relocs_info_eq (const void *entry1, const void *entry2)
 {
-  switch ((int) ELF32_R_TYPE (rela->r_info))
-    {
-    default:
-      return reloc_class_normal;
-    }
+  const struct bfinfdpic_relocs_info *e1 = entry1;
+  const struct bfinfdpic_relocs_info *e2 = entry2;
+
+  return e1->symndx == e2->symndx && e1->addend == e2->addend
+    && (e1->symndx == -1 ? e1->d.h == e2->d.h : e1->d.abfd == e2->d.abfd);
 }
-\f
-/* Relocate an Blackfin ELF section.
 
-   The RELOCATE_SECTION function is called by the new ELF backend linker
-   to handle the relocations for a section.
+/* Find or create an entry in a hash table HT that matches the key
+   fields of the given ENTRY.  If it's not found, memory for a new
+   entry is allocated in ABFD's obstack.  */
+static struct bfinfdpic_relocs_info *
+bfinfdpic_relocs_info_find (struct htab *ht,
+                          bfd *abfd,
+                          const struct bfinfdpic_relocs_info *entry,
+                          enum insert_option insert)
+{
+  struct bfinfdpic_relocs_info **loc;
 
-   The relocs are always passed as Rela structures; if the section
-   actually uses Rel structures, the r_addend field will always be
-   zero.
+  if (!ht)
+    return NULL;
 
-   This function is responsible for adjusting the section contents as
-   necessary, and (if using Rela relocs and generating a relocatable
-   output file) adjusting the reloc addend as necessary.
+  loc = (struct bfinfdpic_relocs_info **) htab_find_slot (ht, entry, insert);
 
-   This function does not have to worry about setting the reloc
-   address or the reloc symbol index.
+  if (! loc)
+    return NULL;
 
-   LOCAL_SYMS is a pointer to the swapped in local symbols.
+  if (*loc)
+    return *loc;
 
-   LOCAL_SECTIONS is an array giving the section in the input file
-   corresponding to the st_shndx field of each local symbol.
+  *loc = bfd_zalloc (abfd, sizeof (**loc));
 
-   The global hash table entry for the global symbols can be found
-   via elf_sym_hashes (input_bfd).
+  if (! *loc)
+    return *loc;
 
-   When generating relocatable output, this function must handle
-   STB_LOCAL/STT_SECTION symbols specially.  The output symbol is
-   going to be the section symbol corresponding to the output
-   section, which means that the addend must be adjusted
-   accordingly.  */
+  (*loc)->symndx = entry->symndx;
+  (*loc)->d = entry->d;
+  (*loc)->addend = entry->addend;
+  (*loc)->plt_entry = (bfd_vma)-1;
+  (*loc)->lzplt_entry = (bfd_vma)-1;
 
-static bfd_boolean
-bfinfdpic_relocate_section (bfd * output_bfd,
-                           struct bfd_link_info *info,
-                           bfd * input_bfd,
-                           asection * input_section,
-                           bfd_byte * contents,
-                           Elf_Internal_Rela * relocs,
-                           Elf_Internal_Sym * local_syms,
-                           asection ** local_sections)
+  return *loc;
+}
+
+/* Obtain the address of the entry in HT associated with H's symbol +
+   addend, creating a new entry if none existed.  ABFD is only used
+   for memory allocation purposes.  */
+inline static struct bfinfdpic_relocs_info *
+bfinfdpic_relocs_info_for_global (struct htab *ht,
+                                bfd *abfd,
+                                struct elf_link_hash_entry *h,
+                                bfd_vma addend,
+                                enum insert_option insert)
 {
-  Elf_Internal_Shdr *symtab_hdr;
-  struct elf_link_hash_entry **sym_hashes;
-  Elf_Internal_Rela *rel;
-  Elf_Internal_Rela *relend;
-  unsigned isec_segment, got_segment, plt_segment,
-    check_segment[2];
-  int silence_segment_error = !(info->shared || info->pie);
+  struct bfinfdpic_relocs_info entry;
 
-  symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
-  sym_hashes = elf_sym_hashes (input_bfd);
-  relend     = relocs + input_section->reloc_count;
+  entry.symndx = -1;
+  entry.d.h = h;
+  entry.addend = addend;
 
-  isec_segment = _bfinfdpic_osec_to_segment (output_bfd,
-                                            input_section->output_section);
-  if (IS_FDPIC (output_bfd) && bfinfdpic_got_section (info))
-    got_segment = _bfinfdpic_osec_to_segment (output_bfd,
-                                             bfinfdpic_got_section (info)
-                                             ->output_section);
-  else
-    got_segment = -1;
-  if (IS_FDPIC (output_bfd) && elf_hash_table (info)->dynamic_sections_created)
-    plt_segment = _bfinfdpic_osec_to_segment (output_bfd,
-                                             bfinfdpic_plt_section (info)
-                                             ->output_section);
-  else
-    plt_segment = -1;
+  return bfinfdpic_relocs_info_find (ht, abfd, &entry, insert);
+}
 
-  for (rel = relocs; rel < relend; rel ++)
-    {
-      reloc_howto_type *howto;
-      unsigned long r_symndx;
-      Elf_Internal_Sym *sym;
-      asection *sec;
-      struct elf_link_hash_entry *h;
-      bfd_vma relocation;
-      bfd_reloc_status_type r;
-      const char * name = NULL;
-      int r_type;
-      asection *osec;
-      struct bfinfdpic_relocs_info *picrel;
-      bfd_vma orig_addend = rel->r_addend;
+/* Obtain the address of the entry in HT associated with the SYMNDXth
+   local symbol of the input bfd ABFD, plus the addend, creating a new
+   entry if none existed.  */
+inline static struct bfinfdpic_relocs_info *
+bfinfdpic_relocs_info_for_local (struct htab *ht,
+                               bfd *abfd,
+                               long symndx,
+                               bfd_vma addend,
+                               enum insert_option insert)
+{
+  struct bfinfdpic_relocs_info entry;
 
-      r_type = ELF32_R_TYPE (rel->r_info);
+  entry.symndx = symndx;
+  entry.d.abfd = abfd;
+  entry.addend = addend;
 
-      if (r_type == R_BFIN_GNU_VTINHERIT
-         || r_type == R_BFIN_GNU_VTENTRY)
-       continue;
+  return bfinfdpic_relocs_info_find (ht, abfd, &entry, insert);
+}
 
-      r_symndx = ELF32_R_SYM (rel->r_info);
-      howto = bfin_reloc_type_lookup (input_bfd, r_type);
-      if (howto == NULL)
-       {
-         bfd_set_error (bfd_error_bad_value);
-         return FALSE;
-       }
+/* Merge fields set by check_relocs() of two entries that end up being
+   mapped to the same (presumably global) symbol.  */
 
-      h      = NULL;
-      sym    = NULL;
-      sec    = NULL;
+inline static void
+bfinfdpic_pic_merge_early_relocs_info (struct bfinfdpic_relocs_info *e2,
+                                     struct bfinfdpic_relocs_info const *e1)
+{
+  e2->got17m4 |= e1->got17m4;
+  e2->gothilo |= e1->gothilo;
+  e2->fd |= e1->fd;
+  e2->fdgot17m4 |= e1->fdgot17m4;
+  e2->fdgothilo |= e1->fdgothilo;
+  e2->fdgoff17m4 |= e1->fdgoff17m4;
+  e2->fdgoffhilo |= e1->fdgoffhilo;
+  e2->gotoff |= e1->gotoff;
+  e2->call |= e1->call;
+  e2->sym |= e1->sym;
+}
 
-      if (r_symndx < symtab_hdr->sh_info)
-       {
-         sym = local_syms + r_symndx;
-         osec = sec = local_sections [r_symndx];
-         relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
+/* Every block of 65535 lazy PLT entries shares a single call to the
+   resolver, inserted in the 32768th lazy PLT entry (i.e., entry #
+   32767, counting from 0).  All other lazy PLT entries branch to it
+   in a single instruction.  */
 
-         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;
-       }
-      else
-       {
-         bfd_boolean warned;
-         bfd_boolean unresolved_reloc;
+#define LZPLT_RESOLVER_EXTRA 10
+#define LZPLT_NORMAL_SIZE 6
+#define LZPLT_ENTRIES 1362
 
-         RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
-                                  r_symndx, symtab_hdr, sym_hashes,
-                                  h, sec, relocation,
-                                  unresolved_reloc, warned);
-         osec = sec;
-       }
+#define BFINFDPIC_LZPLT_BLOCK_SIZE ((bfd_vma) LZPLT_NORMAL_SIZE * LZPLT_ENTRIES + LZPLT_RESOLVER_EXTRA)
+#define BFINFDPIC_LZPLT_RESOLV_LOC (LZPLT_NORMAL_SIZE * LZPLT_ENTRIES / 2)
 
-      if (sec != NULL && elf_discarded_section (sec))
-       {
-         /* For relocs against symbols from removed linkonce sections,
-            or sections discarded by a linker script, we just want the
-            section contents zeroed.  Avoid any special processing.  */
-         _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
-         rel->r_info = 0;
-         rel->r_addend = 0;
-         continue;
-       }
+/* Add a dynamic relocation to the SRELOC section.  */
 
-      if (info->relocatable)
-       continue;
+inline static bfd_vma
+_bfinfdpic_add_dyn_reloc (bfd *output_bfd, asection *sreloc, bfd_vma offset,
+                        int reloc_type, long dynindx, bfd_vma addend,
+                        struct bfinfdpic_relocs_info *entry)
+{
+  Elf_Internal_Rela outrel;
+  bfd_vma reloc_offset;
 
-      if (h != NULL
-         && (h->root.type == bfd_link_hash_defined
-             || h->root.type == bfd_link_hash_defweak)
-         && !BFINFDPIC_SYM_LOCAL (info, h))
-       {
-         osec = sec = NULL;
-         relocation = 0;
-       }
+  outrel.r_offset = offset;
+  outrel.r_info = ELF32_R_INFO (dynindx, reloc_type);
+  outrel.r_addend = addend;
 
-      switch (r_type)
-       {
-       case R_pcrel24:
-       case R_pcrel24_jump_l:
-       case R_byte4_data:
-         if (! IS_FDPIC (output_bfd))
-           goto non_fdpic;
+  reloc_offset = sreloc->reloc_count * sizeof (Elf32_External_Rel);
+  BFD_ASSERT (reloc_offset < sreloc->size);
+  bfd_elf32_swap_reloc_out (output_bfd, &outrel,
+                           sreloc->contents + reloc_offset);
+  sreloc->reloc_count++;
 
-       case R_BFIN_GOT17M4:
-       case R_BFIN_GOTHI:
-       case R_BFIN_GOTLO:
-       case R_BFIN_FUNCDESC_GOT17M4:
-       case R_BFIN_FUNCDESC_GOTHI:
-       case R_BFIN_FUNCDESC_GOTLO:
-       case R_BFIN_GOTOFF17M4:
-       case R_BFIN_GOTOFFHI:
-       case R_BFIN_GOTOFFLO:
-       case R_BFIN_FUNCDESC_GOTOFF17M4:
-       case R_BFIN_FUNCDESC_GOTOFFHI:
-       case R_BFIN_FUNCDESC_GOTOFFLO:
-       case R_BFIN_FUNCDESC:
-       case R_BFIN_FUNCDESC_VALUE:
-         if (h != NULL)
-           picrel = bfinfdpic_relocs_info_for_global (bfinfdpic_relocs_info
-                                                      (info), input_bfd, h,
-                                                      orig_addend, INSERT);
-         else
-           /* In order to find the entry we created before, we must
-              use the original addend, not the one that may have been
-              modified by _bfd_elf_rela_local_sym().  */
-           picrel = bfinfdpic_relocs_info_for_local (bfinfdpic_relocs_info
-                                                     (info), input_bfd, r_symndx,
-                                                     orig_addend, INSERT);
-         if (! picrel)
-           return FALSE;
+  /* If the entry's index is zero, this relocation was probably to a
+     linkonce section that got discarded.  We reserved a dynamic
+     relocation, but it was for another entry than the one we got at
+     the time of emitting the relocation.  Unfortunately there's no
+     simple way for us to catch this situation, since the relocation
+     is cleared right before calling relocate_section, at which point
+     we no longer know what the relocation used to point to.  */
+  if (entry->symndx)
+    {
+      BFD_ASSERT (entry->dynrelocs > 0);
+      entry->dynrelocs--;
+    }
 
-         if (!_bfinfdpic_emit_got_relocs_plt_entries (picrel, output_bfd, info,
-                                                      osec, sym,
-                                                      rel->r_addend))
-           {
-             (*_bfd_error_handler)
-               (_("%B: relocation at `%A+0x%x' references symbol `%s' with nonzero addend"),
-                input_bfd, input_section, rel->r_offset, name);
-             return FALSE;
+  return reloc_offset;
+}
 
-           }
+/* Add a fixup to the ROFIXUP section.  */
 
-         break;
+static bfd_vma
+_bfinfdpic_add_rofixup (bfd *output_bfd, asection *rofixup, bfd_vma offset,
+                      struct bfinfdpic_relocs_info *entry)
+{
+  bfd_vma fixup_offset;
 
-       default:
-       non_fdpic:
-         picrel = NULL;
-         if (h && ! BFINFDPIC_SYM_LOCAL (info, h))
-           {
-             info->callbacks->warning
-               (info, _("relocation references symbol not defined in the module"),
-                name, input_bfd, input_section, rel->r_offset);
-             return FALSE;
-           }
-         break;
-       }
+  if (rofixup->flags & SEC_EXCLUDE)
+    return -1;
 
-      switch (r_type)
-       {
-       case R_pcrel24:
-       case R_pcrel24_jump_l:
-         check_segment[0] = isec_segment;
-         if (! IS_FDPIC (output_bfd))
-           check_segment[1] = isec_segment;
-         else if (picrel->plt)
-           {
-             relocation = bfinfdpic_plt_section (info)->output_section->vma
-               + bfinfdpic_plt_section (info)->output_offset
-               + picrel->plt_entry;
-             check_segment[1] = plt_segment;
-           }
-         /* We don't want to warn on calls to undefined weak symbols,
-            as calls to them must be protected by non-NULL tests
-            anyway, and unprotected calls would invoke undefined
-            behavior.  */
-         else if (picrel->symndx == -1
-                  && picrel->d.h->root.type == bfd_link_hash_undefweak)
-           check_segment[1] = check_segment[0];
-         else
-           check_segment[1] = sec
-             ? _bfinfdpic_osec_to_segment (output_bfd, sec->output_section)
-             : (unsigned)-1;
-         break;
+  fixup_offset = rofixup->reloc_count * 4;
+  if (rofixup->contents)
+    {
+      BFD_ASSERT (fixup_offset < rofixup->size);
+      bfd_put_32 (output_bfd, offset, rofixup->contents + fixup_offset);
+    }
+  rofixup->reloc_count++;
 
-       case R_BFIN_GOT17M4:
-       case R_BFIN_GOTHI:
-       case R_BFIN_GOTLO:
-         relocation = picrel->got_entry;
-         check_segment[0] = check_segment[1] = got_segment;
-         break;
+  if (entry && entry->symndx)
+    {
+      /* See discussion about symndx == 0 in _bfinfdpic_add_dyn_reloc
+        above.  */
+      BFD_ASSERT (entry->fixups > 0);
+      entry->fixups--;
+    }
 
-       case R_BFIN_FUNCDESC_GOT17M4:
-       case R_BFIN_FUNCDESC_GOTHI:
-       case R_BFIN_FUNCDESC_GOTLO:
-         relocation = picrel->fdgot_entry;
-         check_segment[0] = check_segment[1] = got_segment;
-         break;
-
-       case R_BFIN_GOTOFFHI:
-       case R_BFIN_GOTOFF17M4:
-       case R_BFIN_GOTOFFLO:
-         relocation -= bfinfdpic_got_section (info)->output_section->vma
-           + bfinfdpic_got_section (info)->output_offset
-           + bfinfdpic_got_initial_offset (info);
-         check_segment[0] = got_segment;
-         check_segment[1] = sec
-           ? _bfinfdpic_osec_to_segment (output_bfd, sec->output_section)
-           : (unsigned)-1;
-         break;
+  return fixup_offset;
+}
 
-       case R_BFIN_FUNCDESC_GOTOFF17M4:
-       case R_BFIN_FUNCDESC_GOTOFFHI:
-       case R_BFIN_FUNCDESC_GOTOFFLO:
-         relocation = picrel->fd_entry;
-         check_segment[0] = check_segment[1] = got_segment;
-         break;
+/* Find the segment number in which OSEC, and output section, is
+   located.  */
 
-       case R_BFIN_FUNCDESC:
-         {
-           int dynindx;
-           bfd_vma addend = rel->r_addend;
+static unsigned
+_bfinfdpic_osec_to_segment (bfd *output_bfd, asection *osec)
+{
+  Elf_Internal_Phdr *p = _bfd_elf_find_segment_containing_section (output_bfd, osec);
 
-           if (! (h && h->root.type == bfd_link_hash_undefweak
-                  && BFINFDPIC_SYM_LOCAL (info, h)))
-             {
-               /* If the symbol is dynamic and there may be dynamic
-                  symbol resolution because we are or are linked with a
-                  shared library, emit a FUNCDESC relocation such that
-                  the dynamic linker will allocate the function
-                  descriptor.  If the symbol needs a non-local function
-                  descriptor but binds locally (e.g., its visibility is
-                  protected, emit a dynamic relocation decayed to
-                  section+offset.  */
-               if (h && ! BFINFDPIC_FUNCDESC_LOCAL (info, h)
-                   && BFINFDPIC_SYM_LOCAL (info, h)
-                   && !(info->executable && !info->pie))
-                 {
-                   dynindx = elf_section_data (h->root.u.def.section
-                                               ->output_section)->dynindx;
-                   addend += h->root.u.def.section->output_offset
-                     + h->root.u.def.value;
-                 }
-               else if (h && ! BFINFDPIC_FUNCDESC_LOCAL (info, h))
-                 {
-                   if (addend)
-                     {
-                       info->callbacks->warning
-                         (info, _("R_BFIN_FUNCDESC references dynamic symbol with nonzero addend"),
-                          name, input_bfd, input_section, rel->r_offset);
-                       return FALSE;
-                     }
-                   dynindx = h->dynindx;
-                 }
-               else
-                 {
-                   /* Otherwise, we know we have a private function
-                      descriptor, so reference it directly.  */
-                   BFD_ASSERT (picrel->privfd);
-                   r_type = R_byte4_data;
-                   dynindx = elf_section_data (bfinfdpic_got_section (info)
-                                               ->output_section)->dynindx;
-                   addend = bfinfdpic_got_section (info)->output_offset
-                     + bfinfdpic_got_initial_offset (info)
-                     + picrel->fd_entry;
-                 }
+  return (p != NULL) ? p - elf_tdata (output_bfd)->phdr : -1;
+}
 
-               /* If there is room for dynamic symbol resolution, emit
-                  the dynamic relocation.  However, if we're linking an
-                  executable at a fixed location, we won't have emitted a
-                  dynamic symbol entry for the got section, so idx will
-                  be zero, which means we can and should compute the
-                  address of the private descriptor ourselves.  */
-               if (info->executable && !info->pie
-                   && (!h || BFINFDPIC_FUNCDESC_LOCAL (info, h)))
-                 {
-                   addend += bfinfdpic_got_section (info)->output_section->vma;
-                   if ((bfd_get_section_flags (output_bfd,
-                                               input_section->output_section)
-                        & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD))
-                     {
-                       if (_bfinfdpic_osec_readonly_p (output_bfd,
-                                                      input_section
-                                                      ->output_section))
-                         {
-                           info->callbacks->warning
-                             (info,
-                              _("cannot emit fixups in read-only section"),
-                              name, input_bfd, input_section, rel->r_offset);
-                           return FALSE;
-                         }
-                       _bfinfdpic_add_rofixup (output_bfd,
-                                              bfinfdpic_gotfixup_section
-                                              (info),
-                                              _bfd_elf_section_offset
-                                              (output_bfd, info,
-                                               input_section, rel->r_offset)
-                                              + input_section
-                                              ->output_section->vma
-                                              + input_section->output_offset,
-                                              picrel);
-                     }
-                 }
-               else if ((bfd_get_section_flags (output_bfd,
-                                                input_section->output_section)
-                         & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD))
-                 {
-                   bfd_vma offset;
+inline static bfd_boolean
+_bfinfdpic_osec_readonly_p (bfd *output_bfd, asection *osec)
+{
+  unsigned seg = _bfinfdpic_osec_to_segment (output_bfd, osec);
 
-                   if (_bfinfdpic_osec_readonly_p (output_bfd,
-                                                  input_section
-                                                  ->output_section))
-                     {
-                       info->callbacks->warning
-                         (info,
-                          _("cannot emit dynamic relocations in read-only section"),
-                          name, input_bfd, input_section, rel->r_offset);
-                       return FALSE;
-                     }
-                   offset = _bfd_elf_section_offset (output_bfd, info,
-                                                     input_section, rel->r_offset);
-                   /* Only output a reloc for a not deleted entry.  */
-                   if (offset >= (bfd_vma) -2)
-                     _bfinfdpic_add_dyn_reloc (output_bfd,
-                                               bfinfdpic_gotrel_section (info),
-                                               0,
-                                               R_unused0,
-                                               dynindx, addend, picrel);
-                   else
-                     _bfinfdpic_add_dyn_reloc (output_bfd,
-                                               bfinfdpic_gotrel_section (info),
-                                               offset + input_section
-                                               ->output_section->vma
-                                               + input_section->output_offset,
-                                               r_type,
-                                               dynindx, addend, picrel);
-                 }
-               else
-                 addend += bfinfdpic_got_section (info)->output_section->vma;
-             }
+  return ! (elf_tdata (output_bfd)->phdr[seg].p_flags & PF_W);
+}
 
-           /* We want the addend in-place because dynamic
-              relocations are REL.  Setting relocation to it should
-              arrange for it to be installed.  */
-           relocation = addend - rel->r_addend;
-         }
-         check_segment[0] = check_segment[1] = got_segment;
-         break;
+/* Generate relocations for GOT entries, function descriptors, and
+   code for PLT and lazy PLT entries.  */
 
-       case R_byte4_data:
-         if (! IS_FDPIC (output_bfd))
-           {
-             check_segment[0] = check_segment[1] = -1;
-             break;
-           }
-         /* Fall through.  */
-       case R_BFIN_FUNCDESC_VALUE:
-         {
-           int dynindx;
-           bfd_vma addend = rel->r_addend;
+inline static bfd_boolean
+_bfinfdpic_emit_got_relocs_plt_entries (struct bfinfdpic_relocs_info *entry,
+                                       bfd *output_bfd,
+                                       struct bfd_link_info *info,
+                                       asection *sec,
+                                       Elf_Internal_Sym *sym,
+                                       bfd_vma addend)
 
-           /* If the symbol is dynamic but binds locally, use
-              section+offset.  */
-           if (h && ! BFINFDPIC_SYM_LOCAL (info, h))
-             {
-               if (addend && r_type == R_BFIN_FUNCDESC_VALUE)
-                 {
-                   info->callbacks->warning
-                     (info, _("R_BFIN_FUNCDESC_VALUE references dynamic symbol with nonzero addend"),
-                      name, input_bfd, input_section, rel->r_offset);
-                   return FALSE;
-                 }
-               dynindx = h->dynindx;
-             }
-           else
-             {
-               if (h)
-                 addend += h->root.u.def.value;
-               else
-                 addend += sym->st_value;
-               if (osec)
-                 addend += osec->output_offset;
-               if (osec && osec->output_section
-                   && ! bfd_is_abs_section (osec->output_section)
-                   && ! bfd_is_und_section (osec->output_section))
-                 dynindx = elf_section_data (osec->output_section)->dynindx;
-               else
-                 dynindx = 0;
-             }
+{
+  bfd_vma fd_lazy_rel_offset = (bfd_vma)-1;
+  int dynindx = -1;
 
-           /* If we're linking an executable at a fixed address, we
-              can omit the dynamic relocation as long as the symbol
-              is defined in the current link unit (which is implied
-              by its output section not being NULL).  */
-           if (info->executable && !info->pie
-               && (!h || BFINFDPIC_SYM_LOCAL (info, h)))
-             {
-               if (osec)
-                 addend += osec->output_section->vma;
-               if (IS_FDPIC (input_bfd)
-                   && (bfd_get_section_flags (output_bfd,
-                                              input_section->output_section)
-                       & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD))
-                 {
-                   if (_bfinfdpic_osec_readonly_p (output_bfd,
-                                                  input_section
-                                                  ->output_section))
-                     {
-                       info->callbacks->warning
-                         (info,
-                          _("cannot emit fixups in read-only section"),
-                          name, input_bfd, input_section, rel->r_offset);
-                       return FALSE;
-                     }
-                   if (!h || h->root.type != bfd_link_hash_undefweak)
-                     {
-                       _bfinfdpic_add_rofixup (output_bfd,
-                                              bfinfdpic_gotfixup_section
-                                              (info),
-                                              _bfd_elf_section_offset
-                                              (output_bfd, info,
-                                               input_section, rel->r_offset)
-                                              + input_section
-                                              ->output_section->vma
-                                              + input_section->output_offset,
-                                              picrel);
-                       if (r_type == R_BFIN_FUNCDESC_VALUE)
-                         _bfinfdpic_add_rofixup
-                           (output_bfd,
-                            bfinfdpic_gotfixup_section (info),
-                            _bfd_elf_section_offset
-                            (output_bfd, info,
-                             input_section, rel->r_offset)
-                            + input_section->output_section->vma
-                            + input_section->output_offset + 4, picrel);
-                     }
-                 }
-             }
-           else
-             {
-               if ((bfd_get_section_flags (output_bfd,
-                                           input_section->output_section)
-                    & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD))
-                 {
-                   if (_bfinfdpic_osec_readonly_p (output_bfd,
-                                                  input_section
-                                                  ->output_section))
-                     {
-                       info->callbacks->warning
-                         (info,
-                          _("cannot emit dynamic relocations in read-only section"),
-                          name, input_bfd, input_section, rel->r_offset);
-                       return FALSE;
-                     }
-                   _bfinfdpic_add_dyn_reloc (output_bfd,
-                                             bfinfdpic_gotrel_section (info),
-                                             _bfd_elf_section_offset
-                                             (output_bfd, info,
-                                              input_section, rel->r_offset)
-                                             + input_section
-                                             ->output_section->vma
-                                             + input_section->output_offset,
-                                             r_type, dynindx, addend, picrel);
-                 }
-               else if (osec)
-                 addend += osec->output_section->vma;
-               /* We want the addend in-place because dynamic
-                  relocations are REL.  Setting relocation to it
-                  should arrange for it to be installed.  */
-               relocation = addend - rel->r_addend;
-             }
+  if (entry->done)
+    return TRUE;
+  entry->done = 1;
 
-           if (r_type == R_BFIN_FUNCDESC_VALUE)
-             {
-               /* If we've omitted the dynamic relocation, just emit
-                  the fixed addresses of the symbol and of the local
-                  GOT base offset.  */
-               if (info->executable && !info->pie
-                   && (!h || BFINFDPIC_SYM_LOCAL (info, h)))
-                 bfd_put_32 (output_bfd,
-                             bfinfdpic_got_section (info)->output_section->vma
-                             + bfinfdpic_got_section (info)->output_offset
-                             + bfinfdpic_got_initial_offset (info),
-                             contents + rel->r_offset + 4);
-               else
-                 /* A function descriptor used for lazy or local
-                    resolving is initialized such that its high word
-                    contains the output section index in which the
-                    PLT entries are located, and the low word
-                    contains the offset of the lazy PLT entry entry
-                    point into that section.  */
-                 bfd_put_32 (output_bfd,
-                             h && ! BFINFDPIC_SYM_LOCAL (info, h)
-                             ? 0
-                             : _bfinfdpic_osec_to_segment (output_bfd,
-                                                           sec
-                                                           ->output_section),
-                             contents + rel->r_offset + 4);
-             }
-         }
-         check_segment[0] = check_segment[1] = got_segment;
-         break;
+  if (entry->got_entry || entry->fdgot_entry || entry->fd_entry)
+    {
+      /* If the symbol is dynamic, consider it for dynamic
+        relocations, otherwise decay to section + offset.  */
+      if (entry->symndx == -1 && entry->d.h->dynindx != -1)
+       dynindx = entry->d.h->dynindx;
+      else
+       {
+         if (sec
+             && sec->output_section
+             && ! bfd_is_abs_section (sec->output_section)
+             && ! bfd_is_und_section (sec->output_section))
+           dynindx = elf_section_data (sec->output_section)->dynindx;
+         else
+           dynindx = 0;
+       }
+    }
+
+  /* Generate relocation for GOT entry pointing to the symbol.  */
+  if (entry->got_entry)
+    {
+      int idx = dynindx;
+      bfd_vma ad = addend;
+
+      /* If the symbol is dynamic but binds locally, use
+        section+offset.  */
+      if (sec && (entry->symndx != -1
+                 || BFINFDPIC_SYM_LOCAL (info, entry->d.h)))
+       {
+         if (entry->symndx == -1)
+           ad += entry->d.h->root.u.def.value;
+         else
+           ad += sym->st_value;
+         ad += sec->output_offset;
+         if (sec->output_section && elf_section_data (sec->output_section))
+           idx = elf_section_data (sec->output_section)->dynindx;
+         else
+           idx = 0;
+       }
+
+      /* If we're linking an executable at a fixed address, we can
+        omit the dynamic relocation as long as the symbol is local to
+        this module.  */
+      if (info->executable && !info->pie
+         && (entry->symndx != -1
+             || BFINFDPIC_SYM_LOCAL (info, entry->d.h)))
+       {
+         if (sec)
+           ad += sec->output_section->vma;
+         if (entry->symndx != -1
+             || entry->d.h->root.type != bfd_link_hash_undefweak)
+           _bfinfdpic_add_rofixup (output_bfd,
+                                  bfinfdpic_gotfixup_section (info),
+                                  bfinfdpic_got_section (info)->output_section
+                                  ->vma
+                                  + bfinfdpic_got_section (info)->output_offset
+                                  + bfinfdpic_got_initial_offset (info)
+                                  + entry->got_entry, entry);
+       }
+      else
+       _bfinfdpic_add_dyn_reloc (output_bfd, bfinfdpic_gotrel_section (info),
+                                _bfd_elf_section_offset
+                                (output_bfd, info,
+                                 bfinfdpic_got_section (info),
+                                 bfinfdpic_got_initial_offset (info)
+                                 + entry->got_entry)
+                                + bfinfdpic_got_section (info)
+                                ->output_section->vma
+                                + bfinfdpic_got_section (info)->output_offset,
+                                R_BFIN_BYTE4_DATA, idx, ad, entry);
+
+      bfd_put_32 (output_bfd, ad,
+                 bfinfdpic_got_section (info)->contents
+                 + bfinfdpic_got_initial_offset (info)
+                 + entry->got_entry);
+    }
+
+  /* Generate relocation for GOT entry pointing to a canonical
+     function descriptor.  */
+  if (entry->fdgot_entry)
+    {
+      int reloc, idx;
+      bfd_vma ad = 0;
+
+      if (! (entry->symndx == -1
+            && entry->d.h->root.type == bfd_link_hash_undefweak
+            && BFINFDPIC_SYM_LOCAL (info, entry->d.h)))
+       {
+         /* If the symbol is dynamic and there may be dynamic symbol
+            resolution because we are, or are linked with, a shared
+            library, emit a FUNCDESC relocation such that the dynamic
+            linker will allocate the function descriptor.  If the
+            symbol needs a non-local function descriptor but binds
+            locally (e.g., its visibility is protected, emit a
+            dynamic relocation decayed to section+offset.  */
+         if (entry->symndx == -1
+             && ! BFINFDPIC_FUNCDESC_LOCAL (info, entry->d.h)
+             && BFINFDPIC_SYM_LOCAL (info, entry->d.h)
+             && !(info->executable && !info->pie))
+           {
+             reloc = R_BFIN_FUNCDESC;
+             idx = elf_section_data (entry->d.h->root.u.def.section
+                                     ->output_section)->dynindx;
+             ad = entry->d.h->root.u.def.section->output_offset
+               + entry->d.h->root.u.def.value;
+           }
+         else if (entry->symndx == -1
+                  && ! BFINFDPIC_FUNCDESC_LOCAL (info, entry->d.h))
+           {
+             reloc = R_BFIN_FUNCDESC;
+             idx = dynindx;
+             ad = addend;
+             if (ad)
+               return FALSE;
+           }
+         else
+           {
+             /* Otherwise, we know we have a private function descriptor,
+                so reference it directly.  */
+             if (elf_hash_table (info)->dynamic_sections_created)
+               BFD_ASSERT (entry->privfd);
+             reloc = R_BFIN_BYTE4_DATA;
+             idx = elf_section_data (bfinfdpic_got_section (info)
+                                     ->output_section)->dynindx;
+             ad = bfinfdpic_got_section (info)->output_offset
+               + bfinfdpic_got_initial_offset (info) + entry->fd_entry;
+           }
+
+         /* If there is room for dynamic symbol resolution, emit the
+            dynamic relocation.  However, if we're linking an
+            executable at a fixed location, we won't have emitted a
+            dynamic symbol entry for the got section, so idx will be
+            zero, which means we can and should compute the address
+            of the private descriptor ourselves.  */
+         if (info->executable && !info->pie
+             && (entry->symndx != -1
+                 || BFINFDPIC_FUNCDESC_LOCAL (info, entry->d.h)))
+           {
+             ad += bfinfdpic_got_section (info)->output_section->vma;
+             _bfinfdpic_add_rofixup (output_bfd,
+                                    bfinfdpic_gotfixup_section (info),
+                                    bfinfdpic_got_section (info)
+                                    ->output_section->vma
+                                    + bfinfdpic_got_section (info)
+                                    ->output_offset
+                                    + bfinfdpic_got_initial_offset (info)
+                                    + entry->fdgot_entry, entry);
+           }
+         else
+           _bfinfdpic_add_dyn_reloc (output_bfd,
+                                    bfinfdpic_gotrel_section (info),
+                                    _bfd_elf_section_offset
+                                    (output_bfd, info,
+                                     bfinfdpic_got_section (info),
+                                     bfinfdpic_got_initial_offset (info)
+                                     + entry->fdgot_entry)
+                                    + bfinfdpic_got_section (info)
+                                    ->output_section->vma
+                                    + bfinfdpic_got_section (info)
+                                    ->output_offset,
+                                    reloc, idx, ad, entry);
+       }
+
+      bfd_put_32 (output_bfd, ad,
+                 bfinfdpic_got_section (info)->contents
+                 + bfinfdpic_got_initial_offset (info)
+                 + entry->fdgot_entry);
+    }
+
+  /* Generate relocation to fill in a private function descriptor in
+     the GOT.  */
+  if (entry->fd_entry)
+    {
+      int idx = dynindx;
+      bfd_vma ad = addend;
+      bfd_vma ofst;
+      long lowword, highword;
+
+      /* If the symbol is dynamic but binds locally, use
+        section+offset.  */
+      if (sec && (entry->symndx != -1
+                 || BFINFDPIC_SYM_LOCAL (info, entry->d.h)))
+       {
+         if (entry->symndx == -1)
+           ad += entry->d.h->root.u.def.value;
+         else
+           ad += sym->st_value;
+         ad += sec->output_offset;
+         if (sec->output_section && elf_section_data (sec->output_section))
+           idx = elf_section_data (sec->output_section)->dynindx;
+         else
+           idx = 0;
+       }
+
+      /* If we're linking an executable at a fixed address, we can
+        omit the dynamic relocation as long as the symbol is local to
+        this module.  */
+      if (info->executable && !info->pie
+         && (entry->symndx != -1 || BFINFDPIC_SYM_LOCAL (info, entry->d.h)))
+       {
+         if (sec)
+           ad += sec->output_section->vma;
+         ofst = 0;
+         if (entry->symndx != -1
+             || entry->d.h->root.type != bfd_link_hash_undefweak)
+           {
+             _bfinfdpic_add_rofixup (output_bfd,
+                                    bfinfdpic_gotfixup_section (info),
+                                    bfinfdpic_got_section (info)
+                                    ->output_section->vma
+                                    + bfinfdpic_got_section (info)
+                                    ->output_offset
+                                    + bfinfdpic_got_initial_offset (info)
+                                    + entry->fd_entry, entry);
+             _bfinfdpic_add_rofixup (output_bfd,
+                                    bfinfdpic_gotfixup_section (info),
+                                    bfinfdpic_got_section (info)
+                                    ->output_section->vma
+                                    + bfinfdpic_got_section (info)
+                                    ->output_offset
+                                    + bfinfdpic_got_initial_offset (info)
+                                    + entry->fd_entry + 4, entry);
+           }
+       }
+      else
+       {
+         ofst
+           = _bfinfdpic_add_dyn_reloc (output_bfd,
+                                       entry->lazyplt
+                                       ? bfinfdpic_pltrel_section (info)
+                                       : bfinfdpic_gotrel_section (info),
+                                       _bfd_elf_section_offset
+                                       (output_bfd, info,
+                                        bfinfdpic_got_section (info),
+                                        bfinfdpic_got_initial_offset (info)
+                                        + entry->fd_entry)
+                                       + bfinfdpic_got_section (info)
+                                       ->output_section->vma
+                                       + bfinfdpic_got_section (info)
+                                       ->output_offset,
+                                       R_BFIN_FUNCDESC_VALUE, idx, ad, entry);
+       }
+
+      /* If we've omitted the dynamic relocation, just emit the fixed
+        addresses of the symbol and of the local GOT base offset.  */
+      if (info->executable && !info->pie && sec && sec->output_section)
+       {
+         lowword = ad;
+         highword = bfinfdpic_got_section (info)->output_section->vma
+           + bfinfdpic_got_section (info)->output_offset
+           + bfinfdpic_got_initial_offset (info);
+       }
+      else if (entry->lazyplt)
+       {
+         if (ad)
+           return FALSE;
+
+         fd_lazy_rel_offset = ofst;
+
+         /* A function descriptor used for lazy or local resolving is
+            initialized such that its high word contains the output
+            section index in which the PLT entries are located, and
+            the low word contains the address of the lazy PLT entry
+            entry point, that must be within the memory region
+            assigned to that section.  */
+         lowword = entry->lzplt_entry + 4
+           + bfinfdpic_plt_section (info)->output_offset
+           + bfinfdpic_plt_section (info)->output_section->vma;
+         highword = _bfinfdpic_osec_to_segment
+           (output_bfd, bfinfdpic_plt_section (info)->output_section);
+       }
+      else
+       {
+         /* A function descriptor for a local function gets the index
+            of the section.  For a non-local function, it's
+            disregarded.  */
+         lowword = ad;
+         if (sec == NULL
+             || (entry->symndx == -1 && entry->d.h->dynindx != -1
+                 && entry->d.h->dynindx == idx))
+           highword = 0;
+         else
+           highword = _bfinfdpic_osec_to_segment
+             (output_bfd, sec->output_section);
+       }
+
+      bfd_put_32 (output_bfd, lowword,
+                 bfinfdpic_got_section (info)->contents
+                 + bfinfdpic_got_initial_offset (info)
+                 + entry->fd_entry);
+      bfd_put_32 (output_bfd, highword,
+                 bfinfdpic_got_section (info)->contents
+                 + bfinfdpic_got_initial_offset (info)
+                 + entry->fd_entry + 4);
+    }
+
+  /* Generate code for the PLT entry.  */
+  if (entry->plt_entry != (bfd_vma) -1)
+    {
+      bfd_byte *plt_code = bfinfdpic_plt_section (info)->contents
+       + entry->plt_entry;
+
+      BFD_ASSERT (entry->fd_entry);
+
+      /* Figure out what kind of PLT entry we need, depending on the
+        location of the function descriptor within the GOT.  */
+      if (entry->fd_entry >= -(1 << (18 - 1))
+         && entry->fd_entry + 4 < (1 << (18 - 1)))
+       {
+         /* P1 = [P3 + fd_entry]; P3 = [P3 + fd_entry + 4] */
+         bfd_put_32 (output_bfd,
+                     0xe519 | ((entry->fd_entry << 14) & 0xFFFF0000),
+                     plt_code);
+         bfd_put_32 (output_bfd,
+                     0xe51b | (((entry->fd_entry + 4) << 14) & 0xFFFF0000),
+                     plt_code + 4);
+         plt_code += 8;
+       }
+      else
+       {
+         /* P1.L = fd_entry; P1.H = fd_entry;
+            P3 = P3 + P1;
+            P1 = [P3];
+            P3 = [P3 + 4];  */
+         bfd_put_32 (output_bfd,
+                     0xe109 | (entry->fd_entry << 16),
+                     plt_code);
+         bfd_put_32 (output_bfd,
+                     0xe149 | (entry->fd_entry & 0xFFFF0000),
+                     plt_code + 4);
+         bfd_put_16 (output_bfd, 0x5ad9, plt_code + 8);
+         bfd_put_16 (output_bfd, 0x9159, plt_code + 10);
+         bfd_put_16 (output_bfd, 0xac5b, plt_code + 12);
+         plt_code += 14;
+       }
+      /* JUMP (P1) */
+      bfd_put_16 (output_bfd, 0x0051, plt_code);
+    }
+
+  /* Generate code for the lazy PLT entry.  */
+  if (entry->lzplt_entry != (bfd_vma) -1)
+    {
+      bfd_byte *lzplt_code = bfinfdpic_plt_section (info)->contents
+       + entry->lzplt_entry;
+      bfd_vma resolverStub_addr;
+
+      bfd_put_32 (output_bfd, fd_lazy_rel_offset, lzplt_code);
+      lzplt_code += 4;
+
+      resolverStub_addr = entry->lzplt_entry / BFINFDPIC_LZPLT_BLOCK_SIZE
+       * BFINFDPIC_LZPLT_BLOCK_SIZE + BFINFDPIC_LZPLT_RESOLV_LOC;
+      if (resolverStub_addr >= bfinfdpic_plt_initial_offset (info))
+       resolverStub_addr = bfinfdpic_plt_initial_offset (info) - LZPLT_NORMAL_SIZE - LZPLT_RESOLVER_EXTRA;
+
+      if (entry->lzplt_entry == resolverStub_addr)
+       {
+         /* This is a lazy PLT entry that includes a resolver call.
+            P2 = [P3];
+            R3 = [P3 + 4];
+            JUMP (P2);  */
+         bfd_put_32 (output_bfd,
+                     0xa05b915a,
+                     lzplt_code);
+         bfd_put_16 (output_bfd, 0x0052, lzplt_code + 4);
+       }
+      else
+       {
+         /* JUMP.S  resolverStub */
+         bfd_put_16 (output_bfd,
+                     0x2000
+                     | (((resolverStub_addr - entry->lzplt_entry)
+                         / 2) & (((bfd_vma)1 << 12) - 1)),
+                     lzplt_code);
+       }
+    }
+
+  return TRUE;
+}
+\f
+/* Relocate an Blackfin ELF section.
+
+   The RELOCATE_SECTION function is called by the new ELF backend linker
+   to handle the relocations for a section.
+
+   The relocs are always passed as Rela structures; if the section
+   actually uses Rel structures, the r_addend field will always be
+   zero.
+
+   This function is responsible for adjusting the section contents as
+   necessary, and (if using Rela relocs and generating a relocatable
+   output file) adjusting the reloc addend as necessary.
+
+   This function does not have to worry about setting the reloc
+   address or the reloc symbol index.
+
+   LOCAL_SYMS is a pointer to the swapped in local symbols.
+
+   LOCAL_SECTIONS is an array giving the section in the input file
+   corresponding to the st_shndx field of each local symbol.
+
+   The global hash table entry for the global symbols can be found
+   via elf_sym_hashes (input_bfd).
+
+   When generating relocatable output, this function must handle
+   STB_LOCAL/STT_SECTION symbols specially.  The output symbol is
+   going to be the section symbol corresponding to the output
+   section, which means that the addend must be adjusted
+   accordingly.  */
+
+static bfd_boolean
+bfinfdpic_relocate_section (bfd * output_bfd,
+                           struct bfd_link_info *info,
+                           bfd * input_bfd,
+                           asection * input_section,
+                           bfd_byte * contents,
+                           Elf_Internal_Rela * relocs,
+                           Elf_Internal_Sym * local_syms,
+                           asection ** local_sections)
+{
+  Elf_Internal_Shdr *symtab_hdr;
+  struct elf_link_hash_entry **sym_hashes;
+  Elf_Internal_Rela *rel;
+  Elf_Internal_Rela *relend;
+  unsigned isec_segment, got_segment, plt_segment,
+    check_segment[2];
+  int silence_segment_error = !(info->shared || info->pie);
+
+  symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
+  sym_hashes = elf_sym_hashes (input_bfd);
+  relend     = relocs + input_section->reloc_count;
+
+  isec_segment = _bfinfdpic_osec_to_segment (output_bfd,
+                                            input_section->output_section);
+  if (IS_FDPIC (output_bfd) && bfinfdpic_got_section (info))
+    got_segment = _bfinfdpic_osec_to_segment (output_bfd,
+                                             bfinfdpic_got_section (info)
+                                             ->output_section);
+  else
+    got_segment = -1;
+  if (IS_FDPIC (output_bfd) && elf_hash_table (info)->dynamic_sections_created)
+    plt_segment = _bfinfdpic_osec_to_segment (output_bfd,
+                                             bfinfdpic_plt_section (info)
+                                             ->output_section);
+  else
+    plt_segment = -1;
 
-       default:
-         check_segment[0] = isec_segment;
-         check_segment[1] = sec
-           ? _bfinfdpic_osec_to_segment (output_bfd, sec->output_section)
-           : (unsigned)-1;
-         break;
+  for (rel = relocs; rel < relend; rel ++)
+    {
+      reloc_howto_type *howto;
+      unsigned long r_symndx;
+      Elf_Internal_Sym *sym;
+      asection *sec;
+      struct elf_link_hash_entry *h;
+      bfd_vma relocation;
+      bfd_reloc_status_type r;
+      const char * name = NULL;
+      int r_type;
+      asection *osec;
+      struct bfinfdpic_relocs_info *picrel;
+      bfd_vma orig_addend = rel->r_addend;
+
+      r_type = ELF32_R_TYPE (rel->r_info);
+
+      if (r_type == R_BFIN_GNU_VTINHERIT
+         || r_type == R_BFIN_GNU_VTENTRY)
+       continue;
+
+      r_symndx = ELF32_R_SYM (rel->r_info);
+      howto = bfin_reloc_type_lookup (input_bfd, r_type);
+      if (howto == NULL)
+       {
+         bfd_set_error (bfd_error_bad_value);
+         return FALSE;
        }
 
-      if (check_segment[0] != check_segment[1] && IS_FDPIC (output_bfd))
+      h      = NULL;
+      sym    = NULL;
+      sec    = NULL;
+
+      if (r_symndx < symtab_hdr->sh_info)
        {
-#if 1 /* If you take this out, remove the #error from fdpic-static-6.d
-        in the ld testsuite.  */
-         /* This helps catch problems in GCC while we can't do more
-            than static linking.  The idea is to test whether the
-            input file basename is crt0.o only once.  */
-         if (silence_segment_error == 1)
-           silence_segment_error =
-             (strlen (input_bfd->filename) == 6
-              && strcmp (input_bfd->filename, "crt0.o") == 0)
-             || (strlen (input_bfd->filename) > 6
-                 && strcmp (input_bfd->filename
-                            + strlen (input_bfd->filename) - 7,
-                            "/crt0.o") == 0)
-             ? -1 : 0;
-#endif
-         if (!silence_segment_error
-             /* We don't want duplicate errors for undefined
-                symbols.  */
-             && !(picrel && picrel->symndx == -1
-                  && picrel->d.h->root.type == bfd_link_hash_undefined))
-           info->callbacks->warning
-             (info,
-              (info->shared || info->pie)
-              ? _("relocations between different segments are not supported")
-              : _("warning: relocation references a different segment"),
-              name, input_bfd, input_section, rel->r_offset);
-         if (!silence_segment_error && (info->shared || info->pie))
-           return FALSE;
-         elf_elfheader (output_bfd)->e_flags |= EF_BFIN_PIC;
+         sym = local_syms + r_symndx;
+         osec = sec = local_sections [r_symndx];
+         relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
+
+         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;
        }
+      else
+       {
+         bfd_boolean warned;
+         bfd_boolean unresolved_reloc;
 
-      switch (r_type)
+         RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
+                                  r_symndx, symtab_hdr, sym_hashes,
+                                  h, sec, relocation,
+                                  unresolved_reloc, warned);
+         osec = sec;
+       }
+
+      if (sec != NULL && elf_discarded_section (sec))
        {
-       case R_BFIN_GOTOFFHI:
-         /* We need the addend to be applied before we shift the
-            value right.  */
-         relocation += rel->r_addend;
-         /* Fall through.  */
-       case R_BFIN_GOTHI:
-       case R_BFIN_FUNCDESC_GOTHI:
-       case R_BFIN_FUNCDESC_GOTOFFHI:
-         relocation >>= 16;
-         /* Fall through.  */
+         /* For relocs against symbols from removed linkonce sections,
+            or sections discarded by a linker script, we just want the
+            section contents zeroed.  Avoid any special processing.  */
+         _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
+         rel->r_info = 0;
+         rel->r_addend = 0;
+         continue;
+       }
 
-       case R_BFIN_GOTLO:
-       case R_BFIN_FUNCDESC_GOTLO:
-       case R_BFIN_GOTOFFLO:
-       case R_BFIN_FUNCDESC_GOTOFFLO:
-         relocation &= 0xffff;
-         break;
+      if (info->relocatable)
+       continue;
 
-       default:
-         break;
+      if (h != NULL
+         && (h->root.type == bfd_link_hash_defined
+             || h->root.type == bfd_link_hash_defweak)
+         && !BFINFDPIC_SYM_LOCAL (info, h))
+       {
+         osec = sec = NULL;
+         relocation = 0;
        }
 
       switch (r_type)
        {
-       case R_pcrel24:
-       case R_pcrel24_jump_l:
-         if (! IS_FDPIC (output_bfd) || ! picrel->plt)
-           break;
-         /* Fall through.  */
+       case R_BFIN_PCREL24:
+       case R_BFIN_PCREL24_JUMP_L:
+       case R_BFIN_BYTE4_DATA:
+         if (! IS_FDPIC (output_bfd))
+           goto non_fdpic;
 
-         /* When referencing a GOT entry, a function descriptor or a
-            PLT, we don't want the addend to apply to the reference,
-            but rather to the referenced symbol.  The actual entry
-            will have already been created taking the addend into
-            account, so cancel it out here.  */
        case R_BFIN_GOT17M4:
        case R_BFIN_GOTHI:
        case R_BFIN_GOTLO:
        case R_BFIN_FUNCDESC_GOT17M4:
        case R_BFIN_FUNCDESC_GOTHI:
        case R_BFIN_FUNCDESC_GOTLO:
+       case R_BFIN_GOTOFF17M4:
+       case R_BFIN_GOTOFFHI:
+       case R_BFIN_GOTOFFLO:
        case R_BFIN_FUNCDESC_GOTOFF17M4:
        case R_BFIN_FUNCDESC_GOTOFFHI:
        case R_BFIN_FUNCDESC_GOTOFFLO:
-         /* Note that we only want GOTOFFHI, not GOTOFFLO or GOTOFF17M4
-            here, since we do want to apply the addend to the others.
-            Note that we've applied the addend to GOTOFFHI before we
-            shifted it right.  */
-       case R_BFIN_GOTOFFHI:
-         relocation -= rel->r_addend;
-         break;
-
-       default:
-         break;
-       }
-
-      if (r_type == R_pcrel24
-         || r_type == R_pcrel24_jump_l)
-       {
-         bfd_vma x;
-         bfd_vma address = rel->r_offset;
-
-         relocation += rel->r_addend;
-
-         /* Perform usual pc-relative correction.  */
-         relocation -= input_section->output_section->vma + input_section->output_offset;
-         relocation -= address;
-
-         /* We are getting reloc_entry->address 2 byte off from
-            the start of instruction. Assuming absolute postion
-            of the reloc data. But, following code had been written assuming
-            reloc address is starting at begining of instruction.
-            To compensate that I have increased the value of
-            relocation by 1 (effectively 2) and used the addr -2 instead of addr.  */
-
-         relocation += 2;
-         address -= 2;
-
-         relocation >>= 1;
-
-         x = bfd_get_16 (input_bfd, contents + address);
-         x = (x & 0xff00) | ((relocation >> 16) & 0xff);
-         bfd_put_16 (input_bfd, x, contents + address);
-
-         x = bfd_get_16 (input_bfd, contents + address + 2);
-         x = relocation & 0xFFFF;
-         bfd_put_16 (input_bfd, x, contents + address + 2);
-         r = bfd_reloc_ok;
-       }
-      else
-       r = _bfd_final_link_relocate (howto, input_bfd, input_section,
-                                     contents, rel->r_offset,
-                                     relocation, rel->r_addend);
-
-      if (r != bfd_reloc_ok)
-       {
-         const char * msg = (const char *) NULL;
+       case R_BFIN_FUNCDESC:
+       case R_BFIN_FUNCDESC_VALUE:
+         if (h != NULL)
+           picrel = bfinfdpic_relocs_info_for_global (bfinfdpic_relocs_info
+                                                      (info), input_bfd, h,
+                                                      orig_addend, INSERT);
+         else
+           /* In order to find the entry we created before, we must
+              use the original addend, not the one that may have been
+              modified by _bfd_elf_rela_local_sym().  */
+           picrel = bfinfdpic_relocs_info_for_local (bfinfdpic_relocs_info
+                                                     (info), input_bfd, r_symndx,
+                                                     orig_addend, INSERT);
+         if (! picrel)
+           return FALSE;
 
-         switch (r)
+         if (!_bfinfdpic_emit_got_relocs_plt_entries (picrel, output_bfd, info,
+                                                      osec, sym,
+                                                      rel->r_addend))
            {
-           case bfd_reloc_overflow:
-             r = info->callbacks->reloc_overflow
-               (info, (h ? &h->root : NULL), name, howto->name,
-                (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
-             break;
-
-           case bfd_reloc_undefined:
-             r = info->callbacks->undefined_symbol
-               (info, name, input_bfd, input_section, rel->r_offset, TRUE);
-             break;
-
-           case bfd_reloc_outofrange:
-             msg = _("internal error: out of range error");
-             break;
-
-           case bfd_reloc_notsupported:
-             msg = _("internal error: unsupported relocation error");
-             break;
-
-           case bfd_reloc_dangerous:
-             msg = _("internal error: dangerous relocation");
-             break;
+             (*_bfd_error_handler)
+               (_("%B: relocation at `%A+0x%x' references symbol `%s' with nonzero addend"),
+                input_bfd, input_section, rel->r_offset, name);
+             return FALSE;
 
-           default:
-             msg = _("internal error: unknown error");
-             break;
            }
 
-         if (msg)
-           r = info->callbacks->warning
-             (info, msg, name, input_bfd, input_section, rel->r_offset);
-
-         if (! r)
-           return FALSE;
-       }
-    }
-
-  return TRUE;
-}
+         break;
 
-static bfd_boolean
-bfin_relocate_section (bfd * output_bfd,
-                      struct bfd_link_info *info,
-                      bfd * input_bfd,
-                      asection * input_section,
-                      bfd_byte * contents,
-                      Elf_Internal_Rela * relocs,
-                      Elf_Internal_Sym * local_syms,
-                      asection ** local_sections)
-{
-  bfd *dynobj;
-  Elf_Internal_Shdr *symtab_hdr;
-  struct elf_link_hash_entry **sym_hashes;
-  bfd_vma *local_got_offsets;
-  asection *sgot;
-  asection *sreloc;
-  Elf_Internal_Rela *rel;
-  Elf_Internal_Rela *relend;
-  int i = 0;
+       default:
+       non_fdpic:
+         picrel = NULL;
+         if (h && ! BFINFDPIC_SYM_LOCAL (info, h))
+           {
+             info->callbacks->warning
+               (info, _("relocation references symbol not defined in the module"),
+                name, input_bfd, input_section, rel->r_offset);
+             return FALSE;
+           }
+         break;
+       }
 
-  dynobj = elf_hash_table (info)->dynobj;
-  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
-  sym_hashes = elf_sym_hashes (input_bfd);
-  local_got_offsets = elf_local_got_offsets (input_bfd);
+      switch (r_type)
+       {
+       case R_BFIN_PCREL24:
+       case R_BFIN_PCREL24_JUMP_L:
+         check_segment[0] = isec_segment;
+         if (! IS_FDPIC (output_bfd))
+           check_segment[1] = isec_segment;
+         else if (picrel->plt)
+           {
+             relocation = bfinfdpic_plt_section (info)->output_section->vma
+               + bfinfdpic_plt_section (info)->output_offset
+               + picrel->plt_entry;
+             check_segment[1] = plt_segment;
+           }
+         /* We don't want to warn on calls to undefined weak symbols,
+            as calls to them must be protected by non-NULL tests
+            anyway, and unprotected calls would invoke undefined
+            behavior.  */
+         else if (picrel->symndx == -1
+                  && picrel->d.h->root.type == bfd_link_hash_undefweak)
+           check_segment[1] = check_segment[0];
+         else
+           check_segment[1] = sec
+             ? _bfinfdpic_osec_to_segment (output_bfd, sec->output_section)
+             : (unsigned)-1;
+         break;
 
-  sgot = NULL;
-  sreloc = NULL;
+       case R_BFIN_GOT17M4:
+       case R_BFIN_GOTHI:
+       case R_BFIN_GOTLO:
+         relocation = picrel->got_entry;
+         check_segment[0] = check_segment[1] = got_segment;
+         break;
 
-  rel = relocs;
-  relend = relocs + input_section->reloc_count;
-  for (; rel < relend; rel++, i++)
-    {
-      int r_type;
-      reloc_howto_type *howto;
-      unsigned long r_symndx;
-      struct elf_link_hash_entry *h;
-      Elf_Internal_Sym *sym;
-      asection *sec;
-      bfd_vma relocation = 0;
-      bfd_boolean unresolved_reloc;
-      bfd_reloc_status_type r;
-      bfd_vma address;
+       case R_BFIN_FUNCDESC_GOT17M4:
+       case R_BFIN_FUNCDESC_GOTHI:
+       case R_BFIN_FUNCDESC_GOTLO:
+         relocation = picrel->fdgot_entry;
+         check_segment[0] = check_segment[1] = got_segment;
+         break;
 
-      r_type = ELF32_R_TYPE (rel->r_info);
-      if (r_type < 0 || r_type >= 243)
-       {
-         bfd_set_error (bfd_error_bad_value);
-         return FALSE;
-       }
+       case R_BFIN_GOTOFFHI:
+       case R_BFIN_GOTOFF17M4:
+       case R_BFIN_GOTOFFLO:
+         relocation -= bfinfdpic_got_section (info)->output_section->vma
+           + bfinfdpic_got_section (info)->output_offset
+           + bfinfdpic_got_initial_offset (info);
+         check_segment[0] = got_segment;
+         check_segment[1] = sec
+           ? _bfinfdpic_osec_to_segment (output_bfd, sec->output_section)
+           : (unsigned)-1;
+         break;
 
-      if (r_type == R_BFIN_GNU_VTENTRY
-          || r_type == R_BFIN_GNU_VTINHERIT)
-       continue;
+       case R_BFIN_FUNCDESC_GOTOFF17M4:
+       case R_BFIN_FUNCDESC_GOTOFFHI:
+       case R_BFIN_FUNCDESC_GOTOFFLO:
+         relocation = picrel->fd_entry;
+         check_segment[0] = check_segment[1] = got_segment;
+         break;
 
-      howto = bfin_reloc_type_lookup (input_bfd, r_type);
-      if (howto == NULL)
-       {
-         bfd_set_error (bfd_error_bad_value);
-         return FALSE;
-       }
-      r_symndx = ELF32_R_SYM (rel->r_info);
+       case R_BFIN_FUNCDESC:
+         {
+           int dynindx;
+           bfd_vma addend = rel->r_addend;
 
-      h = NULL;
-      sym = NULL;
-      sec = NULL;
-      unresolved_reloc = FALSE;
+           if (! (h && h->root.type == bfd_link_hash_undefweak
+                  && BFINFDPIC_SYM_LOCAL (info, h)))
+             {
+               /* If the symbol is dynamic and there may be dynamic
+                  symbol resolution because we are or are linked with a
+                  shared library, emit a FUNCDESC relocation such that
+                  the dynamic linker will allocate the function
+                  descriptor.  If the symbol needs a non-local function
+                  descriptor but binds locally (e.g., its visibility is
+                  protected, emit a dynamic relocation decayed to
+                  section+offset.  */
+               if (h && ! BFINFDPIC_FUNCDESC_LOCAL (info, h)
+                   && BFINFDPIC_SYM_LOCAL (info, h)
+                   && !(info->executable && !info->pie))
+                 {
+                   dynindx = elf_section_data (h->root.u.def.section
+                                               ->output_section)->dynindx;
+                   addend += h->root.u.def.section->output_offset
+                     + h->root.u.def.value;
+                 }
+               else if (h && ! BFINFDPIC_FUNCDESC_LOCAL (info, h))
+                 {
+                   if (addend)
+                     {
+                       info->callbacks->warning
+                         (info, _("R_BFIN_FUNCDESC references dynamic symbol with nonzero addend"),
+                          name, input_bfd, input_section, rel->r_offset);
+                       return FALSE;
+                     }
+                   dynindx = h->dynindx;
+                 }
+               else
+                 {
+                   /* Otherwise, we know we have a private function
+                      descriptor, so reference it directly.  */
+                   BFD_ASSERT (picrel->privfd);
+                   r_type = R_BFIN_BYTE4_DATA;
+                   dynindx = elf_section_data (bfinfdpic_got_section (info)
+                                               ->output_section)->dynindx;
+                   addend = bfinfdpic_got_section (info)->output_offset
+                     + bfinfdpic_got_initial_offset (info)
+                     + picrel->fd_entry;
+                 }
 
-      if (r_symndx < symtab_hdr->sh_info)
-       {
-         sym = local_syms + r_symndx;
-         sec = local_sections[r_symndx];
-         relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
-       }
-      else
-       {
-         bfd_boolean warned;
+               /* If there is room for dynamic symbol resolution, emit
+                  the dynamic relocation.  However, if we're linking an
+                  executable at a fixed location, we won't have emitted a
+                  dynamic symbol entry for the got section, so idx will
+                  be zero, which means we can and should compute the
+                  address of the private descriptor ourselves.  */
+               if (info->executable && !info->pie
+                   && (!h || BFINFDPIC_FUNCDESC_LOCAL (info, h)))
+                 {
+                   bfd_vma offset;
 
-         RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
-                                  r_symndx, symtab_hdr, sym_hashes,
-                                  h, sec, relocation,
-                                  unresolved_reloc, warned);
-       }
+                   addend += bfinfdpic_got_section (info)->output_section->vma;
+                   if ((bfd_get_section_flags (output_bfd,
+                                               input_section->output_section)
+                        & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD))
+                     {
+                       if (_bfinfdpic_osec_readonly_p (output_bfd,
+                                                      input_section
+                                                      ->output_section))
+                         {
+                           info->callbacks->warning
+                             (info,
+                              _("cannot emit fixups in read-only section"),
+                              name, input_bfd, input_section, rel->r_offset);
+                           return FALSE;
+                         }
 
-      if (sec != NULL && elf_discarded_section (sec))
-       {
-         /* For relocs against symbols from removed linkonce sections,
-            or sections discarded by a linker script, we just want the
-            section contents zeroed.  Avoid any special processing.  */
-         _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
-         rel->r_info = 0;
-         rel->r_addend = 0;
-         continue;
-       }
+                       offset = _bfd_elf_section_offset
+                         (output_bfd, info,
+                          input_section, rel->r_offset);
+
+                       if (offset != (bfd_vma)-1)
+                         _bfinfdpic_add_rofixup (output_bfd,
+                                                 bfinfdpic_gotfixup_section
+                                                 (info),
+                                                 offset + input_section
+                                                 ->output_section->vma
+                                                 + input_section->output_offset,
+                                                 picrel);
+                     }
+                 }
+               else if ((bfd_get_section_flags (output_bfd,
+                                                input_section->output_section)
+                         & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD))
+                 {
+                   bfd_vma offset;
 
-      if (info->relocatable)
-       continue;
+                   if (_bfinfdpic_osec_readonly_p (output_bfd,
+                                                  input_section
+                                                  ->output_section))
+                     {
+                       info->callbacks->warning
+                         (info,
+                          _("cannot emit dynamic relocations in read-only section"),
+                          name, input_bfd, input_section, rel->r_offset);
+                       return FALSE;
+                     }
+                   offset = _bfd_elf_section_offset (output_bfd, info,
+                                                     input_section, rel->r_offset);
 
-      address = rel->r_offset;
+                   if (offset != (bfd_vma)-1)
+                     _bfinfdpic_add_dyn_reloc (output_bfd,
+                                               bfinfdpic_gotrel_section (info),
+                                               offset + input_section
+                                               ->output_section->vma
+                                               + input_section->output_offset,
+                                               r_type,
+                                               dynindx, addend, picrel);
+                 }
+               else
+                 addend += bfinfdpic_got_section (info)->output_section->vma;
+             }
 
-      /* Then, process normally.  */
-      switch (r_type)
-       {
-       case R_BFIN_GNU_VTINHERIT:
-       case R_BFIN_GNU_VTENTRY:
-         return bfd_reloc_ok;
+           /* We want the addend in-place because dynamic
+              relocations are REL.  Setting relocation to it should
+              arrange for it to be installed.  */
+           relocation = addend - rel->r_addend;
+         }
+         check_segment[0] = check_segment[1] = got_segment;
+         break;
 
-       case R_got:
-         /* Relocation is to the address of the entry for this symbol
-            in the global offset table.  */
-         if (h != NULL
-             && strcmp (h->root.root.string, "__GLOBAL_OFFSET_TABLE_") == 0)
-           goto do_default;
+       case R_BFIN_BYTE4_DATA:
+         if (! IS_FDPIC (output_bfd))
+           {
+             check_segment[0] = check_segment[1] = -1;
+             break;
+           }
          /* Fall through.  */
-         /* Relocation is the offset of the entry for this symbol in
-            the global offset table.  */
-
+       case R_BFIN_FUNCDESC_VALUE:
          {
-           bfd_vma off;
+           int dynindx;
+           bfd_vma addend = rel->r_addend;
+           bfd_vma offset;
+           offset = _bfd_elf_section_offset (output_bfd, info,
+                                             input_section, rel->r_offset);
 
-           if (sgot == NULL)
+           /* If the symbol is dynamic but binds locally, use
+              section+offset.  */
+           if (h && ! BFINFDPIC_SYM_LOCAL (info, h))
              {
-               sgot = bfd_get_section_by_name (dynobj, ".got");
-               BFD_ASSERT (sgot != NULL);
+               if (addend && r_type == R_BFIN_FUNCDESC_VALUE)
+                 {
+                   info->callbacks->warning
+                     (info, _("R_BFIN_FUNCDESC_VALUE references dynamic symbol with nonzero addend"),
+                      name, input_bfd, input_section, rel->r_offset);
+                   return FALSE;
+                 }
+               dynindx = h->dynindx;
              }
-
-           if (h != NULL)
+           else
              {
-               bfd_boolean dyn;
-
-               off = h->got.offset;
-               BFD_ASSERT (off != (bfd_vma) - 1);
-               dyn = elf_hash_table (info)->dynamic_sections_created;
+               if (h)
+                 addend += h->root.u.def.value;
+               else
+                 addend += sym->st_value;
+               if (osec)
+                 addend += osec->output_offset;
+               if (osec && osec->output_section
+                   && ! bfd_is_abs_section (osec->output_section)
+                   && ! bfd_is_und_section (osec->output_section))
+                 dynindx = elf_section_data (osec->output_section)->dynindx;
+               else
+                 dynindx = 0;
+             }
 
-               if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
-                   || (info->shared
-                       && (info->symbolic
-                           || h->dynindx == -1
-                           || h->forced_local)
-                       && h->def_regular))
+           /* If we're linking an executable at a fixed address, we
+              can omit the dynamic relocation as long as the symbol
+              is defined in the current link unit (which is implied
+              by its output section not being NULL).  */
+           if (info->executable && !info->pie
+               && (!h || BFINFDPIC_SYM_LOCAL (info, h)))
+             {
+               if (osec)
+                 addend += osec->output_section->vma;
+               if (IS_FDPIC (input_bfd)
+                   && (bfd_get_section_flags (output_bfd,
+                                              input_section->output_section)
+                       & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD))
                  {
-                   /* This is actually a static link, or it is a
-                      -Bsymbolic link and the symbol is defined
-                      locally, or the symbol was forced to be local
-                      because of a version file..  We must initialize
-                      this entry in the global offset table.  Since
-                      the offset must always be a multiple of 4, we
-                      use the least significant bit to record whether
-                      we have initialized it already.
-
-                      When doing a dynamic link, we create a .rela.got
-                      relocation entry to initialize the value.  This
-                      is done in the finish_dynamic_symbol routine.  */
-                   if ((off & 1) != 0)
-                     off &= ~1;
-                   else
+                   if (_bfinfdpic_osec_readonly_p (output_bfd,
+                                                  input_section
+                                                  ->output_section))
                      {
-                       bfd_put_32 (output_bfd, relocation,
-                                   sgot->contents + off);
-                       h->got.offset |= 1;
+                       info->callbacks->warning
+                         (info,
+                          _("cannot emit fixups in read-only section"),
+                          name, input_bfd, input_section, rel->r_offset);
+                       return FALSE;
+                     }
+                   if (!h || h->root.type != bfd_link_hash_undefweak)
+                     {
+                       if (offset != (bfd_vma)-1)
+                         {
+                           _bfinfdpic_add_rofixup (output_bfd,
+                                                   bfinfdpic_gotfixup_section
+                                                   (info),
+                                                   offset + input_section
+                                                   ->output_section->vma
+                                                   + input_section->output_offset,
+                                                   picrel);
+
+                           if (r_type == R_BFIN_FUNCDESC_VALUE)
+                             _bfinfdpic_add_rofixup
+                               (output_bfd,
+                                bfinfdpic_gotfixup_section (info),
+                                offset + input_section->output_section->vma
+                                + input_section->output_offset + 4, picrel);
+                         }
                      }
                  }
-               else
-                 unresolved_reloc = FALSE;
              }
            else
              {
-               BFD_ASSERT (local_got_offsets != NULL);
-               off = local_got_offsets[r_symndx];
-               BFD_ASSERT (off != (bfd_vma) - 1);
-
-               /* The offset must always be a multiple of 4.  We use
-                  the least significant bit to record whether we have
-                  already generated the necessary reloc.  */
-               if ((off & 1) != 0)
-                 off &= ~1;
-               else
+               if ((bfd_get_section_flags (output_bfd,
+                                           input_section->output_section)
+                    & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD))
                  {
-                   bfd_put_32 (output_bfd, relocation, sgot->contents + off);
-
-                   if (info->shared)
+                   if (_bfinfdpic_osec_readonly_p (output_bfd,
+                                                  input_section
+                                                  ->output_section))
                      {
-                       asection *s;
-                       Elf_Internal_Rela outrel;
-                       bfd_byte *loc;
-
-                       s = bfd_get_section_by_name (dynobj, ".rela.got");
-                       BFD_ASSERT (s != NULL);
-
-                       outrel.r_offset = (sgot->output_section->vma
-                                          + sgot->output_offset + off);
-                       outrel.r_info =
-                         ELF32_R_INFO (0, R_pcrel24);
-                       outrel.r_addend = relocation;
-                       loc = s->contents;
-                       loc +=
-                         s->reloc_count++ * sizeof (Elf32_External_Rela);
-                       bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
+                       info->callbacks->warning
+                         (info,
+                          _("cannot emit dynamic relocations in read-only section"),
+                          name, input_bfd, input_section, rel->r_offset);
+                       return FALSE;
                      }
 
-                   local_got_offsets[r_symndx] |= 1;
+                   if (offset != (bfd_vma)-1)
+                     _bfinfdpic_add_dyn_reloc (output_bfd,
+                                               bfinfdpic_gotrel_section (info),
+                                               offset
+                                               + input_section->output_section->vma
+                                               + input_section->output_offset,
+                                               r_type, dynindx, addend, picrel);
                  }
+               else if (osec)
+                 addend += osec->output_section->vma;
+               /* We want the addend in-place because dynamic
+                  relocations are REL.  Setting relocation to it
+                  should arrange for it to be installed.  */
+               relocation = addend - rel->r_addend;
              }
 
-           relocation = sgot->output_offset + off;
-           rel->r_addend = 0;
-            /* bfin : preg = [preg + 17bitdiv4offset] relocation is div by 4.  */
-            relocation /= 4;
+           if (r_type == R_BFIN_FUNCDESC_VALUE)
+             {
+               /* If we've omitted the dynamic relocation, just emit
+                  the fixed addresses of the symbol and of the local
+                  GOT base offset.  */
+               if (info->executable && !info->pie
+                   && (!h || BFINFDPIC_SYM_LOCAL (info, h)))
+                 bfd_put_32 (output_bfd,
+                             bfinfdpic_got_section (info)->output_section->vma
+                             + bfinfdpic_got_section (info)->output_offset
+                             + bfinfdpic_got_initial_offset (info),
+                             contents + rel->r_offset + 4);
+               else
+                 /* A function descriptor used for lazy or local
+                    resolving is initialized such that its high word
+                    contains the output section index in which the
+                    PLT entries are located, and the low word
+                    contains the offset of the lazy PLT entry entry
+                    point into that section.  */
+                 bfd_put_32 (output_bfd,
+                             h && ! BFINFDPIC_SYM_LOCAL (info, h)
+                             ? 0
+                             : _bfinfdpic_osec_to_segment (output_bfd,
+                                                           sec
+                                                           ->output_section),
+                             contents + rel->r_offset + 4);
+             }
          }
-         goto do_default;
-
-       case R_pcrel24:
-       case R_pcrel24_jump_l:
-         {
-           bfd_vma x;
+         check_segment[0] = check_segment[1] = got_segment;
+         break;
 
-           relocation += rel->r_addend;
+       default:
+         check_segment[0] = isec_segment;
+         check_segment[1] = sec
+           ? _bfinfdpic_osec_to_segment (output_bfd, sec->output_section)
+           : (unsigned)-1;
+         break;
+       }
 
-           /* Perform usual pc-relative correction.  */
-           relocation -= input_section->output_section->vma + input_section->output_offset;
-           relocation -= address;
+      if (check_segment[0] != check_segment[1] && IS_FDPIC (output_bfd))
+       {
+#if 1 /* If you take this out, remove the #error from fdpic-static-6.d
+        in the ld testsuite.  */
+         /* This helps catch problems in GCC while we can't do more
+            than static linking.  The idea is to test whether the
+            input file basename is crt0.o only once.  */
+         if (silence_segment_error == 1)
+           silence_segment_error =
+             (strlen (input_bfd->filename) == 6
+              && strcmp (input_bfd->filename, "crt0.o") == 0)
+             || (strlen (input_bfd->filename) > 6
+                 && strcmp (input_bfd->filename
+                            + strlen (input_bfd->filename) - 7,
+                            "/crt0.o") == 0)
+             ? -1 : 0;
+#endif
+         if (!silence_segment_error
+             /* We don't want duplicate errors for undefined
+                symbols.  */
+             && !(picrel && picrel->symndx == -1
+                  && picrel->d.h->root.type == bfd_link_hash_undefined))
+           info->callbacks->warning
+             (info,
+              (info->shared || info->pie)
+              ? _("relocations between different segments are not supported")
+              : _("warning: relocation references a different segment"),
+              name, input_bfd, input_section, rel->r_offset);
+         if (!silence_segment_error && (info->shared || info->pie))
+           return FALSE;
+         elf_elfheader (output_bfd)->e_flags |= EF_BFIN_PIC;
+       }
 
-           /* We are getting reloc_entry->address 2 byte off from
-              the start of instruction. Assuming absolute postion
-              of the reloc data. But, following code had been written assuming
-              reloc address is starting at begining of instruction.
-              To compensate that I have increased the value of
-              relocation by 1 (effectively 2) and used the addr -2 instead of addr.  */
+      switch (r_type)
+       {
+       case R_BFIN_GOTOFFHI:
+         /* We need the addend to be applied before we shift the
+            value right.  */
+         relocation += rel->r_addend;
+         /* Fall through.  */
+       case R_BFIN_GOTHI:
+       case R_BFIN_FUNCDESC_GOTHI:
+       case R_BFIN_FUNCDESC_GOTOFFHI:
+         relocation >>= 16;
+         /* Fall through.  */
 
-           relocation += 2;
-           address -= 2;
+       case R_BFIN_GOTLO:
+       case R_BFIN_FUNCDESC_GOTLO:
+       case R_BFIN_GOTOFFLO:
+       case R_BFIN_FUNCDESC_GOTOFFLO:
+         relocation &= 0xffff;
+         break;
 
-           relocation >>= 1;
+       default:
+         break;
+       }
 
-           x = bfd_get_16 (input_bfd, contents + address);
-           x = (x & 0xff00) | ((relocation >> 16) & 0xff);
-           bfd_put_16 (input_bfd, x, contents + address);
+      switch (r_type)
+       {
+       case R_BFIN_PCREL24:
+       case R_BFIN_PCREL24_JUMP_L:
+         if (! IS_FDPIC (output_bfd) || ! picrel->plt)
+           break;
+         /* Fall through.  */
 
-           x = bfd_get_16 (input_bfd, contents + address + 2);
-           x = relocation & 0xFFFF;
-           bfd_put_16 (input_bfd, x, contents + address + 2);
-           r = bfd_reloc_ok;
-         }
+         /* When referencing a GOT entry, a function descriptor or a
+            PLT, we don't want the addend to apply to the reference,
+            but rather to the referenced symbol.  The actual entry
+            will have already been created taking the addend into
+            account, so cancel it out here.  */
+       case R_BFIN_GOT17M4:
+       case R_BFIN_GOTHI:
+       case R_BFIN_GOTLO:
+       case R_BFIN_FUNCDESC_GOT17M4:
+       case R_BFIN_FUNCDESC_GOTHI:
+       case R_BFIN_FUNCDESC_GOTLO:
+       case R_BFIN_FUNCDESC_GOTOFF17M4:
+       case R_BFIN_FUNCDESC_GOTOFFHI:
+       case R_BFIN_FUNCDESC_GOTOFFLO:
+         /* Note that we only want GOTOFFHI, not GOTOFFLO or GOTOFF17M4
+            here, since we do want to apply the addend to the others.
+            Note that we've applied the addend to GOTOFFHI before we
+            shifted it right.  */
+       case R_BFIN_GOTOFFHI:
+         relocation -= rel->r_addend;
          break;
 
        default:
-       do_default:
-         r = _bfd_final_link_relocate (howto, input_bfd, input_section,
-                                       contents, address,
-                                       relocation, rel->r_addend);
-
          break;
        }
 
-      /* Dynamic relocs are not propagated for SEC_DEBUGGING sections
-         because such sections are not SEC_ALLOC and thus ld.so will
-         not process them.  */
-      if (unresolved_reloc
-         && !((input_section->flags & SEC_DEBUGGING) != 0 && h->def_dynamic))
-       {
-         (*_bfd_error_handler)
-           (_("%B(%A+0x%lx): unresolvable relocation against symbol `%s'"),
-            input_bfd,
-            input_section, (long) rel->r_offset, h->root.root.string);
-         return FALSE;
-       }
+      r = bfin_final_link_relocate (rel, howto, input_bfd, input_section,
+                                   contents, rel->r_offset,
+                                   relocation, rel->r_addend);
 
       if (r != bfd_reloc_ok)
        {
-         const char *name;
+         const char * msg = (const char *) NULL;
 
-         if (h != NULL)
-           name = h->root.root.string;
-         else
+         switch (r)
            {
-             name = bfd_elf_string_from_elf_section (input_bfd,
-                                                     symtab_hdr->sh_link,
-                                                     sym->st_name);
-             if (name == NULL)
-               return FALSE;
-             if (*name == '\0')
-               name = bfd_section_name (input_bfd, sec);
-           }
+           case bfd_reloc_overflow:
+             r = info->callbacks->reloc_overflow
+               (info, (h ? &h->root : NULL), name, howto->name,
+                (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
+             break;
 
-         if (r == bfd_reloc_overflow)
-           {
-             if (!(info->callbacks->reloc_overflow
-                   (info, (h ? &h->root : NULL), name, howto->name,
-                    (bfd_vma) 0, input_bfd, input_section, rel->r_offset)))
-               return FALSE;
-           }
-         else
-           {
-             (*_bfd_error_handler)
-               (_("%B(%A+0x%lx): reloc against `%s': error %d"),
-                input_bfd, input_section,
-                (long) rel->r_offset, name, (int) r);
-             return FALSE;
+           case bfd_reloc_undefined:
+             r = info->callbacks->undefined_symbol
+               (info, name, input_bfd, input_section, rel->r_offset, TRUE);
+             break;
+
+           case bfd_reloc_outofrange:
+             msg = _("internal error: out of range error");
+             break;
+
+           case bfd_reloc_notsupported:
+             msg = _("internal error: unsupported relocation error");
+             break;
+
+           case bfd_reloc_dangerous:
+             msg = _("internal error: dangerous relocation");
+             break;
+
+           default:
+             msg = _("internal error: unknown error");
+             break;
            }
+
+         if (msg)
+           r = info->callbacks->warning
+             (info, msg, name, input_bfd, input_section, rel->r_offset);
+
+         if (! r)
+           return FALSE;
        }
     }
 
   return TRUE;
 }
 
-static asection *
-bfin_gc_mark_hook (asection * sec,
-                  struct bfd_link_info *info,
-                  Elf_Internal_Rela * rel,
-                  struct elf_link_hash_entry *h,
-                   Elf_Internal_Sym * sym)
-{
-  if (h != NULL)
-    switch (ELF32_R_TYPE (rel->r_info))
-      {
-      case R_BFIN_GNU_VTINHERIT:
-      case R_BFIN_GNU_VTENTRY:
-       return NULL;
-      }
-
-  return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
-}
-
-/* Update the got entry reference counts for the section being removed.  */
+/* Update the relocation information for the relocations of the section
+   being removed.  */
 
 static bfd_boolean
-bfin_gc_sweep_hook (bfd * abfd,
-                   struct bfd_link_info *info,
-                   asection * sec,
-                    const Elf_Internal_Rela * relocs)
+bfinfdpic_gc_sweep_hook (bfd *abfd,
+                        struct bfd_link_info *info,
+                        asection *sec,
+                        const Elf_Internal_Rela *relocs)
 {
   Elf_Internal_Shdr *symtab_hdr;
-  struct elf_link_hash_entry **sym_hashes;
-  bfd_signed_vma *local_got_refcounts;
-  const Elf_Internal_Rela *rel, *relend;
-  bfd *dynobj;
-  asection *sgot;
-  asection *srelgot;
+  struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
+  const Elf_Internal_Rela *rel;
+  const Elf_Internal_Rela *rel_end;
+  struct bfinfdpic_relocs_info *picrel;
 
-  dynobj = elf_hash_table (info)->dynobj;
-  if (dynobj == NULL)
-    return TRUE;
+  BFD_ASSERT (IS_FDPIC (abfd));
 
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
   sym_hashes = elf_sym_hashes (abfd);
-  local_got_refcounts = elf_local_got_refcounts (abfd);
-
-  sgot = bfd_get_section_by_name (dynobj, ".got");
-  srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+  sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof(Elf32_External_Sym);
+  if (!elf_bad_symtab (abfd))
+    sym_hashes_end -= symtab_hdr->sh_info;
 
-  relend = relocs + sec->reloc_count;
-  for (rel = relocs; rel < relend; rel++)
+  rel_end = relocs + sec->reloc_count;
+  for (rel = relocs; rel < rel_end; rel++)
     {
-      unsigned long r_symndx;
       struct elf_link_hash_entry *h;
+      unsigned long r_symndx;
+
+      r_symndx = ELF32_R_SYM (rel->r_info);
+      if (r_symndx < symtab_hdr->sh_info)
+        h = NULL;
+      else
+        h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+
+      if (h != NULL)
+       picrel = bfinfdpic_relocs_info_for_global (bfinfdpic_relocs_info (info),
+                                                  abfd, h,
+                                                  rel->r_addend, NO_INSERT);
+      else
+       picrel = bfinfdpic_relocs_info_for_local (bfinfdpic_relocs_info
+                                                 (info), abfd, r_symndx,
+                                                 rel->r_addend, NO_INSERT);
+
+      if (!picrel)
+       return TRUE;
 
       switch (ELF32_R_TYPE (rel->r_info))
-       {
-       case R_got:
-         r_symndx = ELF32_R_SYM (rel->r_info);
-         if (r_symndx >= symtab_hdr->sh_info)
-           {
-             h = sym_hashes[r_symndx - symtab_hdr->sh_info];
-             if (h->got.refcount > 0)
-               {
-                 --h->got.refcount;
-                 if (h->got.refcount == 0)
-                   {
-                     /* We don't need the .got entry any more.  */
-                     sgot->size -= 4;
-                     srelgot->size -= sizeof (Elf32_External_Rela);
-                   }
-               }
-           }
-         else if (local_got_refcounts != NULL)
-           {
-             if (local_got_refcounts[r_symndx] > 0)
-               {
-                 --local_got_refcounts[r_symndx];
-                 if (local_got_refcounts[r_symndx] == 0)
-                   {
-                     /* We don't need the .got entry any more.  */
-                     sgot->size -= 4;
-                     if (info->shared)
-                       srelgot->size -= sizeof (Elf32_External_Rela);
-                   }
-               }
-           }
+        {
+       case R_BFIN_PCREL24:
+       case R_BFIN_PCREL24_JUMP_L:
+         picrel->call--;
+         break;
+
+       case R_BFIN_FUNCDESC_VALUE:
+         picrel->relocsfdv--;
+         if (bfd_get_section_flags (abfd, sec) & SEC_ALLOC)
+           picrel->relocs32++;
+         /* Fall through.  */
+
+       case R_BFIN_BYTE4_DATA:
+         picrel->sym--;
+         if (bfd_get_section_flags (abfd, sec) & SEC_ALLOC)
+           picrel->relocs32--;
+         break;
+
+       case R_BFIN_GOT17M4:
+         picrel->got17m4--;
+         break;
+
+       case R_BFIN_GOTHI:
+       case R_BFIN_GOTLO:
+         picrel->gothilo--;
+         break;
+
+       case R_BFIN_FUNCDESC_GOT17M4:
+         picrel->fdgot17m4--;
+         break;
+
+       case R_BFIN_FUNCDESC_GOTHI:
+       case R_BFIN_FUNCDESC_GOTLO:
+         picrel->fdgothilo--;
+         break;
+
+       case R_BFIN_GOTOFF17M4:
+       case R_BFIN_GOTOFFHI:
+       case R_BFIN_GOTOFFLO:
+         picrel->gotoff--;
+         break;
+
+       case R_BFIN_FUNCDESC_GOTOFF17M4:
+         picrel->fdgoff17m4--;
+         break;
+
+       case R_BFIN_FUNCDESC_GOTOFFHI:
+       case R_BFIN_FUNCDESC_GOTOFFLO:
+         picrel->fdgoffhilo--;
+         break;
+
+       case R_BFIN_FUNCDESC:
+         picrel->fd--;
+         picrel->relocsfd--;
          break;
+
        default:
          break;
-       }
+        }
     }
+
   return TRUE;
 }
 
@@ -3219,9 +3345,8 @@ bfin_gc_sweep_hook (bfd * abfd,
    relocate independently.  */
 static bfd_boolean
 _bfinfdpic_link_omit_section_dynsym (bfd *output_bfd ATTRIBUTE_UNUSED,
-                                   struct bfd_link_info *info
-                                   ATTRIBUTE_UNUSED,
-                                   asection *p ATTRIBUTE_UNUSED)
+                                   struct bfd_link_info *info ATTRIBUTE_UNUSED,
+                                   asection *p)
 {
   switch (elf_section_data (p)->this_hdr.sh_type)
     {
@@ -3338,28 +3463,7 @@ _bfin_create_got_section (bfd *abfd, struct bfd_link_info *info)
       flags = BSF_GLOBAL | BSF_WEAK;
     }
 
-  return TRUE;
-}
-
-/* Make sure the got and plt sections exist, and that our pointers in
-   the link hash table point to them.  */
-
-static bfd_boolean
-elf32_bfinfdpic_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
-{
-  /* This is mostly copied from
-     elflink.c:_bfd_elf_create_dynamic_sections().  */
-  flagword flags, pltflags;
-  asection *s;
-  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
-
-  /* We need to create .plt, .rel[a].plt, .got, .got.plt, .dynbss, and
-     .rel[a].bss sections.  */
-
-  flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
-          | SEC_LINKER_CREATED);
-
-  pltflags = flags;
+  flags = pltflags;
   pltflags |= SEC_CODE;
   if (bed->plt_not_loaded)
     pltflags &= ~ (SEC_CODE | SEC_LOAD | SEC_HAS_CONTENTS);
@@ -3388,18 +3492,39 @@ elf32_bfinfdpic_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
       h->def_regular = 1;
       h->type = STT_OBJECT;
 
-      if (! info->executable
-         && ! bfd_elf_link_record_dynamic_symbol (info, h))
-       return FALSE;
-    }
+      if (! info->executable
+         && ! bfd_elf_link_record_dynamic_symbol (info, h))
+       return FALSE;
+    }
+
+  /* Blackfin-specific: we want rel relocations for the plt.  */
+  s = bfd_make_section_with_flags (abfd, ".rel.plt", flags | SEC_READONLY);
+  if (s == NULL
+      || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
+    return FALSE;
+  /* Blackfin-specific: remember it.  */
+  bfinfdpic_pltrel_section (info) = s;
+
+  return TRUE;
+}
+
+/* Make sure the got and plt sections exist, and that our pointers in
+   the link hash table point to them.  */
+
+static bfd_boolean
+elf32_bfinfdpic_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
+{
+  /* This is mostly copied from
+     elflink.c:_bfd_elf_create_dynamic_sections().  */
+  flagword flags;
+  asection *s;
+  const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+
+  flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+          | SEC_LINKER_CREATED);
 
-  /* Blackfin-specific: we want rel relocations for the plt.  */
-  s = bfd_make_section_with_flags (abfd, ".rel.plt", flags | SEC_READONLY);
-  if (s == NULL
-      || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
-    return FALSE;
-  /* Blackfin-specific: remember it.  */
-  bfinfdpic_pltrel_section (info) = s;
+  /* We need to create .plt, .rel[a].plt, .got, .got.plt, .dynbss, and
+     .rel[a].bss sections.  */
 
   /* Blackfin-specific: we want to create the GOT in the Blackfin way.  */
   if (! _bfin_create_got_section (abfd, info))
@@ -3438,8 +3563,7 @@ elf32_bfinfdpic_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
       if (! info->shared)
        {
          s = bfd_make_section_with_flags (abfd,
-                                          (bed->default_use_rela_p
-                                           ? ".rela.bss" : ".rel.bss"),
+                                          ".rela.bss",
                                           flags | SEC_READONLY);
          if (s == NULL
              || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
@@ -3450,49 +3574,15 @@ elf32_bfinfdpic_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
   return TRUE;
 }
 
-/* The name of the dynamic interpreter.  This is put in the .interp
-   section.  */
-
-#define ELF_DYNAMIC_INTERPRETER "/lib/ld.so.1"
-
-#define DEFAULT_STACK_SIZE 0x20000
-
-/* This structure is used to collect the number of entries present in
-   each addressable range of the got.  */
-struct _bfinfdpic_dynamic_got_info
-{
-  /* Several bits of information about the current link.  */
-  struct bfd_link_info *info;
-  /* Total size needed for GOT entries within the 18- or 32-bit
-     ranges.  */
-  bfd_vma got17m4, gothilo;
-  /* Total size needed for function descriptor entries within the 18-
-     or 32-bit ranges.  */
-  bfd_vma fd17m4, fdhilo;
-  /* Total size needed function descriptor entries referenced in PLT
-     entries, that would be profitable to place in offsets close to
-     the PIC register.  */
-  bfd_vma fdplt;
-  /* Total size needed by lazy PLT entries.  */
-  bfd_vma lzplt;
-  /* Number of relocations carried over from input object files.  */
-  unsigned long relocs;
-  /* Number of fixups introduced by relocations in input object files.  */
-  unsigned long fixups;
-};
-
 /* Compute the total GOT size required by each symbol in each range.
    Symbols may require up to 4 words in the GOT: an entry pointing to
    the symbol, an entry pointing to its function descriptor, and a
    private function descriptors taking two words.  */
 
-static int
-_bfinfdpic_count_got_plt_entries (void **entryp, void *dinfo_)
+static void
+_bfinfdpic_count_nontls_entries (struct bfinfdpic_relocs_info *entry,
+                                struct _bfinfdpic_dynamic_got_info *dinfo)
 {
-  struct bfinfdpic_relocs_info *entry = *entryp;
-  struct _bfinfdpic_dynamic_got_info *dinfo = dinfo_;
-  unsigned relocs = 0, fixups = 0;
-
   /* Allocate space for a GOT entry pointing to the symbol.  */
   if (entry->got17m4)
     dinfo->got17m4 += 4;
@@ -3540,6 +3630,18 @@ _bfinfdpic_count_got_plt_entries (void **entryp, void *dinfo_)
 
   if (entry->lazyplt)
     dinfo->lzplt += LZPLT_NORMAL_SIZE;
+}
+
+/* Compute the number of dynamic relocations and fixups that a symbol
+   requires, and add (or subtract) from the grand and per-symbol
+   totals.  */
+
+static void
+_bfinfdpic_count_relocs_fixups (struct bfinfdpic_relocs_info *entry,
+                               struct _bfinfdpic_dynamic_got_info *dinfo,
+                               bfd_boolean subtract)
+{
+  bfd_vma relocs = 0, fixups = 0;
 
   if (!dinfo->info->executable || dinfo->info->pie)
     relocs = entry->relocs32 + entry->relocsfd + entry->relocsfdv;
@@ -3565,10 +3667,32 @@ _bfinfdpic_count_got_plt_entries (void **entryp, void *dinfo_)
        relocs += entry->relocsfd;
     }
 
+  if (subtract)
+    {
+      relocs = - relocs;
+      fixups = - fixups;
+    }
+
   entry->dynrelocs += relocs;
   entry->fixups += fixups;
   dinfo->relocs += relocs;
   dinfo->fixups += fixups;
+}
+
+/* Compute the total GOT and PLT size required by each symbol in each range. *
+   Symbols may require up to 4 words in the GOT: an entry pointing to
+   the symbol, an entry pointing to its function descriptor, and a
+   private function descriptors taking two words.  */
+
+static int
+_bfinfdpic_count_got_plt_entries (void **entryp, void *dinfo_)
+{
+  struct bfinfdpic_relocs_info *entry = *entryp;
+  struct _bfinfdpic_dynamic_got_info *dinfo = dinfo_;
+
+  _bfinfdpic_count_nontls_entries (entry, dinfo);
+
+  _bfinfdpic_count_relocs_fixups (entry, dinfo, FALSE);
 
   return 1;
 }
@@ -3864,6 +3988,23 @@ _bfinfdpic_assign_plt_entries (void **entryp, void *info_)
   return 1;
 }
 
+/* Cancel out any effects of calling _bfinfdpic_assign_got_entries and
+   _bfinfdpic_assign_plt_entries.  */
+
+static int
+_bfinfdpic_reset_got_plt_entries (void **entryp, void *ignore ATTRIBUTE_UNUSED)
+{
+  struct bfinfdpic_relocs_info *entry = *entryp;
+
+  entry->got_entry = 0;
+  entry->fdgot_entry = 0;
+  entry->fd_entry = 0;
+  entry->plt_entry = (bfd_vma)-1;
+  entry->lzplt_entry = (bfd_vma)-1;
+
+  return 1;
+}
+
 /* Follow indirect and warning hash entries so that each got entry
    points to the final symbol definition.  P must point to a pointer
    to the hash table we're traversing.  Since this traversal may
@@ -3920,89 +4061,62 @@ _bfinfdpic_resolve_final_relocs_info (void **entryp, void *p)
   return 1;
 }
 
-/* Set the sizes of the dynamic sections.  */
+/* Compute the total size of the GOT, the PLT, the dynamic relocations
+   section and the rofixup section.  Assign locations for GOT and PLT
+   entries.  */
 
 static bfd_boolean
-elf32_bfinfdpic_size_dynamic_sections (bfd *output_bfd,
-                                     struct bfd_link_info *info)
+_bfinfdpic_size_got_plt (bfd *output_bfd,
+                        struct _bfinfdpic_dynamic_got_plt_info *gpinfop)
 {
-  bfd *dynobj;
-  asection *s;
-  struct _bfinfdpic_dynamic_got_plt_info gpinfo;
   bfd_signed_vma odd;
   bfd_vma limit;
+  struct bfd_link_info *info = gpinfop->g.info;
+  bfd *dynobj = elf_hash_table (info)->dynobj;
 
-  dynobj = elf_hash_table (info)->dynobj;
-  BFD_ASSERT (dynobj != NULL);
-
-  if (elf_hash_table (info)->dynamic_sections_created)
-    {
-      /* Set the contents of the .interp section to the interpreter.  */
-      if (info->executable)
-       {
-         s = bfd_get_section_by_name (dynobj, ".interp");
-         BFD_ASSERT (s != NULL);
-         s->size = sizeof ELF_DYNAMIC_INTERPRETER;
-         s->contents = (bfd_byte *) ELF_DYNAMIC_INTERPRETER;
-       }
-    }
-
-  memset (&gpinfo, 0, sizeof (gpinfo));
-  gpinfo.g.info = info;
-
-  for (;;)
-    {
-      htab_t relocs = bfinfdpic_relocs_info (info);
-
-      htab_traverse (relocs, _bfinfdpic_resolve_final_relocs_info, &relocs);
-
-      if (relocs == bfinfdpic_relocs_info (info))
-       break;
-    }
-
-  htab_traverse (bfinfdpic_relocs_info (info), _bfinfdpic_count_got_plt_entries,
-                &gpinfo.g);
+  memcpy (bfinfdpic_dynamic_got_plt_info (info), &gpinfop->g,
+         sizeof (gpinfop->g));
 
   odd = 12;
   /* Compute the total size taken by entries in the 18-bit range,
      to tell how many PLT function descriptors we can bring into it
      without causing it to overflow.  */
-  limit = odd + gpinfo.g.got17m4 + gpinfo.g.fd17m4;
+  limit = odd + gpinfop->g.got17m4 + gpinfop->g.fd17m4;
   if (limit < (bfd_vma)1 << 18)
     limit = ((bfd_vma)1 << 18) - limit;
   else
     limit = 0;
-  if (gpinfo.g.fdplt < limit)
-    limit = gpinfo.g.fdplt;
+  if (gpinfop->g.fdplt < limit)
+    limit = gpinfop->g.fdplt;
 
   /* Determine the ranges of GOT offsets that we can use for each
      range of addressing modes.  */
-  odd = _bfinfdpic_compute_got_alloc_data (&gpinfo.got17m4,
+  odd = _bfinfdpic_compute_got_alloc_data (&gpinfop->got17m4,
                                          0,
                                          odd,
                                          16,
-                                         gpinfo.g.got17m4,
-                                         gpinfo.g.fd17m4,
+                                         gpinfop->g.got17m4,
+                                         gpinfop->g.fd17m4,
                                          limit,
                                          (bfd_vma)1 << (18-1));
-  odd = _bfinfdpic_compute_got_alloc_data (&gpinfo.gothilo,
-                                         gpinfo.got17m4.min,
+  odd = _bfinfdpic_compute_got_alloc_data (&gpinfop->gothilo,
+                                         gpinfop->got17m4.min,
                                          odd,
-                                         gpinfo.got17m4.max,
-                                         gpinfo.g.gothilo,
-                                         gpinfo.g.fdhilo,
-                                         gpinfo.g.fdplt - gpinfo.got17m4.fdplt,
+                                         gpinfop->got17m4.max,
+                                         gpinfop->g.gothilo,
+                                         gpinfop->g.fdhilo,
+                                         gpinfop->g.fdplt - gpinfop->got17m4.fdplt,
                                          (bfd_vma)1 << (32-1));
 
   /* Now assign (most) GOT offsets.  */
   htab_traverse (bfinfdpic_relocs_info (info), _bfinfdpic_assign_got_entries,
-                &gpinfo);
+                gpinfop);
 
-  bfinfdpic_got_section (info)->size = gpinfo.gothilo.max
-    - gpinfo.gothilo.min
+  bfinfdpic_got_section (info)->size = gpinfop->gothilo.max
+    - gpinfop->gothilo.min
     /* If an odd word is the last word of the GOT, we don't need this
        word to be part of the GOT.  */
-    - (odd + 4 == gpinfo.gothilo.max ? 4 : 0);
+    - (odd + 4 == gpinfop->gothilo.max ? 4 : 0);
   if (bfinfdpic_got_section (info)->size == 0)
     bfinfdpic_got_section (info)->flags |= SEC_EXCLUDE;
   else if (bfinfdpic_got_section (info)->size == 12
@@ -4024,10 +4138,10 @@ elf32_bfinfdpic_size_dynamic_sections (bfd *output_bfd,
     /* Subtract the number of lzplt entries, since those will generate
        relocations in the pltrel section.  */
     bfinfdpic_gotrel_section (info)->size =
-      (gpinfo.g.relocs - gpinfo.g.lzplt / LZPLT_NORMAL_SIZE)
+      (gpinfop->g.relocs - gpinfop->g.lzplt / LZPLT_NORMAL_SIZE)
       * get_elf_backend_data (output_bfd)->s->sizeof_rel;
   else
-    BFD_ASSERT (gpinfo.g.relocs == 0);
+    BFD_ASSERT (gpinfop->g.relocs == 0);
   if (bfinfdpic_gotrel_section (info)->size == 0)
     bfinfdpic_gotrel_section (info)->flags |= SEC_EXCLUDE;
   else
@@ -4039,7 +4153,7 @@ elf32_bfinfdpic_size_dynamic_sections (bfd *output_bfd,
        return FALSE;
     }
 
-  bfinfdpic_gotfixup_section (info)->size = (gpinfo.g.fixups + 1) * 4;
+  bfinfdpic_gotfixup_section (info)->size = (gpinfop->g.fixups + 1) * 4;
   if (bfinfdpic_gotfixup_section (info)->size == 0)
     bfinfdpic_gotfixup_section (info)->flags |= SEC_EXCLUDE;
   else
@@ -4052,19 +4166,17 @@ elf32_bfinfdpic_size_dynamic_sections (bfd *output_bfd,
     }
 
   if (elf_hash_table (info)->dynamic_sections_created)
+    bfinfdpic_pltrel_section (info)->size =
+      gpinfop->g.lzplt / LZPLT_NORMAL_SIZE * get_elf_backend_data (output_bfd)->s->sizeof_rel;
+  if (bfinfdpic_pltrel_section (info)->size == 0)
+    bfinfdpic_pltrel_section (info)->flags |= SEC_EXCLUDE;
+  else
     {
-      bfinfdpic_pltrel_section (info)->size =
-       gpinfo.g.lzplt / LZPLT_NORMAL_SIZE * get_elf_backend_data (output_bfd)->s->sizeof_rel;
-      if (bfinfdpic_pltrel_section (info)->size == 0)
-       bfinfdpic_pltrel_section (info)->flags |= SEC_EXCLUDE;
-      else
-       {
-         bfinfdpic_pltrel_section (info)->contents =
-           (bfd_byte *) bfd_zalloc (dynobj,
-                                    bfinfdpic_pltrel_section (info)->size);
-         if (bfinfdpic_pltrel_section (info)->contents == NULL)
-           return FALSE;
-       }
+      bfinfdpic_pltrel_section (info)->contents =
+       (bfd_byte *) bfd_zalloc (dynobj,
+                                bfinfdpic_pltrel_section (info)->size);
+      if (bfinfdpic_pltrel_section (info)->contents == NULL)
+       return FALSE;
     }
 
   /* Add 4 bytes for every block of at most 65535 lazy PLT entries,
@@ -4074,47 +4186,97 @@ elf32_bfinfdpic_size_dynamic_sections (bfd *output_bfd,
      block size.  */
   if (elf_hash_table (info)->dynamic_sections_created)
     {
-      bfinfdpic_plt_section (info)->size = gpinfo.g.lzplt
-       + ((gpinfo.g.lzplt + (BFINFDPIC_LZPLT_BLOCK_SIZE - 4) - LZPLT_NORMAL_SIZE)
+      bfinfdpic_plt_section (info)->size = gpinfop->g.lzplt
+       + ((gpinfop->g.lzplt + (BFINFDPIC_LZPLT_BLOCK_SIZE - 4) - LZPLT_NORMAL_SIZE)
           / (BFINFDPIC_LZPLT_BLOCK_SIZE - 4) * LZPLT_RESOLVER_EXTRA);
     }
 
   /* Reset it, such that _bfinfdpic_assign_plt_entries() can use it to
      actually assign lazy PLT entries addresses.  */
-  gpinfo.g.lzplt = 0;
+  gpinfop->g.lzplt = 0;
 
   /* Save information that we're going to need to generate GOT and PLT
      entries.  */
-  bfinfdpic_got_initial_offset (info) = -gpinfo.gothilo.min;
+  bfinfdpic_got_initial_offset (info) = -gpinfop->gothilo.min;
 
   if (get_elf_backend_data (output_bfd)->want_got_sym)
     elf_hash_table (info)->hgot->root.u.def.value
-      += bfinfdpic_got_initial_offset (info);
+      = bfinfdpic_got_initial_offset (info);
 
   if (elf_hash_table (info)->dynamic_sections_created)
     bfinfdpic_plt_initial_offset (info) =
       bfinfdpic_plt_section (info)->size;
 
   htab_traverse (bfinfdpic_relocs_info (info), _bfinfdpic_assign_plt_entries,
-                &gpinfo);
+                gpinfop);
 
   /* Allocate the PLT section contents only after
      _bfinfdpic_assign_plt_entries has a chance to add the size of the
      non-lazy PLT entries.  */
-  if (elf_hash_table (info)->dynamic_sections_created)
+  if (bfinfdpic_plt_section (info)->size == 0)
+    bfinfdpic_plt_section (info)->flags |= SEC_EXCLUDE;
+  else
     {
-      if (bfinfdpic_plt_section (info)->size == 0)
-       bfinfdpic_plt_section (info)->flags |= SEC_EXCLUDE;
-      else
+      bfinfdpic_plt_section (info)->contents =
+       (bfd_byte *) bfd_zalloc (dynobj,
+                                bfinfdpic_plt_section (info)->size);
+      if (bfinfdpic_plt_section (info)->contents == NULL)
+       return FALSE;
+    }
+
+  return TRUE;
+}
+
+/* Set the sizes of the dynamic sections.  */
+
+static bfd_boolean
+elf32_bfinfdpic_size_dynamic_sections (bfd *output_bfd,
+                                     struct bfd_link_info *info)
+{
+  struct elf_link_hash_table *htab;
+  bfd *dynobj;
+  asection *s;
+  struct _bfinfdpic_dynamic_got_plt_info gpinfo;
+
+  htab = elf_hash_table (info);
+  dynobj = htab->dynobj;
+  BFD_ASSERT (dynobj != NULL);
+
+  if (htab->dynamic_sections_created)
+    {
+      /* Set the contents of the .interp section to the interpreter.  */
+      if (info->executable)
        {
-         bfinfdpic_plt_section (info)->contents =
-           (bfd_byte *) bfd_zalloc (dynobj,
-                                    bfinfdpic_plt_section (info)->size);
-         if (bfinfdpic_plt_section (info)->contents == NULL)
-           return FALSE;
+         s = bfd_get_section_by_name (dynobj, ".interp");
+         BFD_ASSERT (s != NULL);
+         s->size = sizeof ELF_DYNAMIC_INTERPRETER;
+         s->contents = (bfd_byte *) ELF_DYNAMIC_INTERPRETER;
        }
     }
 
+  memset (&gpinfo, 0, sizeof (gpinfo));
+  gpinfo.g.info = info;
+
+  for (;;)
+    {
+      htab_t relocs = bfinfdpic_relocs_info (info);
+
+      htab_traverse (relocs, _bfinfdpic_resolve_final_relocs_info, &relocs);
+
+      if (relocs == bfinfdpic_relocs_info (info))
+       break;
+    }
+
+  htab_traverse (bfinfdpic_relocs_info (info), _bfinfdpic_count_got_plt_entries,
+                &gpinfo.g);
+
+  /* Allocate space to save the summary information, we're going to
+     use it if we're doing relaxations.  */
+  bfinfdpic_dynamic_got_plt_info (info) = bfd_alloc (dynobj, sizeof (gpinfo.g));
+
+  if (!_bfinfdpic_size_got_plt (output_bfd, &gpinfo))
+      return FALSE;
+
   if (elf_hash_table (info)->dynamic_sections_created)
     {
       if (bfinfdpic_got_section (info)->size)
@@ -4135,6 +4297,14 @@ elf32_bfinfdpic_size_dynamic_sections (bfd *output_bfd,
          return FALSE;
     }
 
+  s = bfd_get_section_by_name (dynobj, ".dynbss");
+  if (s && s->size == 0)
+    s->flags |= SEC_EXCLUDE;
+
+  s = bfd_get_section_by_name (dynobj, ".rela.bss");
+  if (s && s->size == 0)
+    s->flags |= SEC_EXCLUDE;
+
   return TRUE;
 }
 
@@ -4175,6 +4345,122 @@ elf32_bfinfdpic_always_size_sections (bfd *output_bfd,
   return TRUE;
 }
 
+/* Check whether any of the relocations was optimized away, and
+   subtract it from the relocation or fixup count.  */
+static bfd_boolean
+_bfinfdpic_check_discarded_relocs (bfd *abfd, asection *sec,
+                                 struct bfd_link_info *info,
+                                 
+                                 bfd_boolean *changed)
+{
+  Elf_Internal_Shdr *symtab_hdr;
+  struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
+  Elf_Internal_Rela *rel, *erel;
+
+  if ((sec->flags & SEC_RELOC) == 0
+      || sec->reloc_count == 0)
+    return TRUE;
+
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  sym_hashes = elf_sym_hashes (abfd);
+  sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof(Elf32_External_Sym);
+  if (!elf_bad_symtab (abfd))
+    sym_hashes_end -= symtab_hdr->sh_info;
+
+  rel = elf_section_data (sec)->relocs;
+
+  /* Now examine each relocation.  */
+  for (erel = rel + sec->reloc_count; rel < erel; rel++)
+    {
+      struct elf_link_hash_entry *h;
+      unsigned long r_symndx;
+      struct bfinfdpic_relocs_info *picrel;
+      struct _bfinfdpic_dynamic_got_info *dinfo;
+
+      if (ELF32_R_TYPE (rel->r_info) != R_BFIN_BYTE4_DATA
+         && ELF32_R_TYPE (rel->r_info) != R_BFIN_FUNCDESC)
+       continue;
+
+      if (_bfd_elf_section_offset (sec->output_section->owner,
+                                  info, sec, rel->r_offset)
+         != (bfd_vma)-1)
+       continue;
+
+      r_symndx = ELF32_R_SYM (rel->r_info);
+      if (r_symndx < symtab_hdr->sh_info)
+       h = NULL;
+      else
+       {
+         h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+         while (h->root.type == bfd_link_hash_indirect
+                || h->root.type == bfd_link_hash_warning)
+           h = (struct elf_link_hash_entry *)h->root.u.i.link;
+       }
+
+      if (h != NULL)
+       picrel = bfinfdpic_relocs_info_for_global (bfinfdpic_relocs_info (info),
+                                                 abfd, h,
+                                                 rel->r_addend, NO_INSERT);
+      else
+       picrel = bfinfdpic_relocs_info_for_local (bfinfdpic_relocs_info (info),
+                                                abfd, r_symndx,
+                                                rel->r_addend, NO_INSERT);
+
+      if (! picrel)
+       return FALSE;
+
+      *changed = TRUE;
+      dinfo = bfinfdpic_dynamic_got_plt_info (info);
+
+      _bfinfdpic_count_relocs_fixups (picrel, dinfo, TRUE);
+      if (ELF32_R_TYPE (rel->r_info) == R_BFIN_BYTE4_DATA)
+       picrel->relocs32--;
+      else /* we know (ELF32_R_TYPE (rel->r_info) == R_BFIN_FUNCDESC) */
+       picrel->relocsfd--;
+      _bfinfdpic_count_relocs_fixups (picrel, dinfo, FALSE);
+    }
+
+  return TRUE;
+}
+
+static bfd_boolean
+bfinfdpic_elf_discard_info (bfd *ibfd,
+                          struct elf_reloc_cookie *cookie ATTRIBUTE_UNUSED,
+                          struct bfd_link_info *info)
+{
+  bfd_boolean changed = FALSE;
+  asection *s;
+  bfd *obfd = NULL;
+
+  /* Account for relaxation of .eh_frame section.  */
+  for (s = ibfd->sections; s; s = s->next)
+    if (s->sec_info_type == ELF_INFO_TYPE_EH_FRAME)
+      {
+       if (!_bfinfdpic_check_discarded_relocs (ibfd, s, info, &changed))
+         return FALSE;
+       obfd = s->output_section->owner;
+      }
+
+  if (changed)
+    {
+      struct _bfinfdpic_dynamic_got_plt_info gpinfo;
+
+      memset (&gpinfo, 0, sizeof (gpinfo));
+      memcpy (&gpinfo.g, bfinfdpic_dynamic_got_plt_info (info),
+             sizeof (gpinfo.g));
+
+      /* Clear GOT and PLT assignments.  */
+      htab_traverse (bfinfdpic_relocs_info (info),
+                    _bfinfdpic_reset_got_plt_entries,
+                    NULL);
+
+      if (!_bfinfdpic_size_got_plt (obfd, &gpinfo))
+       return FALSE;
+    }
+
+  return TRUE;
+}
+
 static bfd_boolean
 elf32_bfinfdpic_modify_program_headers (bfd *output_bfd,
                                        struct bfd_link_info *info)
@@ -4314,8 +4600,8 @@ elf32_bfinfdpic_finish_dynamic_sections (bfd *output_bfd,
 
 static bfd_boolean
 elf32_bfinfdpic_adjust_dynamic_symbol
-(struct bfd_link_info *info ATTRIBUTE_UNUSED,
- struct elf_link_hash_entry *h ATTRIBUTE_UNUSED)
+(struct bfd_link_info *info,
+ struct elf_link_hash_entry *h)
 {
   bfd * dynobj;
 
@@ -4509,7 +4795,7 @@ bfinfdpic_check_relocs (bfd *abfd, struct bfd_link_info *info,
                        asection *sec, const Elf_Internal_Rela *relocs)
 {
   Elf_Internal_Shdr *symtab_hdr;
-  struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
+  struct elf_link_hash_entry **sym_hashes;
   const Elf_Internal_Rela *rel;
   const Elf_Internal_Rela *rel_end;
   bfd *dynobj;
@@ -4520,9 +4806,6 @@ bfinfdpic_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
   sym_hashes = elf_sym_hashes (abfd);
-  sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof(Elf32_External_Sym);
-  if (!elf_bad_symtab (abfd))
-    sym_hashes_end -= symtab_hdr->sh_info;
 
   dynobj = elf_hash_table (info)->dynobj;
   rel_end = relocs + sec->reloc_count;
@@ -4556,9 +4839,9 @@ bfinfdpic_check_relocs (bfd *abfd, struct bfd_link_info *info,
          if (! IS_FDPIC (abfd))
            goto bad_reloc;
          /* Fall through.  */
-       case R_pcrel24:
-       case R_pcrel24_jump_l:
-       case R_byte4_data:
+       case R_BFIN_PCREL24:
+       case R_BFIN_PCREL24_JUMP_L:
+       case R_BFIN_BYTE4_DATA:
          if (IS_FDPIC (abfd) && ! dynobj)
            {
              elf_hash_table (info)->dynobj = dynobj = abfd;
@@ -4602,10 +4885,10 @@ bfinfdpic_check_relocs (bfd *abfd, struct bfd_link_info *info,
 
       switch (ELF32_R_TYPE (rel->r_info))
         {
-       case R_pcrel24:
-       case R_pcrel24_jump_l:
+       case R_BFIN_PCREL24:
+       case R_BFIN_PCREL24_JUMP_L:
          if (IS_FDPIC (abfd))
-           picrel->call = 1;
+           picrel->call++;
          break;
 
        case R_BFIN_FUNCDESC_VALUE:
@@ -4614,50 +4897,50 @@ bfinfdpic_check_relocs (bfd *abfd, struct bfd_link_info *info,
            picrel->relocs32--;
          /* Fall through.  */
 
-       case R_byte4_data:
+       case R_BFIN_BYTE4_DATA:
          if (! IS_FDPIC (abfd))
            break;
 
-         picrel->sym = 1;
+         picrel->sym++;
          if (bfd_get_section_flags (abfd, sec) & SEC_ALLOC)
            picrel->relocs32++;
          break;
 
        case R_BFIN_GOT17M4:
-         picrel->got17m4 = 1;
+         picrel->got17m4++;
          break;
 
        case R_BFIN_GOTHI:
        case R_BFIN_GOTLO:
-         picrel->gothilo = 1;
+         picrel->gothilo++;
          break;
 
        case R_BFIN_FUNCDESC_GOT17M4:
-         picrel->fdgot17m4 = 1;
+         picrel->fdgot17m4++;
          break;
 
        case R_BFIN_FUNCDESC_GOTHI:
        case R_BFIN_FUNCDESC_GOTLO:
-         picrel->fdgothilo = 1;
+         picrel->fdgothilo++;
          break;
 
        case R_BFIN_GOTOFF17M4:
        case R_BFIN_GOTOFFHI:
        case R_BFIN_GOTOFFLO:
-         picrel->gotoff = 1;
+         picrel->gotoff++;
          break;
 
        case R_BFIN_FUNCDESC_GOTOFF17M4:
-         picrel->fdgoff17m4 = 1;
+         picrel->fdgoff17m4++;
          break;
 
        case R_BFIN_FUNCDESC_GOTOFFHI:
        case R_BFIN_FUNCDESC_GOTOFFLO:
-         picrel->fdgoffhilo = 1;
+         picrel->fdgoffhilo++;
          break;
 
        case R_BFIN_FUNCDESC:
-         picrel->fd = 1;
+         picrel->fd++;
          picrel->relocsfd++;
          break;
 
@@ -4671,14 +4954,16 @@ bfinfdpic_check_relocs (bfd *abfd, struct bfd_link_info *info,
         /* This relocation describes which C++ vtable entries are actually
            used.  Record for later use during GC.  */
         case R_BFIN_GNU_VTENTRY:
-          if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
+          BFD_ASSERT (h != NULL);
+          if (h != NULL
+              && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
             return FALSE;
           break;
 
-       case R_huimm16:
-       case R_luimm16:
-       case R_pcrel12_jump_s:
-       case R_pcrel10:
+       case R_BFIN_HUIMM16:
+       case R_BFIN_LUIMM16:
+       case R_BFIN_PCREL12_JUMP_S:
+       case R_BFIN_PCREL10:
          break;
 
        default:
@@ -4811,8 +5096,7 @@ elf32_bfin_print_private_bfd_data (bfd * abfd, PTR ptr)
 static bfd_boolean
 elf32_bfin_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
 {
-  flagword old_flags, old_partial;
-  flagword new_flags, new_partial;
+  flagword old_flags, new_flags;
   bfd_boolean error = FALSE;
 
   new_flags = elf_elfheader (ibfd)->e_flags;
@@ -4830,37 +5114,10 @@ elf32_bfin_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
   if (!elf_flags_init (obfd))                  /* First call, no flags set.  */
     {
       elf_flags_init (obfd) = TRUE;
-      old_flags = new_flags;
-    }
-
-  else if (new_flags == old_flags)             /* Compatible flags are ok.  */
-    ;
-
-  else                                         /* Possibly incompatible flags.  */
-    {
-      /* We don't have to do anything if the pic flags are the same, or the new
-         module(s) were compiled with -mlibrary-pic.  */
-      new_partial = (new_flags & EF_BFIN_PIC_FLAGS);
-      old_partial = (old_flags & EF_BFIN_PIC_FLAGS);
-      if (new_partial == old_partial)
-       ;
-
-      /* If we have mixtures of -fpic and -fPIC, or in both bits.  */
-      else if (new_partial != 0 && old_partial != 0)
-       old_flags |= new_partial;
-
-      /* One module was compiled for pic and the other was not, see if we have
-         had any relocations that are not pic-safe.  */
-      else
-       old_flags |= new_partial;
-
+      elf_elfheader (obfd)->e_flags = new_flags;
     }
 
-  /* Update the old flags now with changes made above.  */
-  elf_elfheader (obfd)->e_flags = old_flags;
-
-  if (((new_flags & EF_BFIN_FDPIC) == 0)
-      != (! IS_FDPIC (ibfd)))
+  if (((new_flags & EF_BFIN_FDPIC) == 0) != (! IS_FDPIC (obfd)))
     {
       error = TRUE;
       if (IS_FDPIC (obfd))
@@ -4895,8 +5152,8 @@ struct bfin_link_hash_table
 {
   struct elf_link_hash_table root;
 
-  /* Small local sym to section mapping cache.  */
-  struct sym_sec_cache sym_sec;
+  /* Small local sym cache.  */
+  struct sym_cache sym_cache;
 };
 
 #define bfin_hash_entry(ent) ((struct bfin_link_hash_entry *) (ent))
@@ -4942,7 +5199,7 @@ bfin_link_hash_table_create (bfd * abfd)
       return NULL;
     }
 
-  ret->sym_sec.abfd = NULL;
+  ret->sym_cache.abfd = NULL;
 
   return &ret->root.root;
 }
@@ -5023,7 +5280,7 @@ bfin_finish_dynamic_symbol (bfd * output_bfd,
              || h->dynindx == -1 || h->forced_local) && h->def_regular)
        {
          fprintf(stderr, "*** check this relocation %s\n", __FUNCTION__);
-         rela.r_info = ELF32_R_INFO (0, R_pcrel24);
+         rela.r_info = ELF32_R_INFO (0, R_BFIN_PCREL24);
          rela.r_addend = bfd_get_signed_32 (output_bfd,
                                             (sgot->contents
                                              +
@@ -5034,7 +5291,7 @@ bfin_finish_dynamic_symbol (bfd * output_bfd,
        {
          bfd_put_32 (output_bfd, (bfd_vma) 0,
                      sgot->contents + (h->got.offset & ~(bfd_vma) 1));
-         rela.r_info = ELF32_R_INFO (h->dynindx, R_got);
+         rela.r_info = ELF32_R_INFO (h->dynindx, R_BFIN_GOT);
          rela.r_addend = 0;
        }
 
@@ -5429,7 +5686,7 @@ bfd_bfin_elf32_create_embedded_relocs (
        characters.  */
 
       /* We can only relocate absolute longword relocs at run time.  */
-      if (ELF32_R_TYPE (irel->r_info) != (int) R_byte4_data)
+      if (ELF32_R_TYPE (irel->r_info) != (int) R_BFIN_BYTE4_DATA)
        {
          *errmsg = _("unsupported reloc type");
          bfd_set_error (bfd_error_bad_value);
@@ -5494,6 +5751,14 @@ error_return:
     free (internal_relocs);
   return FALSE;
 }
+
+struct bfd_elf_special_section const elf32_bfin_special_sections[] =
+{
+  { ".l1.text",                8, -2, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
+  { ".l1.data",                8, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
+  { NULL,              0,  0, 0,            0 }
+};
+
 \f
 #define TARGET_LITTLE_SYM              bfd_elf32_bfin_vec
 #define TARGET_LITTLE_NAME             "elf32-bfin"
@@ -5542,6 +5807,7 @@ error_return:
                                         elf32_bfin_print_private_bfd_data
 #define elf_backend_reloc_type_class    elf32_bfin_reloc_type_class
 #define elf_backend_can_gc_sections 1
+#define elf_backend_special_sections   elf32_bfin_special_sections
 #define elf_backend_can_refcount 1
 #define elf_backend_want_got_plt 0
 #define elf_backend_plt_readonly 1
@@ -5559,6 +5825,7 @@ error_return:
 #define        elf32_bed               elf32_bfinfdpic_bed
 
 #undef elf_backend_gc_sweep_hook
+#define elf_backend_gc_sweep_hook       bfinfdpic_gc_sweep_hook
 
 #undef elf_backend_got_header_size
 #define elf_backend_got_header_size     0
@@ -5597,6 +5864,9 @@ error_return:
 #define elf_backend_finish_dynamic_sections \
                elf32_bfinfdpic_finish_dynamic_sections
 
+#undef elf_backend_discard_info
+#define elf_backend_discard_info \
+               bfinfdpic_elf_discard_info
 #undef elf_backend_can_make_relative_eh_frame
 #define elf_backend_can_make_relative_eh_frame \
                bfinfdpic_elf_use_relative_eh_frame