]> 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.
 /* 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.
 
 
    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 "libbfd.h"
 #include "elf-bfd.h"
 #include "elf/bfin.h"
-#include "elf/dwarf2.h"
+#include "dwarf2.h"
 #include "hashtab.h"
 
 /* FUNCTION : bfin_pltpc_reloc
 #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. .  */
 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.  */
         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.  */
         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.  */
 
         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.  */
         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.  */
         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.  */
 
         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.  */
         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.  */
         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.  */
 
         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.  */
         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.  */
         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.  */
 
         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
         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.  */
         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.  */
 
         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.  */
         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.  */
         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.  */
 
         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.  */
         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.  */
         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.  */
 
         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.  */
         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.  */
         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.  */
 
         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.  */
         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.  */
         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.  */
 
         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.  */
          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.  */
          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.  */
 
         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.  */
         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.  */
         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.  */
 
         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.  */
         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.  */
         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.  */
 
         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.  */
         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.  */
         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.  */
 
         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.  */
         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.  */
         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.  */
 
         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.  */
         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.  */
         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.  */
 
         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.  */
         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.  */
         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.  */
 
         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.  */
         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.  */
         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.  */
 
         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.  */
         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.  */
         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.  */
 
         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.  */
         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.  */
         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.  */
 
         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.  */
         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.  */
         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.  */
         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 */
         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 */
         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 [] =
 {
 
 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.  */
         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.  */
         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.  */
 
         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.  */
         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.  */
         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.  */
         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 [] =
 {
 
 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 },
 
   { 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 (
    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] == '$' )
      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);
 }
 
   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;
   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)
        {
        }
 
       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_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_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.  */
          /* 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
              {
              }
            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:
          break;
 
        default:
-       do_default:
-         r = _bfd_final_link_relocate (howto, input_bfd, input_section,
-                                       contents, address,
-                                       relocation, rel->r_addend);
-
          break;
        }
 
          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)
        {
 
       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;
 }
 
        }
     }
 
   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
 
 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;
 {
   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);
 
   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;
       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))
 
       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;
          break;
+
        default:
          break;
        default:
          break;
-       }
+        }
     }
     }
+
   return TRUE;
 }
 
   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,
    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)
     {
 {
   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;
     }
 
       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);
   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;
 
       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))
 
   /* 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,
       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))
                                           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;
 }
 
   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.  */
 
 /* 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;
   /* 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;
 
   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;
 
   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;
     }
 
        relocs += entry->relocsfd;
     }
 
+  if (subtract)
+    {
+      relocs = - relocs;
+      fixups = - fixups;
+    }
+
   entry->dynrelocs += relocs;
   entry->fixups += fixups;
   dinfo->relocs += relocs;
   dinfo->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;
 }
 
   return 1;
 }
@@ -3864,6 +3988,23 @@ _bfinfdpic_assign_plt_entries (void **entryp, void *info_)
   return 1;
 }
 
   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
 /* 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;
 }
 
   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
 
 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;
   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.  */
 
   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 (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.  */
 
   /* 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,
                                          0,
                                          odd,
                                          16,
-                                         gpinfo.g.got17m4,
-                                         gpinfo.g.fd17m4,
+                                         gpinfop->g.got17m4,
+                                         gpinfop->g.fd17m4,
                                          limit,
                                          (bfd_vma)1 << (18-1));
                                          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,
                                          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,
                                          (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.  */
     /* 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
   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 =
     /* 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
       * 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
   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;
     }
 
        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
   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)
     }
 
   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,
     }
 
   /* 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)
     {
      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.  */
           / (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.  */
 
   /* 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
 
   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,
 
   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.  */
 
   /* 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)
   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;
     }
 
          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;
 }
 
   return TRUE;
 }
 
@@ -4175,6 +4345,122 @@ elf32_bfinfdpic_always_size_sections (bfd *output_bfd,
   return TRUE;
 }
 
   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)
 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
 
 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;
 
 {
   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;
                        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;
   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);
 
   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;
 
   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.  */
          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;
          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))
         {
 
       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))
          if (IS_FDPIC (abfd))
-           picrel->call = 1;
+           picrel->call++;
          break;
 
        case R_BFIN_FUNCDESC_VALUE:
          break;
 
        case R_BFIN_FUNCDESC_VALUE:
@@ -4614,50 +4897,50 @@ bfinfdpic_check_relocs (bfd *abfd, struct bfd_link_info *info,
            picrel->relocs32--;
          /* Fall through.  */
 
            picrel->relocs32--;
          /* Fall through.  */
 
-       case R_byte4_data:
+       case R_BFIN_BYTE4_DATA:
          if (! IS_FDPIC (abfd))
            break;
 
          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:
          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:
          break;
 
        case R_BFIN_GOTHI:
        case R_BFIN_GOTLO:
-         picrel->gothilo = 1;
+         picrel->gothilo++;
          break;
 
        case R_BFIN_FUNCDESC_GOT17M4:
          break;
 
        case R_BFIN_FUNCDESC_GOT17M4:
-         picrel->fdgot17m4 = 1;
+         picrel->fdgot17m4++;
          break;
 
        case R_BFIN_FUNCDESC_GOTHI:
        case R_BFIN_FUNCDESC_GOTLO:
          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:
          break;
 
        case R_BFIN_GOTOFF17M4:
        case R_BFIN_GOTOFFHI:
        case R_BFIN_GOTOFFLO:
-         picrel->gotoff = 1;
+         picrel->gotoff++;
          break;
 
        case R_BFIN_FUNCDESC_GOTOFF17M4:
          break;
 
        case R_BFIN_FUNCDESC_GOTOFF17M4:
-         picrel->fdgoff17m4 = 1;
+         picrel->fdgoff17m4++;
          break;
 
        case R_BFIN_FUNCDESC_GOTOFFHI:
        case R_BFIN_FUNCDESC_GOTOFFLO:
          break;
 
        case R_BFIN_FUNCDESC_GOTOFFHI:
        case R_BFIN_FUNCDESC_GOTOFFLO:
-         picrel->fdgoffhilo = 1;
+         picrel->fdgoffhilo++;
          break;
 
        case R_BFIN_FUNCDESC:
          break;
 
        case R_BFIN_FUNCDESC:
-         picrel->fd = 1;
+         picrel->fd++;
          picrel->relocsfd++;
          break;
 
          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:
         /* 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;
 
             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:
          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)
 {
 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;
   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;
   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))
     {
       error = TRUE;
       if (IS_FDPIC (obfd))
@@ -4895,8 +5152,8 @@ struct bfin_link_hash_table
 {
   struct elf_link_hash_table root;
 
 {
   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))
 };
 
 #define bfin_hash_entry(ent) ((struct bfin_link_hash_entry *) (ent))
@@ -4942,7 +5199,7 @@ bfin_link_hash_table_create (bfd * abfd)
       return NULL;
     }
 
       return NULL;
     }
 
-  ret->sym_sec.abfd = NULL;
+  ret->sym_cache.abfd = NULL;
 
   return &ret->root.root;
 }
 
   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__);
              || 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
                                              +
          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));
        {
          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;
        }
 
          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.  */
        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);
        {
          *errmsg = _("unsupported reloc type");
          bfd_set_error (bfd_error_bad_value);
@@ -5494,6 +5751,14 @@ error_return:
     free (internal_relocs);
   return FALSE;
 }
     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"
 \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
                                         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
 #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        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
 
 #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
 
 #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
 #undef elf_backend_can_make_relative_eh_frame
 #define elf_backend_can_make_relative_eh_frame \
                bfinfdpic_elf_use_relative_eh_frame