OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [gdb-6.8/] [bfd/] [elf32-bfin.c] - Diff between revs 157 and 225

Show entire file | Details | Blame | View Log

Rev 157 Rev 225
Line 1... Line 1...
/* 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.
 
 
   This program is free software; you can redistribute it and/or modify
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   it under the terms of the GNU General Public License as published by
Line 21... Line 21...
#include "sysdep.h"
#include "sysdep.h"
#include "bfd.h"
#include "bfd.h"
#include "libbfd.h"
#include "libbfd.h"
#include "elf-bfd.h"
#include "elf-bfd.h"
#include "elf/bfin.h"
#include "elf/bfin.h"
#include "elf/dwarf2.h"
#include "dwarf2.h"
#include "hashtab.h"
#include "hashtab.h"
 
 
/* FUNCTION : bfin_pltpc_reloc
/* FUNCTION : bfin_pltpc_reloc
   ABSTRACT : TODO : figure out how to handle pltpc relocs.  */
   ABSTRACT : TODO : figure out how to handle pltpc relocs.  */
static bfd_reloc_status_type
static bfd_reloc_status_type
Line 419... Line 419...
#define BFIN_ARELOC_MAX 0xF3
#define BFIN_ARELOC_MAX 0xF3
 
 
static reloc_howto_type bfin_howto_table [] =
static reloc_howto_type bfin_howto_table [] =
{
{
  /* This reloc does nothing. .  */
  /* This reloc does nothing. .  */
  HOWTO (R_unused0,             /* type.  */
  HOWTO (R_BFIN_UNUSED0,        /* type.  */
         0,                      /* rightshift.  */
         0,                      /* rightshift.  */
         2,                     /* size (0 = byte, 1 = short, 2 = long).  */
         2,                     /* size (0 = byte, 1 = short, 2 = long).  */
         32,                    /* bitsize.  */
         32,                    /* bitsize.  */
         FALSE,                 /* pc_relative.  */
         FALSE,                 /* pc_relative.  */
         0,                      /* bitpos.  */
         0,                      /* bitpos.  */
         complain_overflow_bitfield, /* complain_on_overflow.  */
         complain_overflow_bitfield, /* complain_on_overflow.  */
         bfd_elf_generic_reloc, /* special_function.  */
         bfd_elf_generic_reloc, /* special_function.  */
         "R_unused0",           /* name.  */
         "R_BFIN_UNUSED0",      /* name.  */
         FALSE,                 /* partial_inplace.  */
         FALSE,                 /* partial_inplace.  */
         0,                      /* src_mask.  */
         0,                      /* src_mask.  */
         0,                      /* dst_mask.  */
         0,                      /* dst_mask.  */
         FALSE),                /* pcrel_offset.  */
         FALSE),                /* pcrel_offset.  */
 
 
  HOWTO (R_pcrel5m2,            /* type.  */
  HOWTO (R_BFIN_PCREL5M2,       /* type.  */
         1,                     /* rightshift.  */
         1,                     /* rightshift.  */
         1,                     /* size (0 = byte, 1 = short, 2 = long)..  */
         1,                     /* size (0 = byte, 1 = short, 2 = long)..  */
         4,                     /* bitsize.  */
         4,                     /* bitsize.  */
         TRUE,                  /* pc_relative.  */
         TRUE,                  /* pc_relative.  */
         0,                      /* bitpos.  */
         0,                      /* bitpos.  */
         complain_overflow_unsigned, /* complain_on_overflow.  */
         complain_overflow_unsigned, /* complain_on_overflow.  */
         bfin_bfd_reloc,        /* special_function.  */
         bfin_bfd_reloc,        /* special_function.  */
         "R_pcrel5m2",          /* name.  */
         "R_BFIN_PCREL5M2",     /* name.  */
         FALSE,                 /* partial_inplace.  */
         FALSE,                 /* partial_inplace.  */
         0,                      /* src_mask.  */
         0,                      /* src_mask.  */
         0x0000000F,            /* dst_mask.  */
         0x0000000F,            /* dst_mask.  */
         FALSE),                /* pcrel_offset.  */
         FALSE),                /* pcrel_offset.  */
 
 
  HOWTO (R_unused1,             /* type.  */
  HOWTO (R_BFIN_UNUSED1,        /* type.  */
         0,                      /* rightshift.  */
         0,                      /* rightshift.  */
         2,                     /* size (0 = byte, 1 = short, 2 = long).  */
         2,                     /* size (0 = byte, 1 = short, 2 = long).  */
         32,                    /* bitsize.  */
         32,                    /* bitsize.  */
         FALSE,                 /* pc_relative.  */
         FALSE,                 /* pc_relative.  */
         0,                      /* bitpos.  */
         0,                      /* bitpos.  */
         complain_overflow_bitfield, /* complain_on_overflow.  */
         complain_overflow_bitfield, /* complain_on_overflow.  */
         bfd_elf_generic_reloc, /* special_function.  */
         bfd_elf_generic_reloc, /* special_function.  */
         "R_unused1",           /* name.  */
         "R_BFIN_UNUSED1",      /* name.  */
         FALSE,                 /* partial_inplace.  */
         FALSE,                 /* partial_inplace.  */
         0,                      /* src_mask.  */
         0,                      /* src_mask.  */
         0,                      /* dst_mask.  */
         0,                      /* dst_mask.  */
         FALSE),                /* pcrel_offset.  */
         FALSE),                /* pcrel_offset.  */
 
 
  HOWTO (R_pcrel10,             /* type.  */
  HOWTO (R_BFIN_PCREL10,        /* type.  */
         1,                     /* rightshift.  */
         1,                     /* rightshift.  */
         1,                     /* size (0 = byte, 1 = short, 2 = long).  */
         1,                     /* size (0 = byte, 1 = short, 2 = long).  */
         10,                    /* bitsize.  */
         10,                    /* bitsize.  */
         TRUE,                  /* pc_relative.  */
         TRUE,                  /* pc_relative.  */
         0,                      /* bitpos.  */
         0,                      /* bitpos.  */
         complain_overflow_signed, /* complain_on_overflow.  */
         complain_overflow_signed, /* complain_on_overflow.  */
         bfin_bfd_reloc,        /* special_function.  */
         bfin_bfd_reloc,        /* special_function.  */
         "R_pcrel10",           /* name.  */
         "R_BFIN_PCREL10",      /* name.  */
         FALSE,                 /* partial_inplace.  */
         FALSE,                 /* partial_inplace.  */
         0,                      /* src_mask.  */
         0,                      /* src_mask.  */
         0x000003FF,            /* dst_mask.  */
         0x000003FF,            /* dst_mask.  */
         TRUE),                 /* pcrel_offset.  */
         TRUE),                 /* pcrel_offset.  */
 
 
  HOWTO (R_pcrel12_jump,        /* type.  */
  HOWTO (R_BFIN_PCREL12_JUMP,   /* type.  */
         1,                     /* rightshift.  */
         1,                     /* rightshift.  */
                                /* the offset is actually 13 bit
                                /* the offset is actually 13 bit
                                   aligned on a word boundary so
                                   aligned on a word boundary so
                                   only 12 bits have to be used.
                                   only 12 bits have to be used.
                                   Right shift the rightmost bit..  */
                                   Right shift the rightmost bit..  */
Line 487... Line 487...
         12,                    /* bitsize.  */
         12,                    /* bitsize.  */
         TRUE,                  /* pc_relative.  */
         TRUE,                  /* pc_relative.  */
         0,                      /* bitpos.  */
         0,                      /* bitpos.  */
         complain_overflow_signed, /* complain_on_overflow.  */
         complain_overflow_signed, /* complain_on_overflow.  */
         bfin_bfd_reloc,        /* special_function.  */
         bfin_bfd_reloc,        /* special_function.  */
         "R_pcrel12_jump",      /* name.  */
         "R_BFIN_PCREL12_JUMP", /* name.  */
         FALSE,                 /* partial_inplace.  */
         FALSE,                 /* partial_inplace.  */
         0,                      /* src_mask.  */
         0,                      /* src_mask.  */
         0x0FFF,                /* dst_mask.  */
         0x0FFF,                /* dst_mask.  */
         TRUE),                 /* pcrel_offset.  */
         TRUE),                 /* pcrel_offset.  */
 
 
  HOWTO (R_rimm16,              /* type.  */
  HOWTO (R_BFIN_RIMM16,         /* type.  */
         0,                      /* rightshift.  */
         0,                      /* rightshift.  */
         1,                     /* size (0 = byte, 1 = short, 2 = long).  */
         1,                     /* size (0 = byte, 1 = short, 2 = long).  */
         16,                    /* bitsize.  */
         16,                    /* bitsize.  */
         FALSE,                 /* pc_relative.  */
         FALSE,                 /* pc_relative.  */
         0,                      /* bitpos.  */
         0,                      /* bitpos.  */
         complain_overflow_signed, /* complain_on_overflow.  */
         complain_overflow_signed, /* complain_on_overflow.  */
         bfin_imm16_reloc,      /* special_function.  */
         bfin_imm16_reloc,      /* special_function.  */
         "R_rimm16",            /* name.  */
         "R_BFIN_RIMM16",       /* name.  */
         FALSE,                 /* partial_inplace.  */
         FALSE,                 /* partial_inplace.  */
         0,                      /* src_mask.  */
         0,                      /* src_mask.  */
         0x0000FFFF,            /* dst_mask.  */
         0x0000FFFF,            /* dst_mask.  */
         TRUE),                 /* pcrel_offset.  */
         TRUE),                 /* pcrel_offset.  */
 
 
  HOWTO (R_luimm16,             /* type.  */
  HOWTO (R_BFIN_LUIMM16,        /* type.  */
         0,                      /* rightshift.  */
         0,                      /* rightshift.  */
         1,                     /* size (0 = byte, 1 = short, 2 = long).  */
         1,                     /* size (0 = byte, 1 = short, 2 = long).  */
         16,                    /* bitsize.  */
         16,                    /* bitsize.  */
         FALSE,                 /* pc_relative.  */
         FALSE,                 /* pc_relative.  */
         0,                      /* bitpos.  */
         0,                      /* bitpos.  */
         complain_overflow_dont, /* complain_on_overflow.  */
         complain_overflow_dont, /* complain_on_overflow.  */
         bfin_imm16_reloc,      /* special_function.  */
         bfin_imm16_reloc,      /* special_function.  */
         "R_luimm16",           /* name.  */
         "R_BFIN_LUIMM16",      /* name.  */
         FALSE,                 /* partial_inplace.  */
         FALSE,                 /* partial_inplace.  */
         0,                      /* src_mask.  */
         0,                      /* src_mask.  */
         0x0000FFFF,            /* dst_mask.  */
         0x0000FFFF,            /* dst_mask.  */
         TRUE),                 /* pcrel_offset.  */
         TRUE),                 /* pcrel_offset.  */
 
 
  HOWTO (R_huimm16,             /* type.  */
  HOWTO (R_BFIN_HUIMM16,        /* type.  */
         16,                    /* rightshift.  */
         16,                    /* rightshift.  */
         1,                     /* size (0 = byte, 1 = short, 2 = long).  */
         1,                     /* size (0 = byte, 1 = short, 2 = long).  */
         16,                    /* bitsize.  */
         16,                    /* bitsize.  */
         FALSE,                 /* pc_relative.  */
         FALSE,                 /* pc_relative.  */
         0,                      /* bitpos.  */
         0,                      /* bitpos.  */
         complain_overflow_unsigned, /* complain_on_overflow.  */
         complain_overflow_unsigned, /* complain_on_overflow.  */
         bfin_imm16_reloc,      /* special_function.  */
         bfin_imm16_reloc,      /* special_function.  */
         "R_huimm16",           /* name.  */
         "R_BFIN_HUIMM16",      /* name.  */
         FALSE,                 /* partial_inplace.  */
         FALSE,                 /* partial_inplace.  */
         0,                      /* src_mask.  */
         0,                      /* src_mask.  */
         0x0000FFFF,            /* dst_mask.  */
         0x0000FFFF,            /* dst_mask.  */
         TRUE),                 /* pcrel_offset.  */
         TRUE),                 /* pcrel_offset.  */
 
 
  HOWTO (R_pcrel12_jump_s,      /* type.  */
  HOWTO (R_BFIN_PCREL12_JUMP_S, /* type.  */
         1,                     /* rightshift.  */
         1,                     /* rightshift.  */
         1,                     /* size (0 = byte, 1 = short, 2 = long).  */
         1,                     /* size (0 = byte, 1 = short, 2 = long).  */
         12,                    /* bitsize.  */
         12,                    /* bitsize.  */
         TRUE,                  /* pc_relative.  */
         TRUE,                  /* pc_relative.  */
         0,                      /* bitpos.  */
         0,                      /* bitpos.  */
         complain_overflow_signed, /* complain_on_overflow.  */
         complain_overflow_signed, /* complain_on_overflow.  */
         bfin_bfd_reloc,        /* special_function.  */
         bfin_bfd_reloc,        /* special_function.  */
         "R_pcrel12_jump_s",    /* name.  */
         "R_BFIN_PCREL12_JUMP_S", /* name.  */
         FALSE,                 /* partial_inplace.  */
         FALSE,                 /* partial_inplace.  */
         0,                      /* src_mask.  */
         0,                      /* src_mask.  */
         0x00000FFF,            /* dst_mask.  */
         0x00000FFF,            /* dst_mask.  */
         TRUE),                 /* pcrel_offset.  */
         TRUE),                 /* pcrel_offset.  */
 
 
  HOWTO (R_pcrel24_jump_x,      /* type.  */
  HOWTO (R_BFIN_PCREL24_JUMP_X, /* type.  */
         1,                     /* rightshift.  */
         1,                     /* rightshift.  */
         2,                     /* size (0 = byte, 1 = short, 2 = long).  */
         2,                     /* size (0 = byte, 1 = short, 2 = long).  */
         24,                    /* bitsize.  */
         24,                    /* bitsize.  */
         TRUE,                  /* pc_relative.  */
         TRUE,                  /* pc_relative.  */
         0,                      /* bitpos.  */
         0,                      /* bitpos.  */
         complain_overflow_signed, /* complain_on_overflow.  */
         complain_overflow_signed, /* complain_on_overflow.  */
         bfin_pcrel24_reloc,    /* special_function.  */
         bfin_pcrel24_reloc,    /* special_function.  */
         "R_pcrel24_jump_x",    /* name.  */
        "R_BFIN_PCREL24_JUMP_X", /* name.  */
         FALSE,                 /* partial_inplace.  */
         FALSE,                 /* partial_inplace.  */
         0,                      /* src_mask.  */
         0,                      /* src_mask.  */
         0x00FFFFFF,            /* dst_mask.  */
         0x00FFFFFF,            /* dst_mask.  */
         TRUE),                 /* pcrel_offset.  */
         TRUE),                 /* pcrel_offset.  */
 
 
  HOWTO (R_pcrel24,             /* type.  */
  HOWTO (R_BFIN_PCREL24,        /* type.  */
         1,                     /* rightshift.  */
         1,                     /* rightshift.  */
         2,                     /* size (0 = byte, 1 = short, 2 = long).  */
         2,                     /* size (0 = byte, 1 = short, 2 = long).  */
         24,                    /* bitsize.  */
         24,                    /* bitsize.  */
         TRUE,                  /* pc_relative.  */
         TRUE,                  /* pc_relative.  */
         0,                      /* bitpos.  */
         0,                      /* bitpos.  */
         complain_overflow_signed, /* complain_on_overflow.  */
         complain_overflow_signed, /* complain_on_overflow.  */
         bfin_pcrel24_reloc,    /* special_function.  */
         bfin_pcrel24_reloc,    /* special_function.  */
         "R_pcrel24",           /* name.  */
         "R_BFIN_PCREL24",      /* name.  */
         FALSE,                 /* partial_inplace.  */
         FALSE,                 /* partial_inplace.  */
         0,                      /* src_mask.  */
         0,                      /* src_mask.  */
         0x00FFFFFF,            /* dst_mask.  */
         0x00FFFFFF,            /* dst_mask.  */
         TRUE),                 /* pcrel_offset.  */
         TRUE),                 /* pcrel_offset.  */
 
 
  HOWTO (R_unusedb,             /* type.  */
  HOWTO (R_BFIN_UNUSEDB,        /* type.  */
         0,                      /* rightshift.  */
         0,                      /* rightshift.  */
         2,                     /* size (0 = byte, 1 = short, 2 = long).  */
         2,                     /* size (0 = byte, 1 = short, 2 = long).  */
         32,                    /* bitsize.  */
         32,                    /* bitsize.  */
         FALSE,                 /* pc_relative.  */
         FALSE,                 /* pc_relative.  */
         0,                      /* bitpos.  */
         0,                      /* bitpos.  */
         complain_overflow_dont, /* complain_on_overflow.  */
         complain_overflow_dont, /* complain_on_overflow.  */
         bfd_elf_generic_reloc, /* special_function.  */
         bfd_elf_generic_reloc, /* special_function.  */
         "R_unusedb",           /* name.  */
         "R_BFIN_UNUSEDB",      /* name.  */
         FALSE,                 /* partial_inplace.  */
         FALSE,                 /* partial_inplace.  */
         0,                      /* src_mask.  */
         0,                      /* src_mask.  */
         0,                      /* dst_mask.  */
         0,                      /* dst_mask.  */
         FALSE),                /* pcrel_offset.  */
         FALSE),                /* pcrel_offset.  */
 
 
  HOWTO (R_unusedc,             /* type.  */
  HOWTO (R_BFIN_UNUSEDC,        /* type.  */
         0,                      /* rightshift.  */
         0,                      /* rightshift.  */
         2,                     /* size (0 = byte, 1 = short, 2 = long).  */
         2,                     /* size (0 = byte, 1 = short, 2 = long).  */
         32,                    /* bitsize.  */
         32,                    /* bitsize.  */
         FALSE,                 /* pc_relative.  */
         FALSE,                 /* pc_relative.  */
         0,                      /* bitpos.  */
         0,                      /* bitpos.  */
         complain_overflow_dont, /* complain_on_overflow.  */
         complain_overflow_dont, /* complain_on_overflow.  */
         bfd_elf_generic_reloc, /* special_function.  */
         bfd_elf_generic_reloc, /* special_function.  */
         "R_unusedc",           /* name.  */
         "R_BFIN_UNUSEDC",      /* name.  */
         FALSE,                 /* partial_inplace.  */
         FALSE,                 /* partial_inplace.  */
         0,                      /* src_mask.  */
         0,                      /* src_mask.  */
         0,                      /* dst_mask.  */
         0,                      /* dst_mask.  */
         FALSE),                /* pcrel_offset.  */
         FALSE),                /* pcrel_offset.  */
 
 
  HOWTO (R_pcrel24_jump_l,      /* type.  */
  HOWTO (R_BFIN_PCREL24_JUMP_L, /* type.  */
         1,                     /* rightshift.  */
         1,                     /* rightshift.  */
         2,                     /* size (0 = byte, 1 = short, 2 = long).  */
         2,                     /* size (0 = byte, 1 = short, 2 = long).  */
         24,                    /* bitsize.  */
         24,                    /* bitsize.  */
         TRUE,                  /* pc_relative.  */
         TRUE,                  /* pc_relative.  */
         0,                      /* bitpos.  */
         0,                      /* bitpos.  */
         complain_overflow_signed, /* complain_on_overflow.  */
         complain_overflow_signed, /* complain_on_overflow.  */
         bfin_pcrel24_reloc,    /* special_function.  */
         bfin_pcrel24_reloc,    /* special_function.  */
         "R_pcrel24_jump_l",    /* name.  */
         "R_BFIN_PCREL24_JUMP_L", /* name.  */
         FALSE,                 /* partial_inplace.  */
         FALSE,                 /* partial_inplace.  */
         0,                      /* src_mask.  */
         0,                      /* src_mask.  */
         0x00FFFFFF,            /* dst_mask.  */
         0x00FFFFFF,            /* dst_mask.  */
         TRUE),                 /* pcrel_offset.  */
         TRUE),                 /* pcrel_offset.  */
 
 
  HOWTO (R_pcrel24_call_x,      /* type.  */
  HOWTO (R_BFIN_PCREL24_CALL_X, /* type.  */
         1,                     /* rightshift.  */
         1,                     /* rightshift.  */
         2,                     /* size (0 = byte, 1 = short, 2 = long).  */
         2,                     /* size (0 = byte, 1 = short, 2 = long).  */
         24,                    /* bitsize.  */
         24,                    /* bitsize.  */
         TRUE,                  /* pc_relative.  */
         TRUE,                  /* pc_relative.  */
         0,                      /* bitpos.  */
         0,                      /* bitpos.  */
         complain_overflow_signed, /* complain_on_overflow.  */
         complain_overflow_signed, /* complain_on_overflow.  */
         bfin_pcrel24_reloc,    /* special_function.  */
         bfin_pcrel24_reloc,    /* special_function.  */
         "R_pcrel24_call_x",    /* name.  */
         "R_BFIN_PCREL24_CALL_X", /* name.  */
         FALSE,                 /* partial_inplace.  */
         FALSE,                 /* partial_inplace.  */
         0,                      /* src_mask.  */
         0,                      /* src_mask.  */
         0x00FFFFFF,            /* dst_mask.  */
         0x00FFFFFF,            /* dst_mask.  */
         TRUE),                 /* pcrel_offset.  */
         TRUE),                 /* pcrel_offset.  */
 
 
  HOWTO (R_var_eq_symb,         /* type.  */
  HOWTO (R_BFIN_VAR_EQ_SYMB,    /* type.  */
         0,                      /* rightshift.  */
         0,                      /* rightshift.  */
         2,                     /* size (0 = byte, 1 = short, 2 = long).  */
         2,                     /* size (0 = byte, 1 = short, 2 = long).  */
         32,                    /* bitsize.  */
         32,                    /* bitsize.  */
         FALSE,                 /* pc_relative.  */
         FALSE,                 /* pc_relative.  */
         0,                      /* bitpos.  */
         0,                      /* bitpos.  */
         complain_overflow_bitfield, /* complain_on_overflow.  */
         complain_overflow_bitfield, /* complain_on_overflow.  */
         bfin_bfd_reloc,        /* special_function.  */
         bfin_bfd_reloc,        /* special_function.  */
         "R_var_eq_symb",               /* name.  */
         "R_BFIN_VAR_EQ_SYMB",  /* name.  */
         FALSE,                 /* partial_inplace.  */
         FALSE,                 /* partial_inplace.  */
         0,                      /* src_mask.  */
         0,                      /* src_mask.  */
         0,                      /* dst_mask.  */
         0,                      /* dst_mask.  */
         FALSE),                /* pcrel_offset.  */
         FALSE),                /* pcrel_offset.  */
 
 
  HOWTO (R_byte_data,           /* type.  */
  HOWTO (R_BFIN_BYTE_DATA,      /* type.  */
         0,                      /* rightshift.  */
         0,                      /* rightshift.  */
         0,                      /* size (0 = byte, 1 = short, 2 = long).  */
         0,                      /* size (0 = byte, 1 = short, 2 = long).  */
         8,                     /* bitsize.  */
         8,                     /* bitsize.  */
         FALSE,                 /* pc_relative.  */
         FALSE,                 /* pc_relative.  */
         0,                      /* bitpos.  */
         0,                      /* bitpos.  */
         complain_overflow_unsigned, /* complain_on_overflow.  */
         complain_overflow_unsigned, /* complain_on_overflow.  */
         bfin_bfd_reloc,        /* special_function.  */
         bfin_bfd_reloc,        /* special_function.  */
         "R_byte_data",         /* name.  */
         "R_BFIN_BYTE_DATA",    /* name.  */
         FALSE,                 /* partial_inplace.  */
         FALSE,                 /* partial_inplace.  */
         0,                      /* src_mask.  */
         0,                      /* src_mask.  */
         0xFF,                  /* dst_mask.  */
         0xFF,                  /* dst_mask.  */
         TRUE),                 /* pcrel_offset.  */
         TRUE),                 /* pcrel_offset.  */
 
 
  HOWTO (R_byte2_data,          /* type.  */
  HOWTO (R_BFIN_BYTE2_DATA,     /* type.  */
         0,                      /* rightshift.  */
         0,                      /* rightshift.  */
         1,                     /* size (0 = byte, 1 = short, 2 = long).  */
         1,                     /* size (0 = byte, 1 = short, 2 = long).  */
         16,                    /* bitsize.  */
         16,                    /* bitsize.  */
         FALSE,                 /* pc_relative.  */
         FALSE,                 /* pc_relative.  */
         0,                      /* bitpos.  */
         0,                      /* bitpos.  */
         complain_overflow_signed, /* complain_on_overflow.  */
         complain_overflow_signed, /* complain_on_overflow.  */
         bfin_bfd_reloc,        /* special_function.  */
         bfin_bfd_reloc,        /* special_function.  */
         "R_byte2_data",        /* name.  */
         "R_BFIN_BYTE2_DATA",   /* name.  */
         FALSE,                 /* partial_inplace.  */
         FALSE,                 /* partial_inplace.  */
         0,                      /* src_mask.  */
         0,                      /* src_mask.  */
         0xFFFF,                /* dst_mask.  */
         0xFFFF,                /* dst_mask.  */
         TRUE),                 /* pcrel_offset.  */
         TRUE),                 /* pcrel_offset.  */
 
 
  HOWTO (R_byte4_data,          /* type.  */
  HOWTO (R_BFIN_BYTE4_DATA,     /* type.  */
         0,                      /* rightshift.  */
         0,                      /* rightshift.  */
         2,                     /* size (0 = byte, 1 = short, 2 = long).  */
         2,                     /* size (0 = byte, 1 = short, 2 = long).  */
         32,                    /* bitsize.  */
         32,                    /* bitsize.  */
         FALSE,                 /* pc_relative.  */
         FALSE,                 /* pc_relative.  */
         0,                      /* bitpos.  */
         0,                      /* bitpos.  */
         complain_overflow_unsigned, /* complain_on_overflow.  */
         complain_overflow_unsigned, /* complain_on_overflow.  */
         bfin_byte4_reloc,      /* special_function.  */
         bfin_byte4_reloc,      /* special_function.  */
         "R_byte4_data",        /* name.  */
         "R_BFIN_BYTE4_DATA",   /* name.  */
         FALSE,                 /* partial_inplace.  */
         FALSE,                 /* partial_inplace.  */
         0,                      /* src_mask.  */
         0,                      /* src_mask.  */
         0xFFFFFFFF,            /* dst_mask.  */
         0xFFFFFFFF,            /* dst_mask.  */
         TRUE),                 /* pcrel_offset.  */
         TRUE),                 /* pcrel_offset.  */
 
 
  HOWTO (R_pcrel11,             /* type.  */
  HOWTO (R_BFIN_PCREL11,        /* type.  */
         1,                     /* rightshift.  */
         1,                     /* rightshift.  */
         1,                     /* size (0 = byte, 1 = short, 2 = long).  */
         1,                     /* size (0 = byte, 1 = short, 2 = long).  */
         10,                    /* bitsize.  */
         10,                    /* bitsize.  */
         TRUE,                  /* pc_relative.  */
         TRUE,                  /* pc_relative.  */
         0,                      /* bitpos.  */
         0,                      /* bitpos.  */
         complain_overflow_unsigned, /* complain_on_overflow.  */
         complain_overflow_unsigned, /* complain_on_overflow.  */
         bfin_bfd_reloc,        /* special_function.  */
         bfin_bfd_reloc,        /* special_function.  */
         "R_pcrel11",           /* name.  */
         "R_BFIN_PCREL11",      /* name.  */
         FALSE,                 /* partial_inplace.  */
         FALSE,                 /* partial_inplace.  */
         0,                      /* src_mask.  */
         0,                      /* src_mask.  */
         0x000003FF,            /* dst_mask.  */
         0x000003FF,            /* dst_mask.  */
         FALSE),                /* pcrel_offset.  */
         FALSE),                /* pcrel_offset.  */
 
 
Line 929... Line 929...
         FALSE),                /* pcrel_offset */
         FALSE),                /* pcrel_offset */
};
};
 
 
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.  */
         0,                      /* rightshift.  */
         1,                     /* size (0 = byte, 1 = short, 2 = long).  */
         1,                     /* size (0 = byte, 1 = short, 2 = long).  */
         16,                    /* bitsize.  */
         16,                    /* bitsize.  */
         FALSE,                 /* pc_relative.  */
         FALSE,                 /* pc_relative.  */
         0,                      /* bitpos.  */
         0,                      /* bitpos.  */
         complain_overflow_bitfield, /* complain_on_overflow.  */
         complain_overflow_bitfield, /* complain_on_overflow.  */
         bfin_pltpc_reloc,      /* special_function.  */
         bfin_pltpc_reloc,      /* special_function.  */
         "R_pltpc",             /* name.  */
         "R_BFIN_PLTPC",        /* name.  */
         FALSE,                 /* partial_inplace.  */
         FALSE,                 /* partial_inplace.  */
         0xffff,                /* src_mask.  */
         0xffff,                /* src_mask.  */
         0xffff,                /* dst_mask.  */
         0xffff,                /* dst_mask.  */
         FALSE),                /* pcrel_offset.  */
         FALSE),                /* pcrel_offset.  */
 
 
  HOWTO (R_got,                 /* type.  */
  HOWTO (R_BFIN_GOT,            /* type.  */
         0,                      /* rightshift.  */
         0,                      /* rightshift.  */
         1,                     /* size (0 = byte, 1 = short, 2 = long).  */
         1,                     /* size (0 = byte, 1 = short, 2 = long).  */
         16,                    /* bitsize.  */
         16,                    /* bitsize.  */
         FALSE,                 /* pc_relative.  */
         FALSE,                 /* pc_relative.  */
         0,                      /* bitpos.  */
         0,                      /* bitpos.  */
         complain_overflow_bitfield, /* complain_on_overflow.  */
         complain_overflow_bitfield, /* complain_on_overflow.  */
         bfd_elf_generic_reloc, /* special_function.  */
         bfd_elf_generic_reloc, /* special_function.  */
         "R_got",               /* name.  */
         "R_BFIN_GOT",          /* name.  */
         FALSE,                 /* partial_inplace.  */
         FALSE,                 /* partial_inplace.  */
         0x7fff,                /* src_mask.  */
         0x7fff,                /* src_mask.  */
         0x7fff,                /* dst_mask.  */
         0x7fff,                /* dst_mask.  */
         FALSE),                /* pcrel_offset.  */
         FALSE),                /* pcrel_offset.  */
 
 
Line 996... Line 996...
  unsigned int                  bfin_reloc_val;
  unsigned int                  bfin_reloc_val;
};
};
 
 
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_NONE,                     R_BFIN_UNUSED0 },
  { BFD_RELOC_BFIN_5_PCREL,             R_pcrel5m2 },
  { BFD_RELOC_BFIN_5_PCREL,             R_BFIN_PCREL5M2 },
  { BFD_RELOC_NONE,                     R_unused1 },
  { BFD_RELOC_NONE,                     R_BFIN_UNUSED1 },
  { BFD_RELOC_BFIN_10_PCREL,            R_pcrel10 },
  { BFD_RELOC_BFIN_10_PCREL,            R_BFIN_PCREL10 },
  { BFD_RELOC_BFIN_12_PCREL_JUMP,       R_pcrel12_jump },
  { BFD_RELOC_BFIN_12_PCREL_JUMP,       R_BFIN_PCREL12_JUMP },
  { BFD_RELOC_BFIN_16_IMM,              R_rimm16 },
  { BFD_RELOC_BFIN_16_IMM,              R_BFIN_RIMM16 },
  { BFD_RELOC_BFIN_16_LOW,              R_luimm16 },
  { BFD_RELOC_BFIN_16_LOW,              R_BFIN_LUIMM16 },
  { BFD_RELOC_BFIN_16_HIGH,             R_huimm16 },
  { BFD_RELOC_BFIN_16_HIGH,             R_BFIN_HUIMM16 },
  { BFD_RELOC_BFIN_12_PCREL_JUMP_S,     R_pcrel12_jump_s },
  { BFD_RELOC_BFIN_12_PCREL_JUMP_S,     R_BFIN_PCREL12_JUMP_S },
  { BFD_RELOC_24_PCREL,                 R_pcrel24 },
  { BFD_RELOC_24_PCREL,                 R_BFIN_PCREL24 },
  { BFD_RELOC_24_PCREL,                 R_pcrel24 },
  { BFD_RELOC_24_PCREL,                 R_BFIN_PCREL24 },
  { BFD_RELOC_BFIN_24_PCREL_JUMP_L,     R_pcrel24_jump_l },
  { BFD_RELOC_BFIN_24_PCREL_JUMP_L,     R_BFIN_PCREL24_JUMP_L },
  { BFD_RELOC_NONE,                     R_unusedb },
  { BFD_RELOC_NONE,                     R_BFIN_UNUSEDB },
  { BFD_RELOC_NONE,                     R_unusedc },
  { BFD_RELOC_NONE,                     R_BFIN_UNUSEDC },
  { BFD_RELOC_BFIN_24_PCREL_CALL_X,     R_pcrel24_call_x },
  { BFD_RELOC_BFIN_24_PCREL_CALL_X,     R_BFIN_PCREL24_CALL_X },
  { BFD_RELOC_8,                        R_byte_data },
  { BFD_RELOC_8,                        R_BFIN_BYTE_DATA },
  { BFD_RELOC_16,                       R_byte2_data },
  { BFD_RELOC_16,                       R_BFIN_BYTE2_DATA },
  { BFD_RELOC_32,                       R_byte4_data },
  { BFD_RELOC_32,                       R_BFIN_BYTE4_DATA },
  { BFD_RELOC_BFIN_11_PCREL,            R_pcrel11 },
  { BFD_RELOC_BFIN_11_PCREL,            R_BFIN_PCREL11 },
  { BFD_RELOC_BFIN_GOT,                 R_got },
  { BFD_RELOC_BFIN_GOT,                 R_BFIN_GOT },
  { BFD_RELOC_BFIN_PLTPC,               R_pltpc },
  { BFD_RELOC_BFIN_PLTPC,               R_BFIN_PLTPC },
 
 
  { BFD_RELOC_BFIN_GOT17M4,      R_BFIN_GOT17M4 },
  { BFD_RELOC_BFIN_GOT17M4,      R_BFIN_GOT17M4 },
  { BFD_RELOC_BFIN_GOTHI,      R_BFIN_GOTHI },
  { BFD_RELOC_BFIN_GOTHI,      R_BFIN_GOTHI },
  { BFD_RELOC_BFIN_GOTLO,      R_BFIN_GOTLO },
  { BFD_RELOC_BFIN_GOTLO,      R_BFIN_GOTLO },
  { BFD_RELOC_BFIN_FUNCDESC,   R_BFIN_FUNCDESC },
  { BFD_RELOC_BFIN_FUNCDESC,   R_BFIN_FUNCDESC },
Line 1121... Line 1121...
 
 
/* Return TRUE if the name is a local label.
/* Return TRUE if the name is a local label.
   bfin local labels begin with L$.  */
   bfin local labels begin with L$.  */
static bfd_boolean
static bfd_boolean
bfin_is_local_label_name (
bfin_is_local_label_name (
     bfd *abfd ATTRIBUTE_UNUSED,
     bfd *abfd,
     const char *label)
     const char *label)
{
{
  if (label[0] == 'L' && label[1] == '$' )
  if (label[0] == 'L' && label[1] == '$' )
    return TRUE;
    return TRUE;
 
 
  return _bfd_elf_is_local_label_name (abfd, label);
  return _bfd_elf_is_local_label_name (abfd, label);
}
}
 

 
/* 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;
static bfd_boolean
#define IS_FDPIC(bfd) ((bfd)->xvec == &bfd_elf32_bfinfdpic_vec)
bfin_check_relocs (bfd * abfd,
 
                   struct bfd_link_info *info,
/* An extension of the elf hash table data structure, containing some
                   asection *sec,
   additional Blackfin-specific data.  */
                   const Elf_Internal_Rela *relocs)
struct bfinfdpic_elf_link_hash_table
 
{
{
  struct elf_link_hash_table elf;
  bfd *dynobj;
 
  Elf_Internal_Shdr *symtab_hdr;
  /* A pointer to the .got section.  */
  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 *srelgot;
  asection *sgotrel;
  if (info->relocatable)
  /* A pointer to the .rofixup section.  */
    return TRUE;
  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.  */
  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);
 
 
#define bfinfdpic_hash_table(info) \
  sgot = NULL;
  ((struct bfinfdpic_elf_link_hash_table *) ((info)->hash))
  srelgot = NULL;
 
 
#define bfinfdpic_got_section(info) \
  rel_end = relocs + sec->reloc_count;
  (bfinfdpic_hash_table (info)->sgot)
  for (rel = relocs; rel < rel_end; rel++)
#define bfinfdpic_gotrel_section(info) \
    {
  (bfinfdpic_hash_table (info)->sgotrel)
      unsigned long r_symndx;
#define bfinfdpic_gotfixup_section(info) \
      struct elf_link_hash_entry *h;
  (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.  */
      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];
 
 
static struct bfd_link_hash_table *
      switch (ELF32_R_TYPE (rel->r_info))
bfinfdpic_elf_link_hash_table_create (bfd *abfd)
 
{
{
  struct bfinfdpic_elf_link_hash_table *ret;
       /* This relocation describes the C++ object vtable hierarchy.
  bfd_size_type amt = sizeof (struct bfinfdpic_elf_link_hash_table);
           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;
 
 
  ret = bfd_zalloc (abfd, amt);
        /* This relocation describes which C++ vtable entries
  if (ret == NULL)
           are actually used.  Record for later use during GC.  */
    return NULL;
        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;
 
 
  if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd,
        case R_BFIN_GOT:
                                      _bfd_elf_link_hash_newfunc,
          if (h != NULL
                                      sizeof (struct elf_link_hash_entry)))
              && strcmp (h->root.root.string, "__GLOBAL_OFFSET_TABLE_") == 0)
 
            break;
 
          /* Fall through.  */
 
 
 
          if (dynobj == NULL)
    {
    {
      free (ret);
              /* Create the .got section.  */
      return NULL;
              elf_hash_table (info)->dynobj = dynobj = abfd;
 
              if (!_bfd_elf_create_got_section (dynobj, info))
 
                return FALSE;
    }
    }
 
 
  return &ret->elf.root;
          if (sgot == NULL)
 
            {
 
              sgot = bfd_get_section_by_name (dynobj, ".got");
 
              BFD_ASSERT (sgot != NULL);
}
}
 
 
/* Decide whether a reference to a symbol can be resolved locally or
          if (srelgot == NULL && (h != NULL || info->shared))
   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)
 
 
 
/* 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
              srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
       symbol.  */
              if (srelgot == NULL)
    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;
 
 
 
  /* 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;
 
 
 
  /* The number of R_byte4_data, R_BFIN_FUNCDESC and R_BFIN_FUNCDESC_VALUE
 
     relocations referencing the symbol.  */
 
  unsigned relocs32, relocsfd, relocsfdv;
 
 
 
  /* The number of .rofixups entries and dynamic relocations allocated
 
     for this symbol, minus any that might have already been used.  */
 
  unsigned fixups, dynrelocs;
 
 
 
  /* 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;
 
};
 
 
 
/* 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_;
                  flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
 
                                    | SEC_IN_MEMORY | SEC_LINKER_CREATED
  return (entry->symndx == -1
                                    | SEC_READONLY);
          ? (long) entry->d.h->root.root.hash
                  srelgot = bfd_make_section_with_flags (dynobj, ".rela.got",
          : entry->symndx + (long) entry->d.abfd->id * 257) + entry->addend;
                                                         flags);
 
                  if (srelgot == NULL
 
                      || !bfd_set_section_alignment (dynobj, srelgot, 2))
 
                    return FALSE;
 
                }
}
}
 
 
/* Test whether the key fields of two bfinfdpic_relocs_info entries are
          if (h != NULL)
   identical.  */
 
static int
 
bfinfdpic_relocs_info_eq (const void *entry1, const void *entry2)
 
{
{
  const struct bfinfdpic_relocs_info *e1 = entry1;
              if (h->got.refcount == 0)
  const struct bfinfdpic_relocs_info *e2 = entry2;
                {
 
                  /* 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 e1->symndx == e2->symndx && e1->addend == e2->addend
                  /* Allocate space in the .got section.  */
    && (e1->symndx == -1 ? e1->d.h == e2->d.h : e1->d.abfd == e2->d.abfd);
                  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;
 
 
/* Find or create an entry in a hash table HT that matches the key
                  size = symtab_hdr->sh_info;
   fields of the given ENTRY.  If it's not found, memory for a new
                  size *= sizeof (bfd_signed_vma);
   entry is allocated in ABFD's obstack.  */
                  local_got_refcounts = ((bfd_signed_vma *)
static struct bfinfdpic_relocs_info *
                                         bfd_zalloc (abfd, size));
bfinfdpic_relocs_info_find (struct htab *ht,
                  if (local_got_refcounts == NULL)
                           bfd *abfd,
                    return FALSE;
                           const struct bfinfdpic_relocs_info *entry,
                  elf_local_got_refcounts (abfd) = local_got_refcounts;
                           enum insert_option insert)
                }
 
              if (local_got_refcounts[r_symndx] == 0)
{
{
  struct bfinfdpic_relocs_info **loc =
                  sgot->size += 4;
    (struct bfinfdpic_relocs_info **) htab_find_slot (ht, entry, insert);
                  if (info->shared)
 
                    {
  if (! loc)
                      /* If we are generating a shared object, we need to
    return NULL;
                         output a R_68K_RELATIVE reloc so that the dynamic
 
                         linker can adjust this GOT entry.  */
  if (*loc)
                      srelgot->size += sizeof (Elf32_External_Rela);
    return *loc;
                    }
 
                }
  *loc = bfd_zalloc (abfd, sizeof (**loc));
              local_got_refcounts[r_symndx]++;
 
            }
  if (! *loc)
          break;
    return *loc;
 
 
 
  (*loc)->symndx = entry->symndx;
        default:
  (*loc)->d = entry->d;
          break;
  (*loc)->addend = entry->addend;
        }
  (*loc)->plt_entry = (bfd_vma)-1;
    }
  (*loc)->lzplt_entry = (bfd_vma)-1;
 
 
 
  return *loc;
  return TRUE;
}
}
 
 
/* Obtain the address of the entry in HT associated with H's symbol +
static enum elf_reloc_type_class
   addend, creating a new entry if none existed.  ABFD is only used
elf32_bfin_reloc_type_class (const Elf_Internal_Rela * rela)
   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;
  switch ((int) ELF32_R_TYPE (rela->r_info))
 
    {
  entry.symndx = -1;
    default:
  entry.d.h = h;
      return reloc_class_normal;
  entry.addend = addend;
    }
 
 
  return bfinfdpic_relocs_info_find (ht, abfd, &entry, insert);
 
}
}
 

 
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)
 
{
 
  int r_type = ELF32_R_TYPE (rel->r_info);
 
 
/* Obtain the address of the entry in HT associated with the SYMNDXth
  if (r_type == R_BFIN_PCREL24 || r_type == R_BFIN_PCREL24_JUMP_L)
   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;
      bfd_reloc_status_type r = bfd_reloc_ok;
 
      bfd_vma x;
 
 
  entry.symndx = symndx;
      if (address > bfd_get_section_limit (input_bfd, input_section))
  entry.d.abfd = abfd;
        return bfd_reloc_outofrange;
  entry.addend = addend;
 
 
 
  return bfinfdpic_relocs_info_find (ht, abfd, &entry, insert);
      value += addend;
}
 
 
 
/* Merge fields set by check_relocs() of two entries that end up being
      /* Perform usual pc-relative correction.  */
   mapped to the same (presumably global) symbol.  */
      value -= input_section->output_section->vma + input_section->output_offset;
 
      value -= address;
 
 
inline static void
      /* We are getting reloc_entry->address 2 byte off from
bfinfdpic_pic_merge_early_relocs_info (struct bfinfdpic_relocs_info *e2,
         the start of instruction. Assuming absolute postion
                                      struct bfinfdpic_relocs_info const *e1)
         of the reloc data. But, following code had been written assuming
{
         reloc address is starting at begining of instruction.
  e2->got17m4 |= e1->got17m4;
         To compensate that I have increased the value of
  e2->gothilo |= e1->gothilo;
         relocation by 1 (effectively 2) and used the addr -2 instead of addr.  */
  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;
 
}
 
 
 
/* Every block of 65535 lazy PLT entries shares a single call to the
      value += 2;
   resolver, inserted in the 32768th lazy PLT entry (i.e., entry #
      address -= 2;
   32767, counting from 0).  All other lazy PLT entries branch to it
 
   in a single instruction.  */
 
 
 
#define LZPLT_RESOLVER_EXTRA 10
      if ((value & 0xFF000000) != 0
#define LZPLT_NORMAL_SIZE 6
          && (value & 0xFF000000) != 0xFF000000)
#define LZPLT_ENTRIES 1362
        r = bfd_reloc_overflow;
 
 
#define BFINFDPIC_LZPLT_BLOCK_SIZE ((bfd_vma) LZPLT_NORMAL_SIZE * LZPLT_ENTRIES + LZPLT_RESOLVER_EXTRA)
      value >>= 1;
#define BFINFDPIC_LZPLT_RESOLV_LOC (LZPLT_NORMAL_SIZE * LZPLT_ENTRIES / 2)
 
 
 
/* Add a dynamic relocation to the SRELOC section.  */
      x = bfd_get_16 (input_bfd, contents + address);
 
      x = (x & 0xff00) | ((value >> 16) & 0xff);
 
      bfd_put_16 (input_bfd, x, contents + address);
 
 
inline static bfd_vma
      x = bfd_get_16 (input_bfd, contents + address + 2);
_bfinfdpic_add_dyn_reloc (bfd *output_bfd, asection *sreloc, bfd_vma offset,
      x = value & 0xFFFF;
                         int reloc_type, long dynindx, bfd_vma addend,
      bfd_put_16 (input_bfd, x, contents + address + 2);
                         struct bfinfdpic_relocs_info *entry)
      return r;
{
    }
  Elf_Internal_Rela outrel;
 
  bfd_vma reloc_offset;
 
 
 
  outrel.r_offset = offset;
  return _bfd_final_link_relocate (howto, input_bfd, input_section, contents,
  outrel.r_info = ELF32_R_INFO (dynindx, reloc_type);
                                   rel->r_offset, value, addend);
  outrel.r_addend = addend;
 
 
 
  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++;
 
 
 
  /* If the entry's index is zero, this relocation was probably to a
static bfd_boolean
     linkonce section that got discarded.  We reserved a dynamic
bfin_relocate_section (bfd * output_bfd,
     relocation, but it was for another entry than the one we got at
                       struct bfd_link_info *info,
     the time of emitting the relocation.  Unfortunately there's no
                       bfd * input_bfd,
     simple way for us to catch this situation, since the relocation
                       asection * input_section,
     is cleared right before calling relocate_section, at which point
                       bfd_byte * contents,
     we no longer know what the relocation used to point to.  */
                       Elf_Internal_Rela * relocs,
  if (entry->symndx)
                       Elf_Internal_Sym * local_syms,
 
                       asection ** local_sections)
    {
    {
      BFD_ASSERT (entry->dynrelocs > 0);
  bfd *dynobj;
      entry->dynrelocs--;
  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;
 
 
  return reloc_offset;
  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);
 
 
/* Add a fixup to the ROFIXUP section.  */
  sgot = NULL;
 
 
static bfd_vma
  rel = relocs;
_bfinfdpic_add_rofixup (bfd *output_bfd, asection *rofixup, bfd_vma offset,
  relend = relocs + input_section->reloc_count;
                       struct bfinfdpic_relocs_info *entry)
  for (; rel < relend; rel++, i++)
{
{
  bfd_vma fixup_offset;
      int r_type;
 
      reloc_howto_type *howto;
  if (rofixup->flags & SEC_EXCLUDE)
      unsigned long r_symndx;
    return -1;
      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;
 
 
  fixup_offset = rofixup->reloc_count * 4;
      r_type = ELF32_R_TYPE (rel->r_info);
  if (rofixup->contents)
      if (r_type < 0 || r_type >= 243)
    {
    {
      BFD_ASSERT (fixup_offset < rofixup->size);
          bfd_set_error (bfd_error_bad_value);
      bfd_put_32 (output_bfd, offset, rofixup->contents + fixup_offset);
          return FALSE;
    }
    }
  rofixup->reloc_count++;
 
 
 
  if (entry && entry->symndx)
      if (r_type == R_BFIN_GNU_VTENTRY
    {
          || r_type == R_BFIN_GNU_VTINHERIT)
      /* See discussion about symndx == 0 in _bfinfdpic_add_dyn_reloc
        continue;
         above.  */
 
      BFD_ASSERT (entry->fixups > 0);
 
      entry->fixups--;
 
    }
 
 
 
  return fixup_offset;
      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);
 
 
/* Find the segment number in which OSEC, and output section, is
      h = NULL;
   located.  */
      sym = NULL;
 
      sec = NULL;
 
      unresolved_reloc = FALSE;
 
 
static unsigned
      if (r_symndx < symtab_hdr->sh_info)
_bfinfdpic_osec_to_segment (bfd *output_bfd, asection *osec)
 
{
{
  Elf_Internal_Phdr *p = _bfd_elf_find_segment_containing_section (output_bfd, osec);
          sym = local_syms + r_symndx;
 
          sec = local_sections[r_symndx];
  return (p != NULL) ? p - elf_tdata (output_bfd)->phdr : -1;
          relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
}
}
 
      else
inline static bfd_boolean
 
_bfinfdpic_osec_readonly_p (bfd *output_bfd, asection *osec)
 
{
{
  unsigned seg = _bfinfdpic_osec_to_segment (output_bfd, osec);
          bfd_boolean warned;
 
 
  return ! (elf_tdata (output_bfd)->phdr[seg].p_flags & PF_W);
 
}
 
 
 
/* Generate relocations for GOT entries, function descriptors, and
          RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
   code for PLT and lazy PLT entries.  */
                                   r_symndx, symtab_hdr, sym_hashes,
 
                                   h, sec, relocation,
 
                                   unresolved_reloc, warned);
 
        }
 
 
inline static bfd_boolean
      if (sec != NULL && elf_discarded_section (sec))
_bfinfdpic_emit_got_relocs_plt_entries (struct bfinfdpic_relocs_info *entry,
        {
                                        bfd *output_bfd,
          /* For relocs against symbols from removed linkonce sections,
                                        struct bfd_link_info *info,
             or sections discarded by a linker script, we just want the
                                        asection *sec,
             section contents zeroed.  Avoid any special processing.  */
                                        Elf_Internal_Sym *sym,
          _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
                                        bfd_vma addend)
          rel->r_info = 0;
 
          rel->r_addend = 0;
 
          continue;
 
        }
 
 
 
      if (info->relocatable)
 
        continue;
 
 
 
      address = rel->r_offset;
 
 
 
      /* Then, process normally.  */
 
      switch (r_type)
{
{
  bfd_vma fd_lazy_rel_offset = (bfd_vma)-1;
        case R_BFIN_GNU_VTINHERIT:
  int dynindx = -1;
        case R_BFIN_GNU_VTENTRY:
 
          return bfd_reloc_ok;
 
 
  if (entry->done)
        case R_BFIN_GOT:
    return TRUE;
          /* Relocation is to the address of the entry for this symbol
  entry->done = 1;
             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.  */
 
 
  if (entry->got_entry || entry->fdgot_entry || entry->fd_entry)
 
    {
    {
      /* If the symbol is dynamic, consider it for dynamic
            bfd_vma off;
         relocations, otherwise decay to section + offset.  */
 
      if (entry->symndx == -1 && entry->d.h->dynindx != -1)
          if (dynobj == NULL)
        dynindx = entry->d.h->dynindx;
 
      else
 
        {
        {
          if (sec->output_section
              /* Create the .got section.  */
              && ! bfd_is_abs_section (sec->output_section)
              elf_hash_table (info)->dynobj = dynobj = output_bfd;
              && ! bfd_is_und_section (sec->output_section))
              if (!_bfd_elf_create_got_section (dynobj, info))
            dynindx = elf_section_data (sec->output_section)->dynindx;
                return FALSE;
          else
 
            dynindx = 0;
 
        }
        }
 
 
 
            if (sgot == NULL)
 
              {
 
                sgot = bfd_get_section_by_name (dynobj, ".got");
 
                BFD_ASSERT (sgot != NULL);
    }
    }
 
 
  /* Generate relocation for GOT entry pointing to the symbol.  */
            if (h != NULL)
  if (entry->got_entry)
 
    {
    {
      int idx = dynindx;
                bfd_boolean dyn;
      bfd_vma ad = addend;
 
 
 
      /* If the symbol is dynamic but binds locally, use
                off = h->got.offset;
         section+offset.  */
                BFD_ASSERT (off != (bfd_vma) - 1);
      if (sec && (entry->symndx != -1
                dyn = elf_hash_table (info)->dynamic_sections_created;
                  || BFINFDPIC_SYM_LOCAL (info, entry->d.h)))
 
 
                if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
 
                    || (info->shared
 
                        && (info->symbolic
 
                            || h->dynindx == -1
 
                            || h->forced_local)
 
                        && h->def_regular))
        {
        {
          if (entry->symndx == -1)
                    /* This is actually a static link, or it is a
            ad += entry->d.h->root.u.def.value;
                       -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
          else
            ad += sym->st_value;
                      {
          ad += sec->output_offset;
                        bfd_put_32 (output_bfd, relocation,
          if (sec->output_section && elf_section_data (sec->output_section))
                                    sgot->contents + off);
            idx = elf_section_data (sec->output_section)->dynindx;
                        h->got.offset |= 1;
 
                      }
 
                  }
          else
          else
            idx = 0;
                  unresolved_reloc = FALSE;
        }
        }
 
            else
 
              {
 
                BFD_ASSERT (local_got_offsets != NULL);
 
                off = local_got_offsets[r_symndx];
 
                BFD_ASSERT (off != (bfd_vma) - 1);
 
 
      /* If we're linking an executable at a fixed address, we can
                /* The offset must always be a multiple of 4.  We use
         omit the dynamic relocation as long as the symbol is local to
                   the least significant bit to record whether we have
         this module.  */
                   already generated the necessary reloc.  */
      if (info->executable && !info->pie
                if ((off & 1) != 0)
          && (entry->symndx != -1
                  off &= ~1;
              || BFINFDPIC_SYM_LOCAL (info, entry->d.h)))
                else
        {
        {
          if (sec)
                    bfd_put_32 (output_bfd, relocation, sgot->contents + off);
            ad += sec->output_section->vma;
 
          if (entry->symndx != -1
                    if (info->shared)
              || entry->d.h->root.type != bfd_link_hash_undefweak)
                      {
            _bfinfdpic_add_rofixup (output_bfd,
                        asection *s;
                                   bfinfdpic_gotfixup_section (info),
                        Elf_Internal_Rela outrel;
                                   bfinfdpic_got_section (info)->output_section
                        bfd_byte *loc;
                                   ->vma
 
                                   + bfinfdpic_got_section (info)->output_offset
                        s = bfd_get_section_by_name (dynobj, ".rela.got");
                                   + bfinfdpic_got_initial_offset (info)
                        BFD_ASSERT (s != NULL);
                                   + entry->got_entry, entry);
 
 
                        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);
        }
        }
      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);
 
 
 
      bfd_put_32 (output_bfd, ad,
                    local_got_offsets[r_symndx] |= 1;
                  bfinfdpic_got_section (info)->contents
                  }
                  + bfinfdpic_got_initial_offset (info)
 
                  + entry->got_entry);
 
    }
    }
 
 
  /* Generate relocation for GOT entry pointing to a canonical
            relocation = sgot->output_offset + off;
     function descriptor.  */
            rel->r_addend = 0;
  if (entry->fdgot_entry)
            /* bfin : preg = [preg + 17bitdiv4offset] relocation is div by 4.  */
 
            relocation /= 4;
 
          }
 
          goto do_default;
 
 
 
        default:
 
        do_default:
 
          r = bfin_final_link_relocate (rel, howto, input_bfd, input_section,
 
                                        contents, address,
 
                                        relocation, rel->r_addend);
 
 
 
          break;
 
        }
 
 
 
      /* Dynamic relocs are not propagated for SEC_DEBUGGING sections
 
         because such sections are not SEC_ALLOC and thus ld.so will
 
         not process them.  */
 
      if (unresolved_reloc
 
          && !((input_section->flags & SEC_DEBUGGING) != 0 && h->def_dynamic))
    {
    {
      int reloc, idx;
          (*_bfd_error_handler)
      bfd_vma ad = 0;
            (_("%B(%A+0x%lx): unresolvable relocation against symbol `%s'"),
 
             input_bfd,
 
             input_section, (long) rel->r_offset, h->root.root.string);
 
          return FALSE;
 
        }
 
 
      if (! (entry->symndx == -1
      if (r != bfd_reloc_ok)
             && 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
          const char *name;
             resolution because we are, or are linked with, a shared
 
             library, emit a FUNCDESC relocation such that the dynamic
          if (h != NULL)
             linker will allocate the function descriptor.  If the
            name = h->root.root.string;
             symbol needs a non-local function descriptor but binds
          else
             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;
              name = bfd_elf_string_from_elf_section (input_bfd,
              idx = elf_section_data (entry->d.h->root.u.def.section
                                                      symtab_hdr->sh_link,
                                      ->output_section)->dynindx;
                                                      sym->st_name);
              ad = entry->d.h->root.u.def.section->output_offset
              if (name == NULL)
                + entry->d.h->root.u.def.value;
                return FALSE;
 
              if (*name == '\0')
 
                name = bfd_section_name (input_bfd, sec);
            }
            }
          else if (entry->symndx == -1
 
                   && ! BFINFDPIC_FUNCDESC_LOCAL (info, entry->d.h))
          if (r == bfd_reloc_overflow)
            {
            {
              reloc = R_BFIN_FUNCDESC;
              if (!(info->callbacks->reloc_overflow
              idx = dynindx;
                    (info, (h ? &h->root : NULL), name, howto->name,
              ad = addend;
                     (bfd_vma) 0, input_bfd, input_section, rel->r_offset)))
              if (ad)
 
                return FALSE;
                return FALSE;
            }
            }
          else
          else
            {
            {
              /* Otherwise, we know we have a private function descriptor,
              (*_bfd_error_handler)
                 so reference it directly.  */
                (_("%B(%A+0x%lx): reloc against `%s': error %d"),
              if (elf_hash_table (info)->dynamic_sections_created)
                 input_bfd, input_section,
                BFD_ASSERT (entry->privfd);
                 (long) rel->r_offset, name, (int) r);
              reloc = R_byte4_data;
              return FALSE;
              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,
  return TRUE;
                  bfinfdpic_got_section (info)->contents
 
                  + bfinfdpic_got_initial_offset (info)
 
                  + entry->fdgot_entry);
 
    }
    }
 
 
  /* Generate relocation to fill in a private function descriptor in
static asection *
     the GOT.  */
bfin_gc_mark_hook (asection * sec,
  if (entry->fd_entry)
                   struct bfd_link_info *info,
 
                   Elf_Internal_Rela * rel,
 
                   struct elf_link_hash_entry *h,
 
                   Elf_Internal_Sym * sym)
    {
    {
      int idx = dynindx;
  if (h != NULL)
      bfd_vma ad = addend;
    switch (ELF32_R_TYPE (rel->r_info))
      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)
      case R_BFIN_GNU_VTINHERIT:
            ad += entry->d.h->root.u.def.value;
      case R_BFIN_GNU_VTENTRY:
          else
        return NULL;
            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
  return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
         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
/* Update the got entry reference counts for the section being removed.  */
         addresses of the symbol and of the local GOT base offset.  */
 
      if (info->executable && !info->pie && sec && sec->output_section)
static bfd_boolean
        {
bfin_gc_sweep_hook (bfd * abfd,
          lowword = ad;
                    struct bfd_link_info *info,
          highword = bfinfdpic_got_section (info)->output_section->vma
                    asection * sec,
            + bfinfdpic_got_section (info)->output_offset
                    const Elf_Internal_Rela * relocs)
            + bfinfdpic_got_initial_offset (info);
 
        }
 
      else if (entry->lazyplt)
 
        {
        {
          if (ad)
  Elf_Internal_Shdr *symtab_hdr;
            return FALSE;
  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;
 
 
          fd_lazy_rel_offset = ofst;
  dynobj = elf_hash_table (info)->dynobj;
 
  if (dynobj == NULL)
 
    return TRUE;
 
 
          /* A function descriptor used for lazy or local resolving is
  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
             initialized such that its high word contains the output
  sym_hashes = elf_sym_hashes (abfd);
             section index in which the PLT entries are located, and
  local_got_refcounts = elf_local_got_refcounts (abfd);
             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,
  sgot = bfd_get_section_by_name (dynobj, ".got");
                  bfinfdpic_got_section (info)->contents
  srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
                  + 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.  */
  relend = relocs + sec->reloc_count;
  if (entry->plt_entry != (bfd_vma) -1)
  for (rel = relocs; rel < relend; rel++)
    {
    {
      bfd_byte *plt_code = bfinfdpic_plt_section (info)->contents
      unsigned long r_symndx;
        + entry->plt_entry;
      struct elf_link_hash_entry *h;
 
 
      BFD_ASSERT (entry->fd_entry);
 
 
 
      /* Figure out what kind of PLT entry we need, depending on the
      switch (ELF32_R_TYPE (rel->r_info))
         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] */
        case R_BFIN_GOT:
          bfd_put_32 (output_bfd,
          r_symndx = ELF32_R_SYM (rel->r_info);
                      0xe519 | ((entry->fd_entry << 14) & 0xFFFF0000),
          if (r_symndx >= symtab_hdr->sh_info)
                      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;
              h = sym_hashes[r_symndx - symtab_hdr->sh_info];
             P3 = P3 + P1;
              if (h->got.refcount > 0)
             P1 = [P3];
                {
             P3 = [P3 + 4];  */
                  --h->got.refcount;
          bfd_put_32 (output_bfd,
                  if (h->got.refcount == 0)
                      0xe109 | (entry->fd_entry << 16),
                    {
                      plt_code);
                      /* We don't need the .got entry any more.  */
          bfd_put_32 (output_bfd,
                      sgot->size -= 4;
                      0xe149 | (entry->fd_entry & 0xFFFF0000),
                      srelgot->size -= sizeof (Elf32_External_Rela);
                      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.  */
          else if (local_got_refcounts != NULL)
  if (entry->lzplt_entry != (bfd_vma) -1)
 
    {
    {
      bfd_byte *lzplt_code = bfinfdpic_plt_section (info)->contents
              if (local_got_refcounts[r_symndx] > 0)
        + 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.
                  --local_got_refcounts[r_symndx];
             P2 = [P3];
                  if (local_got_refcounts[r_symndx] == 0)
             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 */
                      /* We don't need the .got entry any more.  */
          bfd_put_16 (output_bfd,
                      sgot->size -= 4;
                      0x2000
                      if (info->shared)
                      | (((resolverStub_addr - entry->lzplt_entry)
                        srelgot->size -= sizeof (Elf32_External_Rela);
                          / 2) & (((bfd_vma)1 << 12) - 1)),
                    }
                      lzplt_code);
                }
 
            }
 
          break;
 
        default:
 
          break;
        }
        }
    }
    }
 
 
  return TRUE;
  return TRUE;
}
}
 

 
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
/* Look through the relocs for a section during the first phase, and
   additional Blackfin-specific data.  */
   allocate space in the global offset table or procedure linkage
struct bfinfdpic_elf_link_hash_table
   table.  */
 
 
 
static bfd_boolean
 
bfin_check_relocs (bfd * abfd,
 
                   struct bfd_link_info *info,
 
                   asection *sec,
 
                   const Elf_Internal_Rela *relocs)
 
{
{
  bfd *dynobj;
  struct elf_link_hash_table elf;
  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;
  /* A pointer to the .got section.  */
  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
  asection *sgot;
  sym_hashes = elf_sym_hashes (abfd);
  /* A pointer to the .rel.got section.  */
  local_got_refcounts = elf_local_got_refcounts (abfd);
  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;
 
};
 
 
  sgot = NULL;
/* Get the Blackfin ELF linker hash table from a link_info structure.  */
  srelgot = NULL;
 
  sreloc = NULL;
 
 
 
  rel_end = relocs + sec->reloc_count;
#define bfinfdpic_hash_table(info) \
  for (rel = relocs; rel < rel_end; rel++)
  ((struct bfinfdpic_elf_link_hash_table *) ((info)->hash))
    {
 
      unsigned long r_symndx;
 
      struct elf_link_hash_entry *h;
 
 
 
      r_symndx = ELF32_R_SYM (rel->r_info);
#define bfinfdpic_got_section(info) \
      if (r_symndx < symtab_hdr->sh_info)
  (bfinfdpic_hash_table (info)->sgot)
        h = NULL;
#define bfinfdpic_gotrel_section(info) \
      else
  (bfinfdpic_hash_table (info)->sgotrel)
        h = sym_hashes[r_symndx - symtab_hdr->sh_info];
#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)
 
 
      switch (ELF32_R_TYPE (rel->r_info))
/* The name of the dynamic interpreter.  This is put in the .interp
        {
   section.  */
       /* 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 relocation describes which C++ vtable entries
#define ELF_DYNAMIC_INTERPRETER "/lib/ld.so.1"
           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;
 
 
 
        case R_got:
#define DEFAULT_STACK_SIZE 0x20000
          if (h != NULL
 
              && strcmp (h->root.root.string, "__GLOBAL_OFFSET_TABLE_") == 0)
 
            break;
 
          /* Fall through.  */
 
 
 
          if (dynobj == NULL)
/* This structure is used to collect the number of entries present in
 
   each addressable range of the got.  */
 
struct _bfinfdpic_dynamic_got_info
            {
            {
              /* Create the .got section.  */
  /* Several bits of information about the current link.  */
              elf_hash_table (info)->dynobj = dynobj = abfd;
  struct bfd_link_info *info;
              if (!_bfd_elf_create_got_section (dynobj, info))
  /* Total size needed for GOT entries within the 18- or 32-bit
                return FALSE;
     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;
 
};
 
 
          if (sgot == NULL)
/* Create a Blackfin ELF linker hash table.  */
            {
 
              sgot = bfd_get_section_by_name (dynobj, ".got");
 
              BFD_ASSERT (sgot != NULL);
 
            }
 
 
 
          if (srelgot == NULL && (h != NULL || info->shared))
static struct bfd_link_hash_table *
            {
bfinfdpic_elf_link_hash_table_create (bfd *abfd)
              srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
 
              if (srelgot == NULL)
 
                {
                {
                  flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
  struct bfinfdpic_elf_link_hash_table *ret;
                                    | SEC_IN_MEMORY | SEC_LINKER_CREATED
  bfd_size_type amt = sizeof (struct bfinfdpic_elf_link_hash_table);
                                    | SEC_READONLY);
 
                  srelgot = bfd_make_section_with_flags (dynobj, ".rela.got",
 
                                                         flags);
 
                  if (srelgot == NULL
 
                      || !bfd_set_section_alignment (dynobj, srelgot, 2))
 
                    return FALSE;
 
                }
 
            }
 
 
 
          if (h != NULL)
  ret = bfd_zalloc (abfd, amt);
            {
  if (ret == NULL)
              if (h->got.refcount == 0)
    return NULL;
                {
 
                  /* Make sure this symbol is output as a dynamic symbol.  */
  if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd,
                  if (h->dynindx == -1 && !h->forced_local)
                                      _bfd_elf_link_hash_newfunc,
 
                                      sizeof (struct elf_link_hash_entry)))
                    {
                    {
                      if (!bfd_elf_link_record_dynamic_symbol (info, h))
      free (ret);
                        return FALSE;
      return NULL;
                    }
                    }
 
 
                  /* Allocate space in the .got section.  */
  return &ret->elf.root;
                  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;
 
 
 
                  size = symtab_hdr->sh_info;
/* Decide whether a reference to a symbol can be resolved locally or
                  size *= sizeof (bfd_signed_vma);
   not.  If the symbol is protected, we want the local address, but
                  local_got_refcounts = ((bfd_signed_vma *)
   its function descriptor must be assigned by the dynamic linker.  */
                                         bfd_zalloc (abfd, size));
#define BFINFDPIC_SYM_LOCAL(INFO, H) \
                  if (local_got_refcounts == NULL)
  (_bfd_elf_symbol_refs_local_p ((H), (INFO), 1) \
                    return FALSE;
   || ! elf_hash_table (INFO)->dynamic_sections_created)
                  elf_local_got_refcounts (abfd) = local_got_refcounts;
#define BFINFDPIC_FUNCDESC_LOCAL(INFO, H) \
                }
  ((H)->dynindx == -1 || ! elf_hash_table (INFO)->dynamic_sections_created)
              if (local_got_refcounts[r_symndx] == 0)
 
 
/* 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
                {
                {
                  sgot->size += 4;
  /* The index of the symbol, as stored in the relocation r_info, if
                  if (info->shared)
     we have a local symbol; -1 otherwise.  */
 
  long symndx;
 
  union
                    {
                    {
                      /* If we are generating a shared object, we need to
    /* The input bfd in which the symbol is defined, if it's a local
                         output a R_68K_RELATIVE reloc so that the dynamic
       symbol.  */
                         linker can adjust this GOT entry.  */
    bfd *abfd;
                      srelgot->size += sizeof (Elf32_External_Rela);
    /* 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).  */
              local_got_refcounts[r_symndx]++;
    struct elf_link_hash_entry *h;
            }
  } d;
          break;
  /* The addend of the relocation that references the symbol.  */
 
  bfd_vma addend;
 
 
        default:
  /* The fields above are used to identify an entry.  The fields below
          break;
     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;
 
 
  return TRUE;
  /* The number of R_BFIN_BYTE4_DATA, R_BFIN_FUNCDESC and R_BFIN_FUNCDESC_VALUE
}
     relocations referencing the symbol.  */
 
  unsigned relocs32, relocsfd, relocsfdv;
 
 
static enum elf_reloc_type_class
  /* The number of .rofixups entries and dynamic relocations allocated
elf32_bfin_reloc_type_class (const Elf_Internal_Rela * rela)
     for this symbol, minus any that might have already been used.  */
{
  unsigned fixups, dynrelocs;
  switch ((int) ELF32_R_TYPE (rela->r_info))
 
 
  /* 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;
 
};
 
 
 
/* Compute a hash with the key fields of an bfinfdpic_relocs_info entry.  */
 
static hashval_t
 
bfinfdpic_relocs_info_hash (const void *entry_)
    {
    {
    default:
  const struct bfinfdpic_relocs_info *entry = entry_;
      return reloc_class_normal;
 
    }
  return (entry->symndx == -1
 
          ? (long) entry->d.h->root.root.hash
 
          : entry->symndx + (long) entry->d.abfd->id * 257) + entry->addend;
}
}

 
/* Relocate an Blackfin ELF section.
 
 
 
   The RELOCATE_SECTION function is called by the new ELF backend linker
/* Test whether the key fields of two bfinfdpic_relocs_info entries are
   to handle the relocations for a section.
   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;
 
 
   The relocs are always passed as Rela structures; if the section
  return e1->symndx == e2->symndx && e1->addend == e2->addend
   actually uses Rel structures, the r_addend field will always be
    && (e1->symndx == -1 ? e1->d.h == e2->d.h : e1->d.abfd == e2->d.abfd);
   zero.
}
 
 
   This function is responsible for adjusting the section contents as
/* Find or create an entry in a hash table HT that matches the key
   necessary, and (if using Rela relocs and generating a relocatable
   fields of the given ENTRY.  If it's not found, memory for a new
   output file) adjusting the reloc addend as necessary.
   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;
 
 
   This function does not have to worry about setting the reloc
  if (!ht)
   address or the reloc symbol index.
    return NULL;
 
 
   LOCAL_SYMS is a pointer to the swapped in local symbols.
  loc = (struct bfinfdpic_relocs_info **) htab_find_slot (ht, entry, insert);
 
 
   LOCAL_SECTIONS is an array giving the section in the input file
  if (! loc)
   corresponding to the st_shndx field of each local symbol.
    return NULL;
 
 
   The global hash table entry for the global symbols can be found
  if (*loc)
   via elf_sym_hashes (input_bfd).
    return *loc;
 
 
   When generating relocatable output, this function must handle
  *loc = bfd_zalloc (abfd, sizeof (**loc));
   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
  if (! *loc)
bfinfdpic_relocate_section (bfd * output_bfd,
    return *loc;
                            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;
  (*loc)->symndx = entry->symndx;
  sym_hashes = elf_sym_hashes (input_bfd);
  (*loc)->d = entry->d;
  relend     = relocs + input_section->reloc_count;
  (*loc)->addend = entry->addend;
 
  (*loc)->plt_entry = (bfd_vma)-1;
 
  (*loc)->lzplt_entry = (bfd_vma)-1;
 
 
  isec_segment = _bfinfdpic_osec_to_segment (output_bfd,
  return *loc;
                                             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;
 
 
 
  for (rel = relocs; rel < relend; rel ++)
/* 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)
    {
    {
      reloc_howto_type *howto;
  struct bfinfdpic_relocs_info entry;
      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
  entry.symndx = -1;
          || r_type == R_BFIN_GNU_VTENTRY)
  entry.d.h = h;
        continue;
  entry.addend = addend;
 
 
      r_symndx = ELF32_R_SYM (rel->r_info);
  return bfinfdpic_relocs_info_find (ht, abfd, &entry, insert);
      howto = bfin_reloc_type_lookup (input_bfd, r_type);
 
      if (howto == NULL)
 
        {
 
          bfd_set_error (bfd_error_bad_value);
 
          return FALSE;
 
        }
        }
 
 
      h      = NULL;
/* Obtain the address of the entry in HT associated with the SYMNDXth
      sym    = NULL;
   local symbol of the input bfd ABFD, plus the addend, creating a new
      sec    = NULL;
   entry if none existed.  */
 
inline static struct bfinfdpic_relocs_info *
      if (r_symndx < symtab_hdr->sh_info)
bfinfdpic_relocs_info_for_local (struct htab *ht,
 
                                bfd *abfd,
 
                                long symndx,
 
                                bfd_vma addend,
 
                                enum insert_option insert)
        {
        {
          sym = local_syms + r_symndx;
  struct bfinfdpic_relocs_info entry;
          osec = sec = local_sections [r_symndx];
 
          relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
 
 
 
          name = bfd_elf_string_from_elf_section
  entry.symndx = symndx;
            (input_bfd, symtab_hdr->sh_link, sym->st_name);
  entry.d.abfd = abfd;
          name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
  entry.addend = addend;
        }
 
      else
 
        {
 
          bfd_boolean warned;
 
          bfd_boolean unresolved_reloc;
 
 
 
          RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
  return bfinfdpic_relocs_info_find (ht, abfd, &entry, insert);
                                   r_symndx, symtab_hdr, sym_hashes,
 
                                   h, sec, relocation,
 
                                   unresolved_reloc, warned);
 
          osec = sec;
 
        }
        }
 
 
      if (sec != NULL && elf_discarded_section (sec))
/* 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)
        {
        {
          /* For relocs against symbols from removed linkonce sections,
  e2->got17m4 |= e1->got17m4;
             or sections discarded by a linker script, we just want the
  e2->gothilo |= e1->gothilo;
             section contents zeroed.  Avoid any special processing.  */
  e2->fd |= e1->fd;
          _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
  e2->fdgot17m4 |= e1->fdgot17m4;
          rel->r_info = 0;
  e2->fdgothilo |= e1->fdgothilo;
          rel->r_addend = 0;
  e2->fdgoff17m4 |= e1->fdgoff17m4;
          continue;
  e2->fdgoffhilo |= e1->fdgoffhilo;
 
  e2->gotoff |= e1->gotoff;
 
  e2->call |= e1->call;
 
  e2->sym |= e1->sym;
        }
        }
 
 
      if (info->relocatable)
/* Every block of 65535 lazy PLT entries shares a single call to the
        continue;
   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.  */
 
 
      if (h != NULL
#define LZPLT_RESOLVER_EXTRA 10
          && (h->root.type == bfd_link_hash_defined
#define LZPLT_NORMAL_SIZE 6
              || h->root.type == bfd_link_hash_defweak)
#define LZPLT_ENTRIES 1362
          && !BFINFDPIC_SYM_LOCAL (info, h))
 
        {
 
          osec = sec = NULL;
 
          relocation = 0;
 
        }
 
 
 
      switch (r_type)
#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)
 
 
 
/* Add a dynamic relocation to the SRELOC section.  */
 
 
 
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)
        {
        {
        case R_pcrel24:
  Elf_Internal_Rela outrel;
        case R_pcrel24_jump_l:
  bfd_vma reloc_offset;
        case R_byte4_data:
 
          if (! IS_FDPIC (output_bfd))
 
            goto non_fdpic;
 
 
 
        case R_BFIN_GOT17M4:
  outrel.r_offset = offset;
        case R_BFIN_GOTHI:
  outrel.r_info = ELF32_R_INFO (dynindx, reloc_type);
        case R_BFIN_GOTLO:
  outrel.r_addend = addend;
        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 (!_bfinfdpic_emit_got_relocs_plt_entries (picrel, output_bfd, info,
  reloc_offset = sreloc->reloc_count * sizeof (Elf32_External_Rel);
                                                       osec, sym,
  BFD_ASSERT (reloc_offset < sreloc->size);
                                                       rel->r_addend))
  bfd_elf32_swap_reloc_out (output_bfd, &outrel,
 
                            sreloc->contents + reloc_offset);
 
  sreloc->reloc_count++;
 
 
 
  /* 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_error_handler)
      BFD_ASSERT (entry->dynrelocs > 0);
                (_("%B: relocation at `%A+0x%x' references symbol `%s' with nonzero addend"),
      entry->dynrelocs--;
                 input_bfd, input_section, rel->r_offset, name);
    }
              return FALSE;
 
 
 
 
  return reloc_offset;
            }
            }
 
 
          break;
/* Add a fixup to the ROFIXUP section.  */
 
 
        default:
static bfd_vma
        non_fdpic:
_bfinfdpic_add_rofixup (bfd *output_bfd, asection *rofixup, bfd_vma offset,
          picrel = NULL;
                       struct bfinfdpic_relocs_info *entry)
          if (h && ! BFINFDPIC_SYM_LOCAL (info, h))
 
            {
            {
              info->callbacks->warning
  bfd_vma fixup_offset;
                (info, _("relocation references symbol not defined in the module"),
 
                 name, input_bfd, input_section, rel->r_offset);
  if (rofixup->flags & SEC_EXCLUDE)
              return FALSE;
    return -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++;
 
 
      switch (r_type)
  if (entry && entry->symndx)
        {
        {
        case R_pcrel24:
      /* See discussion about symndx == 0 in _bfinfdpic_add_dyn_reloc
        case R_pcrel24_jump_l:
         above.  */
          check_segment[0] = isec_segment;
      BFD_ASSERT (entry->fixups > 0);
          if (! IS_FDPIC (output_bfd))
      entry->fixups--;
            check_segment[1] = isec_segment;
    }
          else if (picrel->plt)
 
 
  return fixup_offset;
 
}
 
 
 
/* Find the segment number in which OSEC, and output section, is
 
   located.  */
 
 
 
static unsigned
 
_bfinfdpic_osec_to_segment (bfd *output_bfd, asection *osec)
            {
            {
              relocation = bfinfdpic_plt_section (info)->output_section->vma
  Elf_Internal_Phdr *p = _bfd_elf_find_segment_containing_section (output_bfd, osec);
                + bfinfdpic_plt_section (info)->output_offset
 
                + picrel->plt_entry;
  return (p != NULL) ? p - elf_tdata (output_bfd)->phdr : -1;
              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;
 
 
 
        case R_BFIN_GOT17M4:
inline static bfd_boolean
        case R_BFIN_GOTHI:
_bfinfdpic_osec_readonly_p (bfd *output_bfd, asection *osec)
        case R_BFIN_GOTLO:
{
          relocation = picrel->got_entry;
  unsigned seg = _bfinfdpic_osec_to_segment (output_bfd, osec);
          check_segment[0] = check_segment[1] = got_segment;
 
          break;
 
 
 
        case R_BFIN_FUNCDESC_GOT17M4:
  return ! (elf_tdata (output_bfd)->phdr[seg].p_flags & PF_W);
        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:
/* Generate relocations for GOT entries, function descriptors, and
        case R_BFIN_GOTOFF17M4:
   code for PLT and lazy PLT entries.  */
        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;
 
 
 
        case R_BFIN_FUNCDESC_GOTOFF17M4:
inline static bfd_boolean
        case R_BFIN_FUNCDESC_GOTOFFHI:
_bfinfdpic_emit_got_relocs_plt_entries (struct bfinfdpic_relocs_info *entry,
        case R_BFIN_FUNCDESC_GOTOFFLO:
                                        bfd *output_bfd,
          relocation = picrel->fd_entry;
                                        struct bfd_link_info *info,
          check_segment[0] = check_segment[1] = got_segment;
                                        asection *sec,
          break;
                                        Elf_Internal_Sym *sym,
 
                                        bfd_vma addend)
 
 
        case R_BFIN_FUNCDESC:
 
          {
          {
            int dynindx;
  bfd_vma fd_lazy_rel_offset = (bfd_vma)-1;
            bfd_vma addend = rel->r_addend;
  int dynindx = -1;
 
 
            if (! (h && h->root.type == bfd_link_hash_undefweak
  if (entry->done)
                   && BFINFDPIC_SYM_LOCAL (info, h)))
    return TRUE;
 
  entry->done = 1;
 
 
 
  if (entry->got_entry || entry->fdgot_entry || entry->fd_entry)
              {
              {
                /* If the symbol is dynamic and there may be dynamic
      /* If the symbol is dynamic, consider it for dynamic
                   symbol resolution because we are or are linked with a
         relocations, otherwise decay to section + offset.  */
                   shared library, emit a FUNCDESC relocation such that
      if (entry->symndx == -1 && entry->d.h->dynindx != -1)
                   the dynamic linker will allocate the function
        dynindx = entry->d.h->dynindx;
                   descriptor.  If the symbol needs a non-local function
      else
                   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
          if (sec
                                                ->output_section)->dynindx;
              && sec->output_section
                    addend += h->root.u.def.section->output_offset
              && ! bfd_is_abs_section (sec->output_section)
                      + h->root.u.def.value;
              && ! bfd_is_und_section (sec->output_section))
 
            dynindx = elf_section_data (sec->output_section)->dynindx;
 
          else
 
            dynindx = 0;
                  }
                  }
                else if (h && ! BFINFDPIC_FUNCDESC_LOCAL (info, h))
    }
 
 
 
  /* Generate relocation for GOT entry pointing to the symbol.  */
 
  if (entry->got_entry)
                  {
                  {
                    if (addend)
      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)))
                      {
                      {
                        info->callbacks->warning
          if (entry->symndx == -1)
                          (info, _("R_BFIN_FUNCDESC references dynamic symbol with nonzero addend"),
            ad += entry->d.h->root.u.def.value;
                           name, input_bfd, input_section, rel->r_offset);
 
                        return FALSE;
 
                      }
 
                    dynindx = h->dynindx;
 
                  }
 
                else
                else
                  {
            ad += sym->st_value;
                    /* Otherwise, we know we have a private function
          ad += sec->output_offset;
                       descriptor, so reference it directly.  */
          if (sec->output_section && elf_section_data (sec->output_section))
                    BFD_ASSERT (picrel->privfd);
            idx = elf_section_data (sec->output_section)->dynindx;
                    r_type = R_byte4_data;
          else
                    dynindx = elf_section_data (bfinfdpic_got_section (info)
            idx = 0;
                                                ->output_section)->dynindx;
 
                    addend = bfinfdpic_got_section (info)->output_offset
 
                      + bfinfdpic_got_initial_offset (info)
 
                      + picrel->fd_entry;
 
                  }
                  }
 
 
                /* If there is room for dynamic symbol resolution, emit
      /* If we're linking an executable at a fixed address, we can
                   the dynamic relocation.  However, if we're linking an
         omit the dynamic relocation as long as the symbol is local to
                   executable at a fixed location, we won't have emitted a
         this module.  */
                   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
                if (info->executable && !info->pie
                    && (!h || BFINFDPIC_FUNCDESC_LOCAL (info, h)))
          && (entry->symndx != -1
                  {
              || BFINFDPIC_SYM_LOCAL (info, entry->d.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
          if (sec)
                              (info,
            ad += sec->output_section->vma;
                               _("cannot emit fixups in read-only section"),
          if (entry->symndx != -1
                               name, input_bfd, input_section, rel->r_offset);
              || entry->d.h->root.type != bfd_link_hash_undefweak)
                            return FALSE;
 
                          }
 
                        _bfinfdpic_add_rofixup (output_bfd,
                        _bfinfdpic_add_rofixup (output_bfd,
                                               bfinfdpic_gotfixup_section
                                   bfinfdpic_gotfixup_section (info),
                                               (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
                                               _bfd_elf_section_offset
                                               (output_bfd, info,
                                               (output_bfd, info,
                                                input_section, rel->r_offset)
                                  bfinfdpic_got_section (info),
                                               + input_section
                                  bfinfdpic_got_initial_offset (info)
 
                                  + entry->got_entry)
 
                                 + bfinfdpic_got_section (info)
                                               ->output_section->vma
                                               ->output_section->vma
                                               + input_section->output_offset,
                                 + bfinfdpic_got_section (info)->output_offset,
                                               picrel);
                                 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);
                  }
                  }
                else if ((bfd_get_section_flags (output_bfd,
 
                                                 input_section->output_section)
  /* Generate relocation for GOT entry pointing to a canonical
                          & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD))
     function descriptor.  */
 
  if (entry->fdgot_entry)
                  {
                  {
                    bfd_vma offset;
      int reloc, idx;
 
      bfd_vma ad = 0;
 
 
                    if (_bfinfdpic_osec_readonly_p (output_bfd,
      if (! (entry->symndx == -1
                                                   input_section
             && entry->d.h->root.type == bfd_link_hash_undefweak
                                                   ->output_section))
             && BFINFDPIC_SYM_LOCAL (info, entry->d.h)))
                      {
                      {
                        info->callbacks->warning
          /* If the symbol is dynamic and there may be dynamic symbol
                          (info,
             resolution because we are, or are linked with, a shared
                           _("cannot emit dynamic relocations in read-only section"),
             library, emit a FUNCDESC relocation such that the dynamic
                           name, input_bfd, input_section, rel->r_offset);
             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;
                        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
                    else
                      _bfinfdpic_add_dyn_reloc (output_bfd,
            {
                                                bfinfdpic_gotrel_section (info),
              /* Otherwise, we know we have a private function descriptor,
                                                offset + input_section
                 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
                                                ->output_section->vma
                                                + input_section->output_offset,
                                     + bfinfdpic_got_section (info)
                                                r_type,
                                     ->output_offset
                                                dynindx, addend, picrel);
                                     + bfinfdpic_got_initial_offset (info)
 
                                     + entry->fdgot_entry, entry);
                  }
                  }
                else
                else
                  addend += bfinfdpic_got_section (info)->output_section->vma;
            _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);
              }
              }
 
 
            /* We want the addend in-place because dynamic
      bfd_put_32 (output_bfd, ad,
               relocations are REL.  Setting relocation to it should
                  bfinfdpic_got_section (info)->contents
               arrange for it to be installed.  */
                  + bfinfdpic_got_initial_offset (info)
            relocation = addend - rel->r_addend;
                  + entry->fdgot_entry);
          }
          }
          check_segment[0] = check_segment[1] = got_segment;
 
          break;
 
 
 
        case R_byte4_data:
  /* Generate relocation to fill in a private function descriptor in
          if (! IS_FDPIC (output_bfd))
     the GOT.  */
            {
  if (entry->fd_entry)
              check_segment[0] = check_segment[1] = -1;
 
              break;
 
            }
 
          /* Fall through.  */
 
        case R_BFIN_FUNCDESC_VALUE:
 
          {
          {
            int dynindx;
      int idx = dynindx;
            bfd_vma addend = rel->r_addend;
      bfd_vma ad = addend;
            bfd_vma offset;
      bfd_vma ofst;
            offset = _bfd_elf_section_offset (output_bfd, info,
      long lowword, highword;
                                              input_section, rel->r_offset);
 
 
 
            /* If the symbol is dynamic but binds locally, use
            /* If the symbol is dynamic but binds locally, use
               section+offset.  */
               section+offset.  */
            if (h && ! BFINFDPIC_SYM_LOCAL (info, h))
      if (sec && (entry->symndx != -1
              {
                  || BFINFDPIC_SYM_LOCAL (info, entry->d.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)
          if (entry->symndx == -1)
                  addend += h->root.u.def.value;
            ad += entry->d.h->root.u.def.value;
                else
                else
                  addend += sym->st_value;
            ad += sym->st_value;
                if (osec)
          ad += sec->output_offset;
                  addend += osec->output_offset;
          if (sec->output_section && elf_section_data (sec->output_section))
                if (osec && osec->output_section
            idx = elf_section_data (sec->output_section)->dynindx;
                    && ! bfd_is_abs_section (osec->output_section)
 
                    && ! bfd_is_und_section (osec->output_section))
 
                  dynindx = elf_section_data (osec->output_section)->dynindx;
 
                else
                else
                  dynindx = 0;
            idx = 0;
              }
              }
 
 
            /* If we're linking an executable at a fixed address, we
      /* If we're linking an executable at a fixed address, we can
               can omit the dynamic relocation as long as the symbol
         omit the dynamic relocation as long as the symbol is local to
               is defined in the current link unit (which is implied
         this module.  */
               by its output section not being NULL).  */
      if (info->executable && !info->pie
            if (info->executable && !info->pie
          && (entry->symndx != -1 || BFINFDPIC_SYM_LOCAL (info, entry->d.h)))
                && (!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
          if (sec)
                          (info,
            ad += sec->output_section->vma;
                           _("cannot emit fixups in read-only section"),
          ofst = 0;
                           name, input_bfd, input_section, rel->r_offset);
          if (entry->symndx != -1
                        return FALSE;
              || entry->d.h->root.type != bfd_link_hash_undefweak)
                      }
 
                    if (!h || h->root.type != bfd_link_hash_undefweak)
 
                      {
                      {
                        /* Only output a reloc for a not deleted entry.  */
 
                        if (offset >= (bfd_vma)-2)
 
                          _bfinfdpic_add_rofixup (output_bfd,
                          _bfinfdpic_add_rofixup (output_bfd,
                                                  bfinfdpic_gotfixup_section
                                     bfinfdpic_gotfixup_section (info),
                                                  (info), -1, picrel);
                                     bfinfdpic_got_section (info)
                        else
                                     ->output_section->vma
 
                                     + bfinfdpic_got_section (info)
 
                                     ->output_offset
 
                                     + bfinfdpic_got_initial_offset (info)
 
                                     + entry->fd_entry, entry);
                          _bfinfdpic_add_rofixup (output_bfd,
                          _bfinfdpic_add_rofixup (output_bfd,
                                                  bfinfdpic_gotfixup_section
                                     bfinfdpic_gotfixup_section (info),
                                                  (info),
                                     bfinfdpic_got_section (info)
                                                  offset + input_section
 
                                                  ->output_section->vma
                                                  ->output_section->vma
                                                  + input_section->output_offset,
                                     + bfinfdpic_got_section (info)
                                                  picrel);
                                     ->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 (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 && sec && sec->output_section)
                          {
                          {
                            if (offset >= (bfd_vma)-2)
          lowword = ad;
                              _bfinfdpic_add_rofixup
          highword = bfinfdpic_got_section (info)->output_section->vma
                                (output_bfd,
            + bfinfdpic_got_section (info)->output_offset
                                 bfinfdpic_gotfixup_section (info),
            + bfinfdpic_got_initial_offset (info);
                                 -1, picrel);
 
                            else
 
                              _bfinfdpic_add_rofixup
 
                                (output_bfd,
 
                                 bfinfdpic_gotfixup_section (info),
 
                                 offset + input_section->output_section->vma
 
                                 + input_section->output_offset + 4, picrel);
 
                          }
                          }
 
      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
            else
              {
              {
                if ((bfd_get_section_flags (output_bfd,
          /* P1.L = fd_entry; P1.H = fd_entry;
                                            input_section->output_section)
             P3 = P3 + P1;
                     & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD))
             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)
                  {
                  {
                    if (_bfinfdpic_osec_readonly_p (output_bfd,
      bfd_byte *lzplt_code = bfinfdpic_plt_section (info)->contents
                                                   input_section
        + entry->lzplt_entry;
                                                   ->output_section))
      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)
                      {
                      {
                        info->callbacks->warning
          /* This is a lazy PLT entry that includes a resolver call.
                          (info,
             P2 = [P3];
                           _("cannot emit dynamic relocations in read-only section"),
             R3 = [P3 + 4];
                           name, input_bfd, input_section, rel->r_offset);
             JUMP (P2);  */
                        return FALSE;
          bfd_put_32 (output_bfd,
 
                      0xa05b915a,
 
                      lzplt_code);
 
          bfd_put_16 (output_bfd, 0x0052, lzplt_code + 4);
                      }
                      }
                    /* 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
                    else
                      _bfinfdpic_add_dyn_reloc (output_bfd,
        {
                                                bfinfdpic_gotrel_section (info),
          /* JUMP.S  resolverStub */
                                                offset
          bfd_put_16 (output_bfd,
                                                + input_section
                      0x2000
                                                ->output_section->vma
                      | (((resolverStub_addr - entry->lzplt_entry)
                                                + input_section->output_offset,
                          / 2) & (((bfd_vma)1 << 12) - 1)),
                                                r_type, dynindx, addend, picrel);
                      lzplt_code);
                  }
                  }
                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 (r_type == R_BFIN_FUNCDESC_VALUE && offset < (bfd_vma)-2)
  return TRUE;
 
}
 

 
/* 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;
 
 
 
  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)
              {
              {
                /* If we've omitted the dynamic relocation, just emit
          bfd_set_error (bfd_error_bad_value);
                   the fixed addresses of the symbol and of the local
          return FALSE;
                   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;
 
 
 
        default:
      h      = NULL;
          check_segment[0] = isec_segment;
      sym    = NULL;
          check_segment[1] = sec
      sec    = NULL;
            ? _bfinfdpic_osec_to_segment (output_bfd, sec->output_section)
 
            : (unsigned)-1;
 
          break;
 
        }
 
 
 
      if (check_segment[0] != check_segment[1] && IS_FDPIC (output_bfd))
      if (r_symndx < symtab_hdr->sh_info)
        {
        {
#if 1 /* If you take this out, remove the #error from fdpic-static-6.d
          sym = local_syms + r_symndx;
         in the ld testsuite.  */
          osec = sec = local_sections [r_symndx];
          /* This helps catch problems in GCC while we can't do more
          relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
             than static linking.  The idea is to test whether the
 
             input file basename is crt0.o only once.  */
          name = bfd_elf_string_from_elf_section
          if (silence_segment_error == 1)
            (input_bfd, symtab_hdr->sh_link, sym->st_name);
            silence_segment_error =
          name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
              (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;
 
        }
        }
 
      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:
          /* For relocs against symbols from removed linkonce sections,
          /* We need the addend to be applied before we shift the
             or sections discarded by a linker script, we just want the
             value right.  */
             section contents zeroed.  Avoid any special processing.  */
          relocation += rel->r_addend;
          _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
          /* Fall through.  */
          rel->r_info = 0;
        case R_BFIN_GOTHI:
          rel->r_addend = 0;
        case R_BFIN_FUNCDESC_GOTHI:
          continue;
        case R_BFIN_FUNCDESC_GOTOFFHI:
        }
          relocation >>= 16;
 
          /* Fall through.  */
 
 
 
        case R_BFIN_GOTLO:
      if (info->relocatable)
        case R_BFIN_FUNCDESC_GOTLO:
        continue;
        case R_BFIN_GOTOFFLO:
 
        case R_BFIN_FUNCDESC_GOTOFFLO:
 
          relocation &= 0xffff;
 
          break;
 
 
 
        default:
      if (h != NULL
          break;
          && (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_BFIN_PCREL24:
        case R_pcrel24_jump_l:
        case R_BFIN_PCREL24_JUMP_L:
          if (! IS_FDPIC (output_bfd) || ! picrel->plt)
        case R_BFIN_BYTE4_DATA:
            break;
          if (! IS_FDPIC (output_bfd))
          /* Fall through.  */
            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_GOT17M4:
        case R_BFIN_GOTHI:
        case R_BFIN_GOTHI:
        case R_BFIN_GOTLO:
        case R_BFIN_GOTLO:
        case R_BFIN_FUNCDESC_GOT17M4:
        case R_BFIN_FUNCDESC_GOT17M4:
        case R_BFIN_FUNCDESC_GOTHI:
        case R_BFIN_FUNCDESC_GOTHI:
        case R_BFIN_FUNCDESC_GOTLO:
        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_GOTOFF17M4:
        case R_BFIN_FUNCDESC_GOTOFFHI:
        case R_BFIN_FUNCDESC_GOTOFFHI:
        case R_BFIN_FUNCDESC_GOTOFFLO:
        case R_BFIN_FUNCDESC_GOTOFFLO:
          /* Note that we only want GOTOFFHI, not GOTOFFLO or GOTOFF17M4
        case R_BFIN_FUNCDESC:
             here, since we do want to apply the addend to the others.
        case R_BFIN_FUNCDESC_VALUE:
             Note that we've applied the addend to GOTOFFHI before we
          if (h != NULL)
             shifted it right.  */
            picrel = bfinfdpic_relocs_info_for_global (bfinfdpic_relocs_info
        case R_BFIN_GOTOFFHI:
                                                       (info), input_bfd, h,
          relocation -= rel->r_addend;
                                                       orig_addend, INSERT);
          break;
          else
 
            /* In order to find the entry we created before, we must
        default:
               use the original addend, not the one that may have been
          break;
               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 (r_type == R_pcrel24
          if (!_bfinfdpic_emit_got_relocs_plt_entries (picrel, output_bfd, info,
          || r_type == R_pcrel24_jump_l)
                                                       osec, sym,
 
                                                       rel->r_addend))
        {
        {
          bfd_vma x;
              (*_bfd_error_handler)
          bfd_vma address = rel->r_offset;
                (_("%B: relocation at `%A+0x%x' references symbol `%s' with nonzero addend"),
 
                 input_bfd, input_section, rel->r_offset, name);
          relocation += rel->r_addend;
              return FALSE;
 
 
          /* 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)
          break;
        {
 
          const char * msg = (const char *) NULL;
 
 
 
          switch (r)
        default:
 
        non_fdpic:
 
          picrel = NULL;
 
          if (h && ! BFINFDPIC_SYM_LOCAL (info, h))
            {
            {
            case bfd_reloc_overflow:
              info->callbacks->warning
              r = info->callbacks->reloc_overflow
                (info, _("relocation references symbol not defined in the module"),
                (info, (h ? &h->root : NULL), name, howto->name,
                 name, input_bfd, input_section, rel->r_offset);
                 (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
              return FALSE;
 
            }
              break;
              break;
 
        }
 
 
            case bfd_reloc_undefined:
      switch (r_type)
              r = info->callbacks->undefined_symbol
        {
                (info, name, input_bfd, input_section, rel->r_offset, TRUE);
        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;
              break;
 
 
            case bfd_reloc_outofrange:
        case R_BFIN_GOT17M4:
              msg = _("internal error: out of range error");
        case R_BFIN_GOTHI:
 
        case R_BFIN_GOTLO:
 
          relocation = picrel->got_entry;
 
          check_segment[0] = check_segment[1] = got_segment;
              break;
              break;
 
 
            case bfd_reloc_notsupported:
        case R_BFIN_FUNCDESC_GOT17M4:
              msg = _("internal error: unsupported relocation error");
        case R_BFIN_FUNCDESC_GOTHI:
 
        case R_BFIN_FUNCDESC_GOTLO:
 
          relocation = picrel->fdgot_entry;
 
          check_segment[0] = check_segment[1] = got_segment;
              break;
              break;
 
 
            case bfd_reloc_dangerous:
        case R_BFIN_GOTOFFHI:
              msg = _("internal error: dangerous relocation");
        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;
              break;
 
 
            default:
        case R_BFIN_FUNCDESC_GOTOFF17M4:
              msg = _("internal error: unknown error");
        case R_BFIN_FUNCDESC_GOTOFFHI:
 
        case R_BFIN_FUNCDESC_GOTOFFLO:
 
          relocation = picrel->fd_entry;
 
          check_segment[0] = check_segment[1] = got_segment;
              break;
              break;
            }
 
 
 
          if (msg)
        case R_BFIN_FUNCDESC:
            r = info->callbacks->warning
          {
              (info, msg, name, input_bfd, input_section, rel->r_offset);
            int dynindx;
 
            bfd_vma addend = rel->r_addend;
 
 
          if (! r)
            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;
            return FALSE;
        }
        }
 
                    dynindx = h->dynindx;
    }
    }
 
                else
  return TRUE;
                  {
 
                    /* 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;
}
}
 
 
static bfd_boolean
                /* If there is room for dynamic symbol resolution, emit
bfin_relocate_section (bfd * output_bfd,
                   the dynamic relocation.  However, if we're linking an
                       struct bfd_link_info *info,
                   executable at a fixed location, we won't have emitted a
                       bfd * input_bfd,
                   dynamic symbol entry for the got section, so idx will
                       asection * input_section,
                   be zero, which means we can and should compute the
                       bfd_byte * contents,
                   address of the private descriptor ourselves.  */
                       Elf_Internal_Rela * relocs,
                if (info->executable && !info->pie
                       Elf_Internal_Sym * local_syms,
                    && (!h || BFINFDPIC_FUNCDESC_LOCAL (info, h)))
                       asection ** local_sections)
 
{
{
  bfd *dynobj;
                    bfd_vma offset;
  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;
 
 
 
  dynobj = elf_hash_table (info)->dynobj;
                    addend += bfinfdpic_got_section (info)->output_section->vma;
  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
                    if ((bfd_get_section_flags (output_bfd,
  sym_hashes = elf_sym_hashes (input_bfd);
                                                input_section->output_section)
  local_got_offsets = elf_local_got_offsets (input_bfd);
                         & (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;
 
                          }
 
 
  sgot = NULL;
                        offset = _bfd_elf_section_offset
  sreloc = NULL;
                          (output_bfd, info,
 
                           input_section, rel->r_offset);
 
 
  rel = relocs;
                        if (offset != (bfd_vma)-1)
  relend = relocs + input_section->reloc_count;
                          _bfinfdpic_add_rofixup (output_bfd,
  for (; rel < relend; rel++, i++)
                                                  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))
    {
    {
      int r_type;
                    bfd_vma offset;
      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;
 
 
 
      r_type = ELF32_R_TYPE (rel->r_info);
                    if (_bfinfdpic_osec_readonly_p (output_bfd,
      if (r_type < 0 || r_type >= 243)
                                                   input_section
 
                                                   ->output_section))
        {
        {
          bfd_set_error (bfd_error_bad_value);
                        info->callbacks->warning
 
                          (info,
 
                           _("cannot emit dynamic relocations in read-only section"),
 
                           name, input_bfd, input_section, rel->r_offset);
          return FALSE;
          return FALSE;
        }
        }
 
                    offset = _bfd_elf_section_offset (output_bfd, info,
 
                                                      input_section, rel->r_offset);
 
 
      if (r_type == R_BFIN_GNU_VTENTRY
                    if (offset != (bfd_vma)-1)
          || r_type == R_BFIN_GNU_VTINHERIT)
                      _bfinfdpic_add_dyn_reloc (output_bfd,
        continue;
                                                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;
 
              }
 
 
      howto = bfin_reloc_type_lookup (input_bfd, r_type);
            /* We want the addend in-place because dynamic
      if (howto == NULL)
               relocations are REL.  Setting relocation to it should
        {
               arrange for it to be installed.  */
          bfd_set_error (bfd_error_bad_value);
            relocation = addend - rel->r_addend;
          return FALSE;
 
        }
        }
      r_symndx = ELF32_R_SYM (rel->r_info);
          check_segment[0] = check_segment[1] = got_segment;
 
          break;
 
 
      h = NULL;
        case R_BFIN_BYTE4_DATA:
      sym = NULL;
          if (! IS_FDPIC (output_bfd))
      sec = NULL;
            {
      unresolved_reloc = FALSE;
              check_segment[0] = check_segment[1] = -1;
 
              break;
 
            }
 
          /* Fall through.  */
 
        case R_BFIN_FUNCDESC_VALUE:
 
          {
 
            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 (r_symndx < symtab_hdr->sh_info)
            /* If the symbol is dynamic but binds locally, use
 
               section+offset.  */
 
            if (h && ! BFINFDPIC_SYM_LOCAL (info, h))
        {
        {
          sym = local_syms + r_symndx;
                if (addend && r_type == R_BFIN_FUNCDESC_VALUE)
          sec = local_sections[r_symndx];
                  {
          relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
                    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
      else
        {
        {
          bfd_boolean warned;
                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 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)
 
                      {
 
                        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);
 
 
          RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
                            if (r_type == R_BFIN_FUNCDESC_VALUE)
                                   r_symndx, symtab_hdr, sym_hashes,
                              _bfinfdpic_add_rofixup
                                   h, sec, relocation,
                                (output_bfd,
                                   unresolved_reloc, warned);
                                 bfinfdpic_gotfixup_section (info),
 
                                 offset + input_section->output_section->vma
 
                                 + input_section->output_offset + 4, picrel);
        }
        }
 
 
      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;
 
        }
        }
 
                  }
      if (info->relocatable)
              }
        continue;
            else
 
 
      address = rel->r_offset;
 
 
 
      /* Then, process normally.  */
 
      switch (r_type)
 
        {
        {
        case R_BFIN_GNU_VTINHERIT:
                if ((bfd_get_section_flags (output_bfd,
        case R_BFIN_GNU_VTENTRY:
                                            input_section->output_section)
          return bfd_reloc_ok;
                     & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD))
 
 
        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;
 
          /* Fall through.  */
 
          /* Relocation is the offset of the entry for this symbol in
 
             the global offset table.  */
 
 
 
          {
          {
            bfd_vma off;
                    if (_bfinfdpic_osec_readonly_p (output_bfd,
 
                                                   input_section
          if (dynobj == NULL)
                                                   ->output_section))
            {
            {
              /* Create the .got section.  */
                        info->callbacks->warning
              elf_hash_table (info)->dynobj = dynobj = output_bfd;
                          (info,
              if (!_bfd_elf_create_got_section (dynobj, info))
                           _("cannot emit dynamic relocations in read-only section"),
 
                           name, input_bfd, input_section, rel->r_offset);
                return FALSE;
                return FALSE;
            }
            }
 
 
            if (sgot == NULL)
                    if (offset != (bfd_vma)-1)
              {
                      _bfinfdpic_add_dyn_reloc (output_bfd,
                sgot = bfd_get_section_by_name (dynobj, ".got");
                                                bfinfdpic_gotrel_section (info),
                BFD_ASSERT (sgot != NULL);
                                                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 (h != NULL)
            if (r_type == R_BFIN_FUNCDESC_VALUE)
              {
 
                bfd_boolean dyn;
 
 
 
                off = h->got.offset;
 
                BFD_ASSERT (off != (bfd_vma) - 1);
 
                dyn = elf_hash_table (info)->dynamic_sections_created;
 
 
 
                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
                /* If we've omitted the dynamic relocation, just emit
                       -Bsymbolic link and the symbol is defined
                   the fixed addresses of the symbol and of the local
                       locally, or the symbol was forced to be local
                   GOT base offset.  */
                       because of a version file..  We must initialize
                if (info->executable && !info->pie
                       this entry in the global offset table.  Since
                    && (!h || BFINFDPIC_SYM_LOCAL (info, h)))
                       the offset must always be a multiple of 4, we
                  bfd_put_32 (output_bfd,
                       use the least significant bit to record whether
                              bfinfdpic_got_section (info)->output_section->vma
                       we have initialized it already.
                              + bfinfdpic_got_section (info)->output_offset
 
                              + bfinfdpic_got_initial_offset (info),
                       When doing a dynamic link, we create a .rela.got
                              contents + rel->r_offset + 4);
                       relocation entry to initialize the value.  This
 
                       is done in the finish_dynamic_symbol routine.  */
 
                    if ((off & 1) != 0)
 
                      off &= ~1;
 
                    else
                    else
                      {
                  /* A function descriptor used for lazy or local
                        bfd_put_32 (output_bfd, relocation,
                     resolving is initialized such that its high word
                                    sgot->contents + off);
                     contains the output section index in which the
                        h->got.offset |= 1;
                     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);
                      }
                      }
                  }
                  }
                else
          check_segment[0] = check_segment[1] = got_segment;
                  unresolved_reloc = FALSE;
          break;
 
 
 
        default:
 
          check_segment[0] = isec_segment;
 
          check_segment[1] = sec
 
            ? _bfinfdpic_osec_to_segment (output_bfd, sec->output_section)
 
            : (unsigned)-1;
 
          break;
              }
              }
            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
      if (check_segment[0] != check_segment[1] && IS_FDPIC (output_bfd))
                   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);
#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;
 
        }
 
 
                    if (info->shared)
      switch (r_type)
                      {
                      {
                        asection *s;
        case R_BFIN_GOTOFFHI:
                        Elf_Internal_Rela outrel;
          /* We need the addend to be applied before we shift the
                        bfd_byte *loc;
             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.  */
 
 
                        s = bfd_get_section_by_name (dynobj, ".rela.got");
        case R_BFIN_GOTLO:
                        BFD_ASSERT (s != NULL);
        case R_BFIN_FUNCDESC_GOTLO:
 
        case R_BFIN_GOTOFFLO:
 
        case R_BFIN_FUNCDESC_GOTOFFLO:
 
          relocation &= 0xffff;
 
          break;
 
 
                        outrel.r_offset = (sgot->output_section->vma
        default:
                                           + sgot->output_offset + off);
          break;
                        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);
 
                      }
                      }
 
 
                    local_got_offsets[r_symndx] |= 1;
      switch (r_type)
                  }
        {
 
        case R_BFIN_PCREL24:
 
        case R_BFIN_PCREL24_JUMP_L:
 
          if (! IS_FDPIC (output_bfd) || ! picrel->plt)
 
            break;
 
          /* Fall through.  */
 
 
 
          /* 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;
              }
              }
 
 
            relocation = sgot->output_offset + off;
      r = bfin_final_link_relocate (rel, howto, input_bfd, input_section,
            rel->r_addend = 0;
                                    contents, rel->r_offset,
            /* bfin : preg = [preg + 17bitdiv4offset] relocation is div by 4.  */
                                    relocation, rel->r_addend);
            relocation /= 4;
 
          }
 
          goto do_default;
 
 
 
        case R_pcrel24:
      if (r != bfd_reloc_ok)
        case R_pcrel24_jump_l:
 
          {
          {
            bfd_vma x;
          const char * msg = (const char *) NULL;
 
 
            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
          switch (r)
               the start of instruction. Assuming absolute postion
            {
               of the reloc data. But, following code had been written assuming
            case bfd_reloc_overflow:
               reloc address is starting at begining of instruction.
              r = info->callbacks->reloc_overflow
               To compensate that I have increased the value of
                (info, (h ? &h->root : NULL), name, howto->name,
               relocation by 1 (effectively 2) and used the addr -2 instead of addr.  */
                 (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
 
              break;
 
 
            relocation += 2;
            case bfd_reloc_undefined:
            address -= 2;
              r = info->callbacks->undefined_symbol
 
                (info, name, input_bfd, input_section, rel->r_offset, TRUE);
 
              break;
 
 
            relocation >>= 1;
            case bfd_reloc_outofrange:
 
              msg = _("internal error: out of range error");
 
              break;
 
 
            x = bfd_get_16 (input_bfd, contents + address);
            case bfd_reloc_notsupported:
            x = (x & 0xff00) | ((relocation >> 16) & 0xff);
              msg = _("internal error: unsupported relocation error");
            bfd_put_16 (input_bfd, x, contents + address);
              break;
 
 
            x = bfd_get_16 (input_bfd, contents + address + 2);
            case bfd_reloc_dangerous:
            x = relocation & 0xFFFF;
              msg = _("internal error: dangerous relocation");
            bfd_put_16 (input_bfd, x, contents + address + 2);
 
            r = bfd_reloc_ok;
 
          }
 
          break;
          break;
 
 
        default:
        default:
        do_default:
              msg = _("internal error: unknown error");
          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
          if (msg)
         because such sections are not SEC_ALLOC and thus ld.so will
            r = info->callbacks->warning
         not process them.  */
              (info, msg, name, input_bfd, input_section, rel->r_offset);
      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;
 
        }
 
 
 
      if (r != bfd_reloc_ok)
 
        {
 
          const char *name;
 
 
 
          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 (! r)
            {
 
              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;
              return FALSE;
            }
            }
        }
        }
    }
 
 
 
  return TRUE;
  return TRUE;
}
}
 
 
static asection *
/* Update the relocation information for the relocations of the section
bfin_gc_mark_hook (asection * sec,
   being removed.  */
                   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.  */
 
 
 
static bfd_boolean
static bfd_boolean
bfin_gc_sweep_hook (bfd * abfd,
bfinfdpic_gc_sweep_hook (bfd *abfd,
                    struct bfd_link_info *info,
                    struct bfd_link_info *info,
                    asection * sec,
                    asection * sec,
                    const Elf_Internal_Rela * relocs)
                    const Elf_Internal_Rela * relocs)
{
{
  Elf_Internal_Shdr *symtab_hdr;
  Elf_Internal_Shdr *symtab_hdr;
  struct elf_link_hash_entry **sym_hashes;
  struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
  bfd_signed_vma *local_got_refcounts;
  const Elf_Internal_Rela *rel;
  const Elf_Internal_Rela *rel, *relend;
  const Elf_Internal_Rela *rel_end;
  bfd *dynobj;
  struct bfinfdpic_relocs_info *picrel;
  asection *sgot;
 
  asection *srelgot;
 
 
 
  dynobj = elf_hash_table (info)->dynobj;
  BFD_ASSERT (IS_FDPIC (abfd));
  if (dynobj == NULL)
 
    return TRUE;
 
 
 
  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
  sym_hashes = elf_sym_hashes (abfd);
  sym_hashes = elf_sym_hashes (abfd);
  local_got_refcounts = elf_local_got_refcounts (abfd);
  sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof(Elf32_External_Sym);
 
  if (!elf_bad_symtab (abfd))
  sgot = bfd_get_section_by_name (dynobj, ".got");
    sym_hashes_end -= symtab_hdr->sh_info;
  srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
 
 
 
  relend = relocs + sec->reloc_count;
  rel_end = relocs + sec->reloc_count;
  for (rel = relocs; rel < relend; rel++)
  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;
 
 
      switch (ELF32_R_TYPE (rel->r_info))
 
        {
 
        case R_got:
 
          r_symndx = ELF32_R_SYM (rel->r_info);
          r_symndx = ELF32_R_SYM (rel->r_info);
          if (r_symndx >= symtab_hdr->sh_info)
      if (r_symndx < symtab_hdr->sh_info)
            {
        h = NULL;
 
      else
              h = sym_hashes[r_symndx - symtab_hdr->sh_info];
              h = sym_hashes[r_symndx - symtab_hdr->sh_info];
              if (h->got.refcount > 0)
 
                {
      if (h != NULL)
                  --h->got.refcount;
        picrel = bfinfdpic_relocs_info_for_global (bfinfdpic_relocs_info (info),
                  if (h->got.refcount == 0)
                                                   abfd, h,
                    {
                                                   rel->r_addend, NO_INSERT);
                      /* We don't need the .got entry any more.  */
      else
                      sgot->size -= 4;
        picrel = bfinfdpic_relocs_info_for_local (bfinfdpic_relocs_info
                      srelgot->size -= sizeof (Elf32_External_Rela);
                                                  (info), abfd, r_symndx,
                    }
                                                  rel->r_addend, NO_INSERT);
                }
 
            }
      if (!picrel)
          else if (local_got_refcounts != NULL)
        return TRUE;
            {
 
              if (local_got_refcounts[r_symndx] > 0)
      switch (ELF32_R_TYPE (rel->r_info))
                {
 
                  --local_got_refcounts[r_symndx];
 
                  if (local_got_refcounts[r_symndx] == 0)
 
                    {
                    {
                      /* We don't need the .got entry any more.  */
        case R_BFIN_PCREL24:
                      sgot->size -= 4;
        case R_BFIN_PCREL24_JUMP_L:
                      if (info->shared)
          picrel->call--;
                        srelgot->size -= sizeof (Elf32_External_Rela);
          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;
          break;
 
 
 
        case R_BFIN_FUNCDESC:
 
          picrel->fd--;
 
          picrel->relocsfd--;
 
          break;
 
 
        default:
        default:
          break;
          break;
        }
        }
    }
    }
 
 
  return TRUE;
  return TRUE;
}
}
 
 
/* We need dynamic symbols for every section, since segments can
/* We need dynamic symbols for every section, since segments can
   relocate independently.  */
   relocate independently.  */
static bfd_boolean
static bfd_boolean
_bfinfdpic_link_omit_section_dynsym (bfd *output_bfd ATTRIBUTE_UNUSED,
_bfinfdpic_link_omit_section_dynsym (bfd *output_bfd ATTRIBUTE_UNUSED,
                                    struct bfd_link_info *info
                                    struct bfd_link_info *info ATTRIBUTE_UNUSED,
                                    ATTRIBUTE_UNUSED,
                                    asection *p)
                                    asection *p ATTRIBUTE_UNUSED)
 
{
{
  switch (elf_section_data (p)->this_hdr.sh_type)
  switch (elf_section_data (p)->this_hdr.sh_type)
    {
    {
    case SHT_PROGBITS:
    case SHT_PROGBITS:
    case SHT_NOBITS:
    case SHT_NOBITS:
Line 3339... Line 3455...
 
 
      bfinfdpic_gotfixup_section (info) = s;
      bfinfdpic_gotfixup_section (info) = s;
      offset = -2048;
      offset = -2048;
      flags = BSF_GLOBAL;
      flags = BSF_GLOBAL;
    }
    }
  else
  else
    {
    {
      offset = 2048;
      offset = 2048;
      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;
  pltflags |= SEC_CODE;
  if (bed->plt_not_loaded)
  if (bed->plt_not_loaded)
    pltflags &= ~ (SEC_CODE | SEC_LOAD | SEC_HAS_CONTENTS);
    pltflags &= ~ (SEC_CODE | SEC_LOAD | SEC_HAS_CONTENTS);
  if (bed->plt_readonly)
  if (bed->plt_readonly)
    pltflags |= SEC_READONLY;
    pltflags |= SEC_READONLY;
Line 3408... Line 3503...
      || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
      || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
    return FALSE;
    return FALSE;
  /* Blackfin-specific: remember it.  */
  /* Blackfin-specific: remember it.  */
  bfinfdpic_pltrel_section (info) = s;
  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);
 
 
 
  /* 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.  */
  /* Blackfin-specific: we want to create the GOT in the Blackfin way.  */
  if (! _bfin_create_got_section (abfd, info))
  if (! _bfin_create_got_section (abfd, info))
    return FALSE;
    return FALSE;
 
 
  /* Blackfin-specific: make sure we created everything we wanted.  */
  /* Blackfin-specific: make sure we created everything we wanted.  */
Line 3445... Line 3561...
     section when generating a shared object, since they do not use
     section when generating a shared object, since they do not use
     copy relocs.  */
     copy relocs.  */
      if (! info->shared)
      if (! info->shared)
        {
        {
          s = bfd_make_section_with_flags (abfd,
          s = bfd_make_section_with_flags (abfd,
                                           (bed->default_use_rela_p
                                           ".rela.bss",
                                            ? ".rela.bss" : ".rel.bss"),
 
                                           flags | SEC_READONLY);
                                           flags | SEC_READONLY);
          if (s == NULL
          if (s == NULL
              || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
              || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align))
            return FALSE;
            return FALSE;
        }
        }
    }
    }
 
 
  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.
/* 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
   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
   the symbol, an entry pointing to its function descriptor, and a
   private function descriptors taking two words.  */
   private function descriptors taking two words.  */
 
 
static int
static void
_bfinfdpic_count_got_plt_entries (void **entryp, void *dinfo_)
_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.  */
  /* Allocate space for a GOT entry pointing to the symbol.  */
  if (entry->got17m4)
  if (entry->got17m4)
    dinfo->got17m4 += 4;
    dinfo->got17m4 += 4;
  else if (entry->gothilo)
  else if (entry->gothilo)
    dinfo->gothilo += 4;
    dinfo->gothilo += 4;
Line 3547... Line 3628...
    entry->relocsfdv--;
    entry->relocsfdv--;
  entry->relocsfdv++;
  entry->relocsfdv++;
 
 
  if (entry->lazyplt)
  if (entry->lazyplt)
    dinfo->lzplt += LZPLT_NORMAL_SIZE;
    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)
  if (!dinfo->info->executable || dinfo->info->pie)
    relocs = entry->relocs32 + entry->relocsfd + entry->relocsfdv;
    relocs = entry->relocs32 + entry->relocsfd + entry->relocsfdv;
  else
  else
    {
    {
Line 3572... Line 3665...
        }
        }
      else
      else
        relocs += entry->relocsfd;
        relocs += entry->relocsfd;
    }
    }
 
 
 
  if (subtract)
 
    {
 
      relocs = - relocs;
 
      fixups = - fixups;
 
    }
 
 
  entry->dynrelocs += relocs;
  entry->dynrelocs += relocs;
  entry->fixups += fixups;
  entry->fixups += fixups;
  dinfo->relocs += relocs;
  dinfo->relocs += relocs;
  dinfo->fixups += fixups;
  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;
}
}
 
 
/* This structure is used to assign offsets to got entries, function
/* This structure is used to assign offsets to got entries, function
Line 3871... Line 3986...
    }
    }
 
 
  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
/* Follow indirect and warning hash entries so that each got entry
   points to the final symbol definition.  P must point to a pointer
   points to the final symbol definition.  P must point to a pointer
   to the hash table we're traversing.  Since this traversal may
   to the hash table we're traversing.  Since this traversal may
   modify the hash table, we set this pointer to NULL to indicate
   modify the hash table, we set this pointer to NULL to indicate
   we've made a potentially-destructive change to the hash table, so
   we've made a potentially-destructive change to the hash table, so
Line 3927... Line 4059...
    }
    }
 
 
  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,
_bfinfdpic_size_got_plt (bfd *output_bfd,
                                      struct bfd_link_info *info)
                         struct _bfinfdpic_dynamic_got_plt_info *gpinfop)
{
{
  bfd *dynobj;
 
  asection *s;
 
  struct _bfinfdpic_dynamic_got_plt_info gpinfo;
 
  bfd_signed_vma odd;
  bfd_signed_vma odd;
  bfd_vma limit;
  bfd_vma limit;
 
  struct bfd_link_info *info = gpinfop->g.info;
 
  bfd *dynobj = elf_hash_table (info)->dynobj;
 
 
  dynobj = elf_hash_table (info)->dynobj;
  memcpy (bfinfdpic_dynamic_got_plt_info (info), &gpinfop->g,
  BFD_ASSERT (dynobj != NULL);
          sizeof (gpinfop->g));
 
 
  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);
 
 
 
  odd = 12;
  odd = 12;
  /* Compute the total size taken by entries in the 18-bit range,
  /* Compute the total size taken by entries in the 18-bit range,
     to tell how many PLT function descriptors we can bring into it
     to tell how many PLT function descriptors we can bring into it
     without causing it to overflow.  */
     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)
  if (limit < (bfd_vma)1 << 18)
    limit = ((bfd_vma)1 << 18) - limit;
    limit = ((bfd_vma)1 << 18) - limit;
  else
  else
    limit = 0;
    limit = 0;
  if (gpinfo.g.fdplt < limit)
  if (gpinfop->g.fdplt < limit)
    limit = gpinfo.g.fdplt;
    limit = gpinfop->g.fdplt;
 
 
  /* Determine the ranges of GOT offsets that we can use for each
  /* Determine the ranges of GOT offsets that we can use for each
     range of addressing modes.  */
     range of addressing modes.  */
  odd = _bfinfdpic_compute_got_alloc_data (&gpinfo.got17m4,
  odd = _bfinfdpic_compute_got_alloc_data (&gpinfop->got17m4,
                                          0,
                                          0,
                                          odd,
                                          odd,
                                          16,
                                          16,
                                          gpinfo.g.got17m4,
                                          gpinfop->g.got17m4,
                                          gpinfo.g.fd17m4,
                                          gpinfop->g.fd17m4,
                                          limit,
                                          limit,
                                          (bfd_vma)1 << (18-1));
                                          (bfd_vma)1 << (18-1));
  odd = _bfinfdpic_compute_got_alloc_data (&gpinfo.gothilo,
  odd = _bfinfdpic_compute_got_alloc_data (&gpinfop->gothilo,
                                          gpinfo.got17m4.min,
                                          gpinfop->got17m4.min,
                                          odd,
                                          odd,
                                          gpinfo.got17m4.max,
                                          gpinfop->got17m4.max,
                                          gpinfo.g.gothilo,
                                          gpinfop->g.gothilo,
                                          gpinfo.g.fdhilo,
                                          gpinfop->g.fdhilo,
                                          gpinfo.g.fdplt - gpinfo.got17m4.fdplt,
                                          gpinfop->g.fdplt - gpinfop->got17m4.fdplt,
                                          (bfd_vma)1 << (32-1));
                                          (bfd_vma)1 << (32-1));
 
 
  /* Now assign (most) GOT offsets.  */
  /* Now assign (most) GOT offsets.  */
  htab_traverse (bfinfdpic_relocs_info (info), _bfinfdpic_assign_got_entries,
  htab_traverse (bfinfdpic_relocs_info (info), _bfinfdpic_assign_got_entries,
                 &gpinfo);
                 gpinfop);
 
 
  bfinfdpic_got_section (info)->size = gpinfo.gothilo.max
  bfinfdpic_got_section (info)->size = gpinfop->gothilo.max
    - gpinfo.gothilo.min
    - gpinfop->gothilo.min
    /* If an odd word is the last word of the GOT, we don't need this
    /* If an odd word is the last word of the GOT, we don't need this
       word to be part of the GOT.  */
       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)
  if (bfinfdpic_got_section (info)->size == 0)
    bfinfdpic_got_section (info)->flags |= SEC_EXCLUDE;
    bfinfdpic_got_section (info)->flags |= SEC_EXCLUDE;
  else if (bfinfdpic_got_section (info)->size == 12
  else if (bfinfdpic_got_section (info)->size == 12
           && ! elf_hash_table (info)->dynamic_sections_created)
           && ! elf_hash_table (info)->dynamic_sections_created)
    {
    {
Line 4031... Line 4136...
 
 
  if (elf_hash_table (info)->dynamic_sections_created)
  if (elf_hash_table (info)->dynamic_sections_created)
    /* Subtract the number of lzplt entries, since those will generate
    /* Subtract the number of lzplt entries, since those will generate
       relocations in the pltrel section.  */
       relocations in the pltrel section.  */
    bfinfdpic_gotrel_section (info)->size =
    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;
      * get_elf_backend_data (output_bfd)->s->sizeof_rel;
  else
  else
    BFD_ASSERT (gpinfo.g.relocs == 0);
    BFD_ASSERT (gpinfop->g.relocs == 0);
  if (bfinfdpic_gotrel_section (info)->size == 0)
  if (bfinfdpic_gotrel_section (info)->size == 0)
    bfinfdpic_gotrel_section (info)->flags |= SEC_EXCLUDE;
    bfinfdpic_gotrel_section (info)->flags |= SEC_EXCLUDE;
  else
  else
    {
    {
      bfinfdpic_gotrel_section (info)->contents =
      bfinfdpic_gotrel_section (info)->contents =
Line 4046... Line 4151...
                                 bfinfdpic_gotrel_section (info)->size);
                                 bfinfdpic_gotrel_section (info)->size);
      if (bfinfdpic_gotrel_section (info)->contents == NULL)
      if (bfinfdpic_gotrel_section (info)->contents == NULL)
        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)
  if (bfinfdpic_gotfixup_section (info)->size == 0)
    bfinfdpic_gotfixup_section (info)->flags |= SEC_EXCLUDE;
    bfinfdpic_gotfixup_section (info)->flags |= SEC_EXCLUDE;
  else
  else
    {
    {
      bfinfdpic_gotfixup_section (info)->contents =
      bfinfdpic_gotfixup_section (info)->contents =
Line 4059... Line 4164...
      if (bfinfdpic_gotfixup_section (info)->contents == NULL)
      if (bfinfdpic_gotfixup_section (info)->contents == NULL)
        return FALSE;
        return FALSE;
    }
    }
 
 
  if (elf_hash_table (info)->dynamic_sections_created)
  if (elf_hash_table (info)->dynamic_sections_created)
    {
 
      bfinfdpic_pltrel_section (info)->size =
      bfinfdpic_pltrel_section (info)->size =
        gpinfo.g.lzplt / LZPLT_NORMAL_SIZE * get_elf_backend_data (output_bfd)->s->sizeof_rel;
      gpinfop->g.lzplt / LZPLT_NORMAL_SIZE * get_elf_backend_data (output_bfd)->s->sizeof_rel;
      if (bfinfdpic_pltrel_section (info)->size == 0)
      if (bfinfdpic_pltrel_section (info)->size == 0)
        bfinfdpic_pltrel_section (info)->flags |= SEC_EXCLUDE;
        bfinfdpic_pltrel_section (info)->flags |= SEC_EXCLUDE;
      else
      else
        {
        {
          bfinfdpic_pltrel_section (info)->contents =
          bfinfdpic_pltrel_section (info)->contents =
            (bfd_byte *) bfd_zalloc (dynobj,
            (bfd_byte *) bfd_zalloc (dynobj,
                                     bfinfdpic_pltrel_section (info)->size);
                                     bfinfdpic_pltrel_section (info)->size);
          if (bfinfdpic_pltrel_section (info)->contents == NULL)
          if (bfinfdpic_pltrel_section (info)->contents == NULL)
            return FALSE;
            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,
     such that there's room for the additional instruction needed to
     such that there's room for the additional instruction needed to
     call the resolver.  Since _bfinfdpic_assign_got_entries didn't
     call the resolver.  Since _bfinfdpic_assign_got_entries didn't
     account for them, our block size is 4 bytes smaller than the real
     account for them, our block size is 4 bytes smaller than the real
     block size.  */
     block size.  */
  if (elf_hash_table (info)->dynamic_sections_created)
  if (elf_hash_table (info)->dynamic_sections_created)
    {
    {
      bfinfdpic_plt_section (info)->size = gpinfo.g.lzplt
      bfinfdpic_plt_section (info)->size = gpinfop->g.lzplt
        + ((gpinfo.g.lzplt + (BFINFDPIC_LZPLT_BLOCK_SIZE - 4) - LZPLT_NORMAL_SIZE)
        + ((gpinfop->g.lzplt + (BFINFDPIC_LZPLT_BLOCK_SIZE - 4) - LZPLT_NORMAL_SIZE)
           / (BFINFDPIC_LZPLT_BLOCK_SIZE - 4) * LZPLT_RESOLVER_EXTRA);
           / (BFINFDPIC_LZPLT_BLOCK_SIZE - 4) * LZPLT_RESOLVER_EXTRA);
    }
    }
 
 
  /* Reset it, such that _bfinfdpic_assign_plt_entries() can use it to
  /* Reset it, such that _bfinfdpic_assign_plt_entries() can use it to
     actually assign lazy PLT entries addresses.  */
     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
  /* Save information that we're going to need to generate GOT and PLT
     entries.  */
     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)
  if (get_elf_backend_data (output_bfd)->want_got_sym)
    elf_hash_table (info)->hgot->root.u.def.value
    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)
  if (elf_hash_table (info)->dynamic_sections_created)
    bfinfdpic_plt_initial_offset (info) =
    bfinfdpic_plt_initial_offset (info) =
      bfinfdpic_plt_section (info)->size;
      bfinfdpic_plt_section (info)->size;
 
 
  htab_traverse (bfinfdpic_relocs_info (info), _bfinfdpic_assign_plt_entries,
  htab_traverse (bfinfdpic_relocs_info (info), _bfinfdpic_assign_plt_entries,
                 &gpinfo);
                 gpinfop);
 
 
  /* Allocate the PLT section contents only after
  /* Allocate the PLT section contents only after
     _bfinfdpic_assign_plt_entries has a chance to add the size of the
     _bfinfdpic_assign_plt_entries has a chance to add the size of the
     non-lazy PLT entries.  */
     non-lazy PLT entries.  */
  if (elf_hash_table (info)->dynamic_sections_created)
 
    {
 
      if (bfinfdpic_plt_section (info)->size == 0)
      if (bfinfdpic_plt_section (info)->size == 0)
        bfinfdpic_plt_section (info)->flags |= SEC_EXCLUDE;
        bfinfdpic_plt_section (info)->flags |= SEC_EXCLUDE;
      else
      else
        {
        {
          bfinfdpic_plt_section (info)->contents =
          bfinfdpic_plt_section (info)->contents =
            (bfd_byte *) bfd_zalloc (dynobj,
            (bfd_byte *) bfd_zalloc (dynobj,
                                     bfinfdpic_plt_section (info)->size);
                                     bfinfdpic_plt_section (info)->size);
          if (bfinfdpic_plt_section (info)->contents == NULL)
          if (bfinfdpic_plt_section (info)->contents == NULL)
            return FALSE;
            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)
 
        {
 
          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 (elf_hash_table (info)->dynamic_sections_created)
    {
    {
      if (bfinfdpic_got_section (info)->size)
      if (bfinfdpic_got_section (info)->size)
        if (!_bfd_elf_add_dynamic_entry (info, DT_PLTGOT, 0))
        if (!_bfd_elf_add_dynamic_entry (info, DT_PLTGOT, 0))
          return FALSE;
          return FALSE;
Line 4142... Line 4295...
            || !_bfd_elf_add_dynamic_entry (info, DT_RELENT,
            || !_bfd_elf_add_dynamic_entry (info, DT_RELENT,
                                            sizeof (Elf32_External_Rel)))
                                            sizeof (Elf32_External_Rel)))
          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;
}
}
 
 
static bfd_boolean
static bfd_boolean
elf32_bfinfdpic_always_size_sections (bfd *output_bfd,
elf32_bfinfdpic_always_size_sections (bfd *output_bfd,
Line 4182... Line 4343...
    }
    }
 
 
  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
static bfd_boolean
elf32_bfinfdpic_modify_program_headers (bfd *output_bfd,
elf32_bfinfdpic_modify_program_headers (bfd *output_bfd,
                                        struct bfd_link_info *info)
                                        struct bfd_link_info *info)
{
{
  struct elf_obj_tdata *tdata = elf_tdata (output_bfd);
  struct elf_obj_tdata *tdata = elf_tdata (output_bfd);
Line 4321... Line 4598...
/* Adjust a symbol defined by a dynamic object and referenced by a
/* Adjust a symbol defined by a dynamic object and referenced by a
   regular object.  */
   regular object.  */
 
 
static bfd_boolean
static bfd_boolean
elf32_bfinfdpic_adjust_dynamic_symbol
elf32_bfinfdpic_adjust_dynamic_symbol
(struct bfd_link_info *info ATTRIBUTE_UNUSED,
(struct bfd_link_info *info,
 struct elf_link_hash_entry *h ATTRIBUTE_UNUSED)
 struct elf_link_hash_entry *h)
{
{
  bfd * dynobj;
  bfd * dynobj;
 
 
  dynobj = elf_hash_table (info)->dynobj;
  dynobj = elf_hash_table (info)->dynobj;
 
 
Line 4560... Line 4837...
        case R_BFIN_FUNCDESC:
        case R_BFIN_FUNCDESC:
        case R_BFIN_FUNCDESC_VALUE:
        case R_BFIN_FUNCDESC_VALUE:
          if (! IS_FDPIC (abfd))
          if (! IS_FDPIC (abfd))
            goto bad_reloc;
            goto bad_reloc;
          /* Fall through.  */
          /* Fall through.  */
        case R_pcrel24:
        case R_BFIN_PCREL24:
        case R_pcrel24_jump_l:
        case R_BFIN_PCREL24_JUMP_L:
        case R_byte4_data:
        case R_BFIN_BYTE4_DATA:
          if (IS_FDPIC (abfd) && ! dynobj)
          if (IS_FDPIC (abfd) && ! dynobj)
            {
            {
              elf_hash_table (info)->dynobj = dynobj = abfd;
              elf_hash_table (info)->dynobj = dynobj = abfd;
              if (! _bfin_create_got_section (abfd, info))
              if (! _bfin_create_got_section (abfd, info))
                return FALSE;
                return FALSE;
Line 4606... Line 4883...
          break;
          break;
        }
        }
 
 
      switch (ELF32_R_TYPE (rel->r_info))
      switch (ELF32_R_TYPE (rel->r_info))
        {
        {
        case R_pcrel24:
        case R_BFIN_PCREL24:
        case R_pcrel24_jump_l:
        case R_BFIN_PCREL24_JUMP_L:
          if (IS_FDPIC (abfd))
          if (IS_FDPIC (abfd))
            picrel->call = 1;
            picrel->call++;
          break;
          break;
 
 
        case R_BFIN_FUNCDESC_VALUE:
        case R_BFIN_FUNCDESC_VALUE:
          picrel->relocsfdv++;
          picrel->relocsfdv++;
          if (bfd_get_section_flags (abfd, sec) & SEC_ALLOC)
          if (bfd_get_section_flags (abfd, sec) & SEC_ALLOC)
            picrel->relocs32--;
            picrel->relocs32--;
          /* Fall through.  */
          /* Fall through.  */
 
 
        case R_byte4_data:
        case R_BFIN_BYTE4_DATA:
          if (! IS_FDPIC (abfd))
          if (! IS_FDPIC (abfd))
            break;
            break;
 
 
          picrel->sym = 1;
          picrel->sym++;
          if (bfd_get_section_flags (abfd, sec) & SEC_ALLOC)
          if (bfd_get_section_flags (abfd, sec) & SEC_ALLOC)
            picrel->relocs32++;
            picrel->relocs32++;
          break;
          break;
 
 
        case R_BFIN_GOT17M4:
        case R_BFIN_GOT17M4:
          picrel->got17m4 = 1;
          picrel->got17m4++;
          break;
          break;
 
 
        case R_BFIN_GOTHI:
        case R_BFIN_GOTHI:
        case R_BFIN_GOTLO:
        case R_BFIN_GOTLO:
          picrel->gothilo = 1;
          picrel->gothilo++;
          break;
          break;
 
 
        case R_BFIN_FUNCDESC_GOT17M4:
        case R_BFIN_FUNCDESC_GOT17M4:
          picrel->fdgot17m4 = 1;
          picrel->fdgot17m4++;
          break;
          break;
 
 
        case R_BFIN_FUNCDESC_GOTHI:
        case R_BFIN_FUNCDESC_GOTHI:
        case R_BFIN_FUNCDESC_GOTLO:
        case R_BFIN_FUNCDESC_GOTLO:
          picrel->fdgothilo = 1;
          picrel->fdgothilo++;
          break;
          break;
 
 
        case R_BFIN_GOTOFF17M4:
        case R_BFIN_GOTOFF17M4:
        case R_BFIN_GOTOFFHI:
        case R_BFIN_GOTOFFHI:
        case R_BFIN_GOTOFFLO:
        case R_BFIN_GOTOFFLO:
          picrel->gotoff = 1;
          picrel->gotoff++;
          break;
          break;
 
 
        case R_BFIN_FUNCDESC_GOTOFF17M4:
        case R_BFIN_FUNCDESC_GOTOFF17M4:
          picrel->fdgoff17m4 = 1;
          picrel->fdgoff17m4++;
          break;
          break;
 
 
        case R_BFIN_FUNCDESC_GOTOFFHI:
        case R_BFIN_FUNCDESC_GOTOFFHI:
        case R_BFIN_FUNCDESC_GOTOFFLO:
        case R_BFIN_FUNCDESC_GOTOFFLO:
          picrel->fdgoffhilo = 1;
          picrel->fdgoffhilo++;
          break;
          break;
 
 
        case R_BFIN_FUNCDESC:
        case R_BFIN_FUNCDESC:
          picrel->fd = 1;
          picrel->fd++;
          picrel->relocsfd++;
          picrel->relocsfd++;
          break;
          break;
 
 
        /* This relocation describes the C++ object vtable hierarchy.
        /* This relocation describes the C++ object vtable hierarchy.
           Reconstruct it for later use during GC.  */
           Reconstruct it for later use during GC.  */
Line 4681... Line 4958...
          if (h != NULL
          if (h != NULL
              && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
              && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
            return FALSE;
            return FALSE;
          break;
          break;
 
 
        case R_huimm16:
        case R_BFIN_HUIMM16:
        case R_luimm16:
        case R_BFIN_LUIMM16:
        case R_pcrel12_jump_s:
        case R_BFIN_PCREL12_JUMP_S:
        case R_pcrel10:
        case R_BFIN_PCREL10:
          break;
          break;
 
 
        default:
        default:
        bad_reloc:
        bad_reloc:
          (*_bfd_error_handler)
          (*_bfd_error_handler)
Line 4873... Line 5150...
 
 
struct bfin_link_hash_table
struct bfin_link_hash_table
{
{
  struct elf_link_hash_table root;
  struct elf_link_hash_table root;
 
 
  /* Small local sym to section mapping cache.  */
  /* Small local sym cache.  */
  struct sym_sec_cache sym_sec;
  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))
 
 
static struct bfd_hash_entry *
static struct bfd_hash_entry *
Line 4920... Line 5197...
    {
    {
      free (ret);
      free (ret);
      return NULL;
      return NULL;
    }
    }
 
 
  ret->sym_sec.abfd = NULL;
  ret->sym_cache.abfd = NULL;
 
 
  return &ret->root.root;
  return &ret->root.root;
}
}
 
 
/* The size in bytes of an entry in the procedure linkage table.  */
/* The size in bytes of an entry in the procedure linkage table.  */
Line 5001... Line 5278...
      if (info->shared
      if (info->shared
          && (info->symbolic
          && (info->symbolic
              || h->dynindx == -1 || h->forced_local) && h->def_regular)
              || h->dynindx == -1 || h->forced_local) && h->def_regular)
        {
        {
          fprintf(stderr, "*** check this relocation %s\n", __FUNCTION__);
          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,
          rela.r_addend = bfd_get_signed_32 (output_bfd,
                                             (sgot->contents
                                             (sgot->contents
                                              +
                                              +
                                              (h->got.
                                              (h->got.
                                               offset & ~(bfd_vma) 1)));
                                               offset & ~(bfd_vma) 1)));
        }
        }
      else
      else
        {
        {
          bfd_put_32 (output_bfd, (bfd_vma) 0,
          bfd_put_32 (output_bfd, (bfd_vma) 0,
                      sgot->contents + (h->got.offset & ~(bfd_vma) 1));
                      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;
        }
        }
 
 
      loc = srela->contents;
      loc = srela->contents;
      loc += srela->reloc_count++ * sizeof (Elf32_External_Rela);
      loc += srela->reloc_count++ * sizeof (Elf32_External_Rela);
Line 5407... Line 5684...
       section which must be relocated.  It is followed by the name
       section which must be relocated.  It is followed by the name
       of the target section NUL-padded or truncated to 8
       of the target section NUL-padded or truncated to 8
       characters.  */
       characters.  */
 
 
      /* We can only relocate absolute longword relocs at run time.  */
      /* 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");
          *errmsg = _("unsupported reloc type");
          bfd_set_error (bfd_error_bad_value);
          bfd_set_error (bfd_error_bad_value);
          goto error_return;
          goto error_return;
        }
        }
Line 5472... Line 5749...
  if (internal_relocs != NULL
  if (internal_relocs != NULL
      && elf_section_data (datasec)->relocs != internal_relocs)
      && elf_section_data (datasec)->relocs != internal_relocs)
    free (internal_relocs);
    free (internal_relocs);
  return FALSE;
  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 }
 
};
 
 


#define TARGET_LITTLE_SYM               bfd_elf32_bfin_vec
#define TARGET_LITTLE_SYM               bfd_elf32_bfin_vec
#define TARGET_LITTLE_NAME              "elf32-bfin"
#define TARGET_LITTLE_NAME              "elf32-bfin"
#define ELF_ARCH                        bfd_arch_bfin
#define ELF_ARCH                        bfd_arch_bfin
#define ELF_MACHINE_CODE                EM_BLACKFIN
#define ELF_MACHINE_CODE                EM_BLACKFIN
Line 5520... Line 5805...
                                        elf32_bfin_set_private_flags
                                        elf32_bfin_set_private_flags
#define bfd_elf32_bfd_print_private_bfd_data \
#define bfd_elf32_bfd_print_private_bfd_data \
                                        elf32_bfin_print_private_bfd_data
                                        elf32_bfin_print_private_bfd_data
#define elf_backend_reloc_type_class    elf32_bfin_reloc_type_class
#define elf_backend_reloc_type_class    elf32_bfin_reloc_type_class
#define elf_backend_can_gc_sections 1
#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_can_refcount 1
#define elf_backend_want_got_plt 0
#define elf_backend_want_got_plt 0
#define elf_backend_plt_readonly 1
#define elf_backend_plt_readonly 1
#define elf_backend_want_plt_sym 0
#define elf_backend_want_plt_sym 0
#define elf_backend_got_header_size     12
#define elf_backend_got_header_size     12
Line 5537... Line 5823...
#define TARGET_LITTLE_NAME              "elf32-bfinfdpic"
#define TARGET_LITTLE_NAME              "elf32-bfinfdpic"
#undef  elf32_bed
#undef  elf32_bed
#define elf32_bed               elf32_bfinfdpic_bed
#define elf32_bed               elf32_bfinfdpic_bed
 
 
#undef elf_backend_gc_sweep_hook
#undef elf_backend_gc_sweep_hook
 
#define elf_backend_gc_sweep_hook       bfinfdpic_gc_sweep_hook
 
 
#undef elf_backend_got_header_size
#undef elf_backend_got_header_size
#define elf_backend_got_header_size     0
#define elf_backend_got_header_size     0
 
 
#undef elf_backend_relocate_section
#undef elf_backend_relocate_section
Line 5575... Line 5862...
                elf32_bfinfdpic_finish_dynamic_symbol
                elf32_bfinfdpic_finish_dynamic_symbol
#undef elf_backend_finish_dynamic_sections
#undef elf_backend_finish_dynamic_sections
#define elf_backend_finish_dynamic_sections \
#define elf_backend_finish_dynamic_sections \
                elf32_bfinfdpic_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
#undef elf_backend_can_make_relative_eh_frame
#define elf_backend_can_make_relative_eh_frame \
#define elf_backend_can_make_relative_eh_frame \
                bfinfdpic_elf_use_relative_eh_frame
                bfinfdpic_elf_use_relative_eh_frame
#undef elf_backend_can_make_lsda_relative_eh_frame
#undef elf_backend_can_make_lsda_relative_eh_frame
#define elf_backend_can_make_lsda_relative_eh_frame \
#define elf_backend_can_make_lsda_relative_eh_frame \

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.