summaryrefslogtreecommitdiff
path: root/package/binutils
diff options
context:
space:
mode:
authorWaldemar Brodkorb <wbx@openadk.org>2016-01-05 18:57:50 +0100
committerWaldemar Brodkorb <wbx@openadk.org>2016-01-05 18:57:57 +0100
commite1c2aa3954889443c5c26bbfaf09b1a4d819fdb6 (patch)
tree3a6d208023e41d4f2512c7b89dc73df7cb832e06 /package/binutils
parent0302664a0116a1b4eff8ab932abffde85953abac (diff)
fix binutils compile for avr32 target
Diffstat (limited to 'package/binutils')
-rw-r--r--package/binutils/patches/2.20.1/avr32.patch30797
1 files changed, 30797 insertions, 0 deletions
diff --git a/package/binutils/patches/2.20.1/avr32.patch b/package/binutils/patches/2.20.1/avr32.patch
new file mode 100644
index 000000000..646049cc0
--- /dev/null
+++ b/package/binutils/patches/2.20.1/avr32.patch
@@ -0,0 +1,30797 @@
+--- a/bfd/archures.c
++++ b/bfd/archures.c
+@@ -368,6 +368,12 @@ DESCRIPTION
+ .#define bfd_mach_avr5 5
+ .#define bfd_mach_avr51 51
+ .#define bfd_mach_avr6 6
++. bfd_arch_avr32, {* Atmel AVR32 *}
++.#define bfd_mach_avr32_ap 7000
++.#define bfd_mach_avr32_uc 3000
++.#define bfd_mach_avr32_ucr1 3001
++.#define bfd_mach_avr32_ucr2 3002
++.#define bfd_mach_avr32_ucr3 3003
+ . bfd_arch_bfin, {* ADI Blackfin *}
+ .#define bfd_mach_bfin 1
+ . bfd_arch_cr16, {* National Semiconductor CompactRISC (ie CR16). *}
+@@ -465,6 +471,7 @@ extern const bfd_arch_info_type bfd_alph
+ extern const bfd_arch_info_type bfd_arc_arch;
+ extern const bfd_arch_info_type bfd_arm_arch;
+ extern const bfd_arch_info_type bfd_avr_arch;
++extern const bfd_arch_info_type bfd_avr32_arch;
+ extern const bfd_arch_info_type bfd_bfin_arch;
+ extern const bfd_arch_info_type bfd_cr16_arch;
+ extern const bfd_arch_info_type bfd_cr16c_arch;
+@@ -541,6 +548,7 @@ static const bfd_arch_info_type * const
+ &bfd_arc_arch,
+ &bfd_arm_arch,
+ &bfd_avr_arch,
++ &bfd_avr32_arch,
+ &bfd_bfin_arch,
+ &bfd_cr16_arch,
+ &bfd_cr16c_arch,
+--- a/bfd/config.bfd
++++ b/bfd/config.bfd
+@@ -347,6 +347,10 @@ case "${targ}" in
+ targ_underscore=yes
+ ;;
+
++ avr32-*-*)
++ targ_defvec=bfd_elf32_avr32_vec
++ ;;
++
+ c30-*-*aout* | tic30-*-*aout*)
+ targ_defvec=tic30_aout_vec
+ ;;
+--- a/bfd/configure.in
++++ b/bfd/configure.in
+@@ -675,6 +675,7 @@ do
+ bfd_pei_ia64_vec) tb="$tb pei-ia64.lo pepigen.lo cofflink.lo"; target_size=64 ;;
+ bfd_elf32_am33lin_vec) tb="$tb elf32-am33lin.lo elf32.lo $elf" ;;
+ bfd_elf32_avr_vec) tb="$tb elf32-avr.lo elf32.lo $elf" ;;
++ bfd_elf32_avr32_vec) tb="$tb elf32-avr32.lo elf32.lo $elf" ;;
+ bfd_elf32_bfin_vec) tb="$tb elf32-bfin.lo elf32.lo $elf" ;;
+ bfd_elf32_bfinfdpic_vec) tb="$tb elf32-bfin.lo elf32.lo $elf" ;;
+ bfd_elf32_big_generic_vec) tb="$tb elf32-gen.lo elf32.lo $elf" ;;
+--- /dev/null
++++ b/bfd/cpu-avr32.c
+@@ -0,0 +1,52 @@
++/* BFD library support routines for AVR32.
++ Copyright 2003,2004,2005,2006,2007,2008,2009 Atmel Corporation.
++
++ Written by Haavard Skinnemoen, Atmel Norway, <hskinnemoen@atmel.com>
++
++ This is part of BFD, the Binary File Descriptor library.
++
++ 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
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
++
++#include "bfd.h"
++#include "sysdep.h"
++#include "libbfd.h"
++
++#define N(machine, print, default, next) \
++ { \
++ 32, /* 32 bits in a word */ \
++ 32, /* 32 bits in an address */ \
++ 8, /* 8 bits in a byte */ \
++ bfd_arch_avr32, /* architecture */ \
++ machine, /* machine */ \
++ "avr32", /* arch name */ \
++ print, /* printable name */ \
++ 1, /* section align power */ \
++ default, /* the default machine? */ \
++ bfd_default_compatible, \
++ bfd_default_scan, \
++ next, \
++ }
++
++static const bfd_arch_info_type cpu_info[] =
++{
++ N(bfd_mach_avr32_ap, "avr32:ap", FALSE, &cpu_info[1]),
++ N(bfd_mach_avr32_uc, "avr32:uc", FALSE, &cpu_info[2]),
++ N(bfd_mach_avr32_ucr1, "avr32:ucr1", FALSE, &cpu_info[3]),
++ N(bfd_mach_avr32_ucr2, "avr32:ucr2", FALSE, &cpu_info[4]),
++ N(bfd_mach_avr32_ucr3, "avr32:ucr3", FALSE, NULL),
++};
++
++const bfd_arch_info_type bfd_avr32_arch =
++ N(bfd_mach_avr32_ap, "avr32", TRUE, &cpu_info[0]);
+--- /dev/null
++++ b/bfd/elf32-avr32.c
+@@ -0,0 +1,3915 @@
++/* AVR32-specific support for 32-bit ELF.
++ Copyright 2003,2004,2005,2006,2007,2008,2009 Atmel Corporation.
++
++ Written by Haavard Skinnemoen, Atmel Norway, <hskinnemoen@atmel.com>
++
++ This file is part of BFD, the Binary File Descriptor library.
++
++ 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
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
++
++#include "bfd.h"
++#include "sysdep.h"
++#include "bfdlink.h"
++#include "libbfd.h"
++#include "elf-bfd.h"
++#include "elf/avr32.h"
++#include "elf32-avr32.h"
++
++#define xDEBUG
++#define xRELAX_DEBUG
++
++#ifdef DEBUG
++# define pr_debug(fmt, args...) fprintf(stderr, fmt, ##args)
++#else
++# define pr_debug(fmt, args...) do { } while (0)
++#endif
++
++#ifdef RELAX_DEBUG
++# define RDBG(fmt, args...) fprintf(stderr, fmt, ##args)
++#else
++# define RDBG(fmt, args...) do { } while (0)
++#endif
++
++/* When things go wrong, we want it to blow up, damnit! */
++#undef BFD_ASSERT
++#undef abort
++#define BFD_ASSERT(expr) \
++ do \
++ { \
++ if (!(expr)) \
++ { \
++ bfd_assert(__FILE__, __LINE__); \
++ abort(); \
++ } \
++ } \
++ while (0)
++
++/* The name of the dynamic interpreter. This is put in the .interp section. */
++#define ELF_DYNAMIC_INTERPRETER "/lib/ld.so.1"
++
++#define AVR32_GOT_HEADER_SIZE 8
++#define AVR32_FUNCTION_STUB_SIZE 8
++
++#define ELF_R_INFO(x, y) ELF32_R_INFO(x, y)
++#define ELF_R_TYPE(x) ELF32_R_TYPE(x)
++#define ELF_R_SYM(x) ELF32_R_SYM(x)
++
++#define NOP_OPCODE 0xd703
++
++
++/* Mapping between BFD relocations and ELF relocations */
++
++static reloc_howto_type *
++bfd_elf32_bfd_reloc_type_lookup(bfd *abfd, bfd_reloc_code_real_type code);
++
++static reloc_howto_type *
++bfd_elf32_bfd_reloc_name_lookup(bfd *abfd, const char *r_name);
++
++static void
++avr32_info_to_howto (bfd *abfd, arelent *cache_ptr, Elf_Internal_Rela *dst);
++
++/* Generic HOWTO */
++#define GENH(name, align, size, bitsize, pcrel, bitpos, complain, mask) \
++ HOWTO(name, align, size, bitsize, pcrel, bitpos, \
++ complain_overflow_##complain, bfd_elf_generic_reloc, #name, \
++ FALSE, 0, mask, pcrel)
++
++static reloc_howto_type elf_avr32_howto_table[] = {
++ /* NAME ALN SZ BSZ PCREL BP COMPLAIN MASK */
++ GENH(R_AVR32_NONE, 0, 0, 0, FALSE, 0, dont, 0x00000000),
++
++ GENH(R_AVR32_32, 0, 2, 32, FALSE, 0, dont, 0xffffffff),
++ GENH(R_AVR32_16, 0, 1, 16, FALSE, 0, bitfield, 0x0000ffff),
++ GENH(R_AVR32_8, 0, 0, 8, FALSE, 0, bitfield, 0x000000ff),
++ GENH(R_AVR32_32_PCREL, 0, 2, 32, TRUE, 0, signed, 0xffffffff),
++ GENH(R_AVR32_16_PCREL, 0, 1, 16, TRUE, 0, signed, 0x0000ffff),
++ GENH(R_AVR32_8_PCREL, 0, 0, 8, TRUE, 0, signed, 0x000000ff),
++
++ /* Difference between two symbol (sym2 - sym1). The reloc encodes
++ the value of sym1. The field contains the difference before any
++ relaxing is done. */
++ GENH(R_AVR32_DIFF32, 0, 2, 32, FALSE, 0, dont, 0xffffffff),
++ GENH(R_AVR32_DIFF16, 0, 1, 16, FALSE, 0, signed, 0x0000ffff),
++ GENH(R_AVR32_DIFF8, 0, 0, 8, FALSE, 0, signed, 0x000000ff),
++
++ GENH(R_AVR32_GOT32, 0, 2, 32, FALSE, 0, signed, 0xffffffff),
++ GENH(R_AVR32_GOT16, 0, 1, 16, FALSE, 0, signed, 0x0000ffff),
++ GENH(R_AVR32_GOT8, 0, 0, 8, FALSE, 0, signed, 0x000000ff),
++
++ GENH(R_AVR32_21S, 0, 2, 21, FALSE, 0, signed, 0x1e10ffff),
++ GENH(R_AVR32_16U, 0, 2, 16, FALSE, 0, unsigned, 0x0000ffff),
++ GENH(R_AVR32_16S, 0, 2, 16, FALSE, 0, signed, 0x0000ffff),
++ GENH(R_AVR32_8S, 0, 1, 8, FALSE, 4, signed, 0x00000ff0),
++ GENH(R_AVR32_8S_EXT, 0, 2, 8, FALSE, 0, signed, 0x000000ff),
++
++ GENH(R_AVR32_22H_PCREL, 1, 2, 21, TRUE, 0, signed, 0x1e10ffff),
++ GENH(R_AVR32_18W_PCREL, 2, 2, 16, TRUE, 0, signed, 0x0000ffff),
++ GENH(R_AVR32_16B_PCREL, 0, 2, 16, TRUE, 0, signed, 0x0000ffff),
++ GENH(R_AVR32_16N_PCREL, 0, 2, 16, TRUE, 0, signed, 0x0000ffff),
++ GENH(R_AVR32_14UW_PCREL, 2, 2, 12, TRUE, 0, unsigned, 0x0000f0ff),
++ GENH(R_AVR32_11H_PCREL, 1, 1, 10, TRUE, 4, signed, 0x00000ff3),
++ GENH(R_AVR32_10UW_PCREL, 2, 2, 8, TRUE, 0, unsigned, 0x000000ff),
++ GENH(R_AVR32_9H_PCREL, 1, 1, 8, TRUE, 4, signed, 0x00000ff0),
++ GENH(R_AVR32_9UW_PCREL, 2, 1, 7, TRUE, 4, unsigned, 0x000007f0),
++
++ GENH(R_AVR32_HI16, 16, 2, 16, FALSE, 0, dont, 0x0000ffff),
++ GENH(R_AVR32_LO16, 0, 2, 16, FALSE, 0, dont, 0x0000ffff),
++
++ GENH(R_AVR32_GOTPC, 0, 2, 32, FALSE, 0, dont, 0xffffffff),
++ GENH(R_AVR32_GOTCALL, 2, 2, 21, FALSE, 0, signed, 0x1e10ffff),
++ GENH(R_AVR32_LDA_GOT, 2, 2, 21, FALSE, 0, signed, 0x1e10ffff),
++ GENH(R_AVR32_GOT21S, 0, 2, 21, FALSE, 0, signed, 0x1e10ffff),
++ GENH(R_AVR32_GOT18SW, 2, 2, 16, FALSE, 0, signed, 0x0000ffff),
++ GENH(R_AVR32_GOT16S, 0, 2, 16, FALSE, 0, signed, 0x0000ffff),
++ GENH(R_AVR32_GOT7UW, 2, 1, 5, FALSE, 4, unsigned, 0x000001f0),
++
++ GENH(R_AVR32_32_CPENT, 0, 2, 32, FALSE, 0, dont, 0xffffffff),
++ GENH(R_AVR32_CPCALL, 2, 2, 16, TRUE, 0, signed, 0x0000ffff),
++ GENH(R_AVR32_16_CP, 0, 2, 16, TRUE, 0, signed, 0x0000ffff),
++ GENH(R_AVR32_9W_CP, 2, 1, 7, TRUE, 4, unsigned, 0x000007f0),
++
++ GENH(R_AVR32_RELATIVE, 0, 2, 32, FALSE, 0, signed, 0xffffffff),
++ GENH(R_AVR32_GLOB_DAT, 0, 2, 32, FALSE, 0, dont, 0xffffffff),
++ GENH(R_AVR32_JMP_SLOT, 0, 2, 32, FALSE, 0, dont, 0xffffffff),
++
++ GENH(R_AVR32_ALIGN, 0, 1, 0, FALSE, 0, unsigned, 0x00000000),
++
++ GENH(R_AVR32_15S, 2, 2, 15, FALSE, 0, signed, 0x00007fff),
++};
++
++struct elf_reloc_map
++{
++ bfd_reloc_code_real_type bfd_reloc_val;
++ unsigned char elf_reloc_val;
++};
++
++static const struct elf_reloc_map avr32_reloc_map[] =
++{
++ { BFD_RELOC_NONE, R_AVR32_NONE },
++
++ { BFD_RELOC_32, R_AVR32_32 },
++ { BFD_RELOC_16, R_AVR32_16 },
++ { BFD_RELOC_8, R_AVR32_8 },
++ { BFD_RELOC_32_PCREL, R_AVR32_32_PCREL },
++ { BFD_RELOC_16_PCREL, R_AVR32_16_PCREL },
++ { BFD_RELOC_8_PCREL, R_AVR32_8_PCREL },
++ { BFD_RELOC_AVR32_DIFF32, R_AVR32_DIFF32 },
++ { BFD_RELOC_AVR32_DIFF16, R_AVR32_DIFF16 },
++ { BFD_RELOC_AVR32_DIFF8, R_AVR32_DIFF8 },
++ { BFD_RELOC_AVR32_GOT32, R_AVR32_GOT32 },
++ { BFD_RELOC_AVR32_GOT16, R_AVR32_GOT16 },
++ { BFD_RELOC_AVR32_GOT8, R_AVR32_GOT8 },
++
++ { BFD_RELOC_AVR32_21S, R_AVR32_21S },
++ { BFD_RELOC_AVR32_16U, R_AVR32_16U },
++ { BFD_RELOC_AVR32_16S, R_AVR32_16S },
++ { BFD_RELOC_AVR32_SUB5, R_AVR32_16S },
++ { BFD_RELOC_AVR32_8S_EXT, R_AVR32_8S_EXT },
++ { BFD_RELOC_AVR32_8S, R_AVR32_8S },
++
++ { BFD_RELOC_AVR32_22H_PCREL, R_AVR32_22H_PCREL },
++ { BFD_RELOC_AVR32_18W_PCREL, R_AVR32_18W_PCREL },
++ { BFD_RELOC_AVR32_16B_PCREL, R_AVR32_16B_PCREL },
++ { BFD_RELOC_AVR32_16N_PCREL, R_AVR32_16N_PCREL },
++ { BFD_RELOC_AVR32_11H_PCREL, R_AVR32_11H_PCREL },
++ { BFD_RELOC_AVR32_10UW_PCREL, R_AVR32_10UW_PCREL },
++ { BFD_RELOC_AVR32_9H_PCREL, R_AVR32_9H_PCREL },
++ { BFD_RELOC_AVR32_9UW_PCREL, R_AVR32_9UW_PCREL },
++
++ { BFD_RELOC_HI16, R_AVR32_HI16 },
++ { BFD_RELOC_LO16, R_AVR32_LO16 },
++
++ { BFD_RELOC_AVR32_GOTPC, R_AVR32_GOTPC },
++ { BFD_RELOC_AVR32_GOTCALL, R_AVR32_GOTCALL },
++ { BFD_RELOC_AVR32_LDA_GOT, R_AVR32_LDA_GOT },
++ { BFD_RELOC_AVR32_GOT21S, R_AVR32_GOT21S },
++ { BFD_RELOC_AVR32_GOT18SW, R_AVR32_GOT18SW },
++ { BFD_RELOC_AVR32_GOT16S, R_AVR32_GOT16S },
++ /* GOT7UW should never be generated by the assembler */
++
++ { BFD_RELOC_AVR32_32_CPENT, R_AVR32_32_CPENT },
++ { BFD_RELOC_AVR32_CPCALL, R_AVR32_CPCALL },
++ { BFD_RELOC_AVR32_16_CP, R_AVR32_16_CP },
++ { BFD_RELOC_AVR32_9W_CP, R_AVR32_9W_CP },
++
++ { BFD_RELOC_AVR32_ALIGN, R_AVR32_ALIGN },
++
++ { BFD_RELOC_AVR32_15S, R_AVR32_15S },
++};
++
++static reloc_howto_type *
++bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
++ bfd_reloc_code_real_type code)
++{
++ unsigned int i;
++
++ for (i = 0; i < sizeof(avr32_reloc_map) / sizeof(struct elf_reloc_map); i++)
++ {
++ if (avr32_reloc_map[i].bfd_reloc_val == code)
++ return &elf_avr32_howto_table[avr32_reloc_map[i].elf_reloc_val];
++ }
++
++ return NULL;
++}
++
++static reloc_howto_type *
++bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
++ const char *r_name)
++{
++ unsigned int i;
++
++ for (i = 0;
++ i < sizeof (elf_avr32_howto_table) / sizeof (elf_avr32_howto_table[0]);
++ i++)
++ if (elf_avr32_howto_table[i].name != NULL
++ && strcasecmp (elf_avr32_howto_table[i].name, r_name) == 0)
++ return &elf_avr32_howto_table[i];
++
++ return NULL;
++}
++
++/* Set the howto pointer for an AVR32 ELF reloc. */
++static void
++avr32_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED,
++ arelent *cache_ptr,
++ Elf_Internal_Rela *dst)
++{
++ unsigned int r_type;
++
++ r_type = ELF32_R_TYPE (dst->r_info);
++ BFD_ASSERT (r_type < (unsigned int) R_AVR32_max);
++ cache_ptr->howto = &elf_avr32_howto_table[r_type];
++}
++
++
++/* AVR32 ELF linker hash table and associated hash entries. */
++
++static struct bfd_hash_entry *
++avr32_elf_link_hash_newfunc(struct bfd_hash_entry *entry,
++ struct bfd_hash_table *table,
++ const char *string);
++static void
++avr32_elf_copy_indirect_symbol(struct bfd_link_info *info,
++ struct elf_link_hash_entry *dir,
++ struct elf_link_hash_entry *ind);
++static struct bfd_link_hash_table *
++avr32_elf_link_hash_table_create(bfd *abfd);
++
++/*
++ Try to limit memory usage to something reasonable when sorting the
++ GOT. If just a couple of entries end up getting more references
++ than this, it won't affect performance at all, but if there are many
++ of them, we could end up with the wrong symbols being assigned the
++ first GOT entries.
++*/
++#define MAX_NR_GOT_HOLES 2048
++
++/*
++ AVR32 GOT entry. We need to keep track of refcounts and offsets
++ simultaneously, since we need the offsets during relaxation, and we
++ also want to be able to drop GOT entries during relaxation. In
++ addition to this, we want to keep the list of GOT entries sorted so
++ that we can keep the most-used entries at the lowest offsets.
++*/
++struct got_entry
++{
++ struct got_entry *next;
++ struct got_entry **pprev;
++ int refcount;
++ bfd_signed_vma offset;
++};
++
++struct elf_avr32_link_hash_entry
++{
++ struct elf_link_hash_entry root;
++
++ /* Number of runtime relocations against this symbol. */
++ unsigned int possibly_dynamic_relocs;
++
++ /* If there are anything but R_AVR32_GOT18 relocations against this
++ symbol, it means that someone may be taking the address of the
++ function, and we should therefore not create a stub. */
++ bfd_boolean no_fn_stub;
++
++ /* If there is a R_AVR32_32 relocation in a read-only section
++ against this symbol, we could be in trouble. If we're linking a
++ shared library or this symbol is defined in one, it means we must
++ emit a run-time reloc for it and that's not allowed in read-only
++ sections. */
++ asection *readonly_reloc_sec;
++ bfd_vma readonly_reloc_offset;
++
++ /* Record which frag (if any) contains the symbol. This is used
++ during relaxation in order to avoid having to update all symbols
++ whenever we move something. For local symbols, this information
++ is in the local_sym_frag member of struct elf_obj_tdata. */
++ struct fragment *sym_frag;
++};
++#define avr32_elf_hash_entry(ent) ((struct elf_avr32_link_hash_entry *)(ent))
++
++struct elf_avr32_link_hash_table
++{
++ struct elf_link_hash_table root;
++
++ /* Shortcuts to get to dynamic linker sections. */
++ asection *sgot;
++ asection *srelgot;
++ asection *sstub;
++
++ /* We use a variation of Pigeonhole Sort to sort the GOT. After the
++ initial refcounts have been determined, we initialize
++ nr_got_holes to the highest refcount ever seen and allocate an
++ array of nr_got_holes entries for got_hole. Each GOT entry is
++ then stored in this array at the index given by its refcount.
++
++ When a GOT entry has its refcount decremented during relaxation,
++ it is moved to a lower index in the got_hole array.
++ */
++ struct got_entry **got_hole;
++ int nr_got_holes;
++
++ /* Dynamic relocations to local symbols. Only used when linking a
++ shared library and -Bsymbolic is not given. */
++ unsigned int local_dynamic_relocs;
++
++ bfd_boolean relocations_analyzed;
++ bfd_boolean symbols_adjusted;
++ bfd_boolean repeat_pass;
++ bfd_boolean direct_data_refs;
++ unsigned int relax_iteration;
++ unsigned int relax_pass;
++};
++#define avr32_elf_hash_table(p) \
++ ((struct elf_avr32_link_hash_table *)((p)->hash))
++
++static struct bfd_hash_entry *
++avr32_elf_link_hash_newfunc(struct bfd_hash_entry *entry,
++ struct bfd_hash_table *table,
++ const char *string)
++{
++ struct elf_avr32_link_hash_entry *ret = avr32_elf_hash_entry(entry);
++
++ /* Allocate the structure if it hasn't already been allocated by a
++ subclass */
++ if (ret == NULL)
++ ret = (struct elf_avr32_link_hash_entry *)
++ bfd_hash_allocate(table, sizeof(struct elf_avr32_link_hash_entry));
++
++ if (ret == NULL)
++ return NULL;
++
++ memset(ret, 0, sizeof(struct elf_avr32_link_hash_entry));
++
++ /* Give the superclass a chance */
++ ret = (struct elf_avr32_link_hash_entry *)
++ _bfd_elf_link_hash_newfunc((struct bfd_hash_entry *)ret, table, string);
++
++ return (struct bfd_hash_entry *)ret;
++}
++
++/* Copy data from an indirect symbol to its direct symbol, hiding the
++ old indirect symbol. Process additional relocation information.
++ Also called for weakdefs, in which case we just let
++ _bfd_elf_link_hash_copy_indirect copy the flags for us. */
++
++static void
++avr32_elf_copy_indirect_symbol(struct bfd_link_info *info,
++ struct elf_link_hash_entry *dir,
++ struct elf_link_hash_entry *ind)
++{
++ struct elf_avr32_link_hash_entry *edir, *eind;
++
++ _bfd_elf_link_hash_copy_indirect (info, dir, ind);
++
++ if (ind->root.type != bfd_link_hash_indirect)
++ return;
++
++ edir = (struct elf_avr32_link_hash_entry *)dir;
++ eind = (struct elf_avr32_link_hash_entry *)ind;
++
++ edir->possibly_dynamic_relocs += eind->possibly_dynamic_relocs;
++ edir->no_fn_stub = edir->no_fn_stub || eind->no_fn_stub;
++}
++
++static struct bfd_link_hash_table *
++avr32_elf_link_hash_table_create(bfd *abfd)
++{
++ struct elf_avr32_link_hash_table *ret;
++
++ ret = bfd_zmalloc(sizeof(*ret));
++ if (ret == NULL)
++ return NULL;
++
++ if (! _bfd_elf_link_hash_table_init(&ret->root, abfd,
++ avr32_elf_link_hash_newfunc,
++ sizeof (struct elf_avr32_link_hash_entry)))
++ {
++ free(ret);
++ return NULL;
++ }
++
++ /* Prevent the BFD core from creating bogus got_entry pointers */
++ ret->root.init_got_refcount.glist = NULL;
++ ret->root.init_plt_refcount.glist = NULL;
++ ret->root.init_got_offset.glist = NULL;
++ ret->root.init_plt_offset.glist = NULL;
++
++ return &ret->root.root;
++}
++
++
++/* Initial analysis and creation of dynamic sections and symbols */
++
++static asection *
++create_dynamic_section(bfd *dynobj, const char *name, flagword flags,
++ unsigned int align_power);
++static struct elf_link_hash_entry *
++create_dynamic_symbol(bfd *dynobj, struct bfd_link_info *info,
++ const char *name, asection *sec,
++ bfd_vma offset);
++static bfd_boolean
++avr32_elf_create_got_section (bfd *dynobj, struct bfd_link_info *info);
++static bfd_boolean
++avr32_elf_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info);
++static bfd_boolean
++avr32_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec,
++ const Elf_Internal_Rela *relocs);
++static bfd_boolean
++avr32_elf_adjust_dynamic_symbol(struct bfd_link_info *info,
++ struct elf_link_hash_entry *h);
++
++static asection *
++create_dynamic_section(bfd *dynobj, const char *name, flagword flags,
++ unsigned int align_power)
++{
++ asection *sec;
++
++ sec = bfd_make_section(dynobj, name);
++ if (!sec
++ || !bfd_set_section_flags(dynobj, sec, flags)
++ || !bfd_set_section_alignment(dynobj, sec, align_power))
++ return NULL;
++
++ return sec;
++}
++
++static struct elf_link_hash_entry *
++create_dynamic_symbol(bfd *dynobj, struct bfd_link_info *info,
++ const char *name, asection *sec,
++ bfd_vma offset)
++{
++ struct bfd_link_hash_entry *bh = NULL;
++ struct elf_link_hash_entry *h;
++ const struct elf_backend_data *bed = get_elf_backend_data (dynobj);
++
++ if (!(_bfd_generic_link_add_one_symbol
++ (info, dynobj, name, BSF_GLOBAL, sec, offset, NULL, FALSE,
++ bed->collect, &bh)))
++ return NULL;
++
++ h = (struct elf_link_hash_entry *)bh;
++ h->def_regular = 1;
++ h->type = STT_OBJECT;
++ h->other = STV_HIDDEN;
++
++ return h;
++}
++
++static bfd_boolean
++avr32_elf_create_got_section (bfd *dynobj, struct bfd_link_info *info)
++{
++ struct elf_avr32_link_hash_table *htab;
++ flagword flags;
++ const struct elf_backend_data *bed = get_elf_backend_data (dynobj);
++
++ htab = avr32_elf_hash_table(info);
++ flags = bed->dynamic_sec_flags;
++
++ if (htab->sgot)
++ return TRUE;
++
++ htab->sgot = create_dynamic_section(dynobj, ".got", flags, 2);
++ if (!htab->srelgot)
++ htab->srelgot = create_dynamic_section(dynobj, ".rela.got",
++ flags | SEC_READONLY, 2);
++
++ if (!htab->sgot || !htab->srelgot)
++ return FALSE;
++
++ htab->root.hgot = create_dynamic_symbol(dynobj, info, "_GLOBAL_OFFSET_TABLE_",
++ htab->sgot, 0);
++ if (!htab->root.hgot)
++ return FALSE;
++
++ /* Make room for the GOT header */
++ htab->sgot->size += bed->got_header_size;
++
++ return TRUE;
++}
++
++/* (1) Create all dynamic (i.e. linker generated) sections that we may
++ need during the link */
++
++static bfd_boolean
++avr32_elf_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info)
++{
++ struct elf_avr32_link_hash_table *htab;
++ flagword flags;
++ const struct elf_backend_data *bed = get_elf_backend_data (dynobj);
++
++ pr_debug("(1) create dynamic sections\n");
++
++ htab = avr32_elf_hash_table(info);
++ flags = bed->dynamic_sec_flags;
++
++ if (!avr32_elf_create_got_section (dynobj, info))
++ return FALSE;
++
++ if (!htab->sstub)
++ htab->sstub = create_dynamic_section(dynobj, ".stub",
++ flags | SEC_READONLY | SEC_CODE, 2);
++
++ if (!htab->sstub)
++ return FALSE;
++
++ return TRUE;
++}
++
++/* (2) Go through all the relocs and count any potential GOT- or
++ PLT-references to each symbol */
++
++static bfd_boolean
++avr32_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec,
++ const Elf_Internal_Rela *relocs)
++{
++ Elf_Internal_Shdr *symtab_hdr;
++ struct elf_avr32_link_hash_table *htab;
++ struct elf_link_hash_entry **sym_hashes;
++ const Elf_Internal_Rela *rel, *rel_end;
++ struct got_entry **local_got_ents;
++ struct got_entry *got;
++ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
++ asection *sgot;
++ bfd *dynobj;
++
++ pr_debug("(2) check relocs for %s:<%s> (size 0x%lx)\n",
++ abfd->filename, sec->name, sec->size);
++
++ if (info->relocatable)
++ return TRUE;
++
++ dynobj = elf_hash_table(info)->dynobj;
++ symtab_hdr = &elf_tdata(abfd)->symtab_hdr;
++ sym_hashes = elf_sym_hashes(abfd);
++ htab = avr32_elf_hash_table(info);
++ local_got_ents = elf_local_got_ents(abfd);
++ sgot = htab->sgot;
++
++ rel_end = relocs + sec->reloc_count;
++ for (rel = relocs; rel < rel_end; rel++)
++ {
++ unsigned long r_symndx, r_type;
++ struct elf_avr32_link_hash_entry *h;
++
++ r_symndx = ELF32_R_SYM(rel->r_info);
++ r_type = ELF32_R_TYPE(rel->r_info);
++
++ /* Local symbols use local_got_ents, while others store the same
++ information in the hash entry */
++ if (r_symndx < symtab_hdr->sh_info)
++ {
++ pr_debug(" (2a) processing local symbol %lu\n", r_symndx);
++ h = NULL;
++ }
++ else
++ {
++ h = (struct elf_avr32_link_hash_entry *)
++ 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_avr32_link_hash_entry *)h->root.root.u.i.link;
++ pr_debug(" (2a) processing symbol %s\n", h->root.root.root.string);
++ }
++
++ /* Some relocs require special sections to be created. */
++ switch (r_type)
++ {
++ case R_AVR32_GOT32:
++ case R_AVR32_GOT16:
++ case R_AVR32_GOT8:
++ case R_AVR32_GOT21S:
++ case R_AVR32_GOT18SW:
++ case R_AVR32_GOT16S:
++ case R_AVR32_GOT7UW:
++ case R_AVR32_LDA_GOT:
++ case R_AVR32_GOTCALL:
++ if (rel->r_addend)
++ {
++ if (info->callbacks->reloc_dangerous
++ (info, _("Non-zero addend on GOT-relative relocation"),
++ abfd, sec, rel->r_offset) == FALSE)
++ return FALSE;
++ }
++ /* fall through */
++ case R_AVR32_GOTPC:
++ if (dynobj == NULL)
++ elf_hash_table(info)->dynobj = dynobj = abfd;
++ if (sgot == NULL && !avr32_elf_create_got_section(dynobj, info))
++ return FALSE;
++ break;
++ case R_AVR32_32:
++ /* We may need to create .rela.dyn later on. */
++ if (dynobj == NULL
++ && (info->shared || h != NULL)
++ && (sec->flags & SEC_ALLOC))
++ elf_hash_table(info)->dynobj = dynobj = abfd;
++ break;
++ }
++
++ if (h != NULL && r_type != R_AVR32_GOT18SW)
++ h->no_fn_stub = TRUE;
++
++ switch (r_type)
++ {
++ case R_AVR32_GOT32:
++ case R_AVR32_GOT16:
++ case R_AVR32_GOT8:
++ case R_AVR32_GOT21S:
++ case R_AVR32_GOT18SW:
++ case R_AVR32_GOT16S:
++ case R_AVR32_GOT7UW:
++ case R_AVR32_LDA_GOT:
++ case R_AVR32_GOTCALL:
++ if (h != NULL)
++ {
++ got = h->root.got.glist;
++ if (!got)
++ {
++ got = bfd_zalloc(abfd, sizeof(struct got_entry));
++ if (!got)
++ return FALSE;
++ h->root.got.glist = got;
++ }
++ }
++ else
++ {
++ if (!local_got_ents)
++ {
++ bfd_size_type size;
++ bfd_size_type i;
++ struct got_entry *tmp_entry;
++
++ size = symtab_hdr->sh_info;
++ size *= sizeof(struct got_entry *) + sizeof(struct got_entry);
++ local_got_ents = bfd_zalloc(abfd, size);
++ if (!local_got_ents)
++ return FALSE;
++
++ elf_local_got_ents(abfd) = local_got_ents;
++
++ tmp_entry = (struct got_entry *)(local_got_ents
++ + symtab_hdr->sh_info);
++ for (i = 0; i < symtab_hdr->sh_info; i++)
++ local_got_ents[i] = &tmp_entry[i];
++ }
++
++ got = local_got_ents[r_symndx];
++ }
++
++ got->refcount++;
++ if (got->refcount > htab->nr_got_holes)
++ htab->nr_got_holes = got->refcount;
++ break;
++
++ case R_AVR32_32:
++ if ((info->shared || h != NULL)
++ && (sec->flags & SEC_ALLOC))
++ {
++ if (htab->srelgot == NULL)
++ {
++ htab->srelgot = create_dynamic_section(dynobj, ".rela.got",
++ bed->dynamic_sec_flags
++ | SEC_READONLY, 2);
++ if (htab->srelgot == NULL)
++ return FALSE;
++ }
++
++ if (sec->flags & SEC_READONLY
++ && !h->readonly_reloc_sec)
++ {
++ h->readonly_reloc_sec = sec;
++ h->readonly_reloc_offset = rel->r_offset;
++ }
++
++ if (h != NULL)
++ {
++ pr_debug("Non-GOT reference to symbol %s\n",
++ h->root.root.root.string);
++ h->possibly_dynamic_relocs++;
++ }
++ else
++ {
++ pr_debug("Non-GOT reference to local symbol %lu\n",
++ r_symndx);
++ htab->local_dynamic_relocs++;
++ }
++ }
++
++ break;
++
++ /* TODO: GNU_VTINHERIT and GNU_VTENTRY */
++ }
++ }
++
++ return TRUE;
++}
++
++/* (3) Adjust a symbol defined by a dynamic object and referenced by a
++ regular object. The current definition is in some section of the
++ dynamic object, but we're not including those sections. We have to
++ change the definition to something the rest of the link can
++ understand. */
++
++static bfd_boolean
++avr32_elf_adjust_dynamic_symbol(struct bfd_link_info *info,
++ struct elf_link_hash_entry *h)
++{
++ struct elf_avr32_link_hash_table *htab;
++ struct elf_avr32_link_hash_entry *havr;
++ bfd *dynobj;
++
++ pr_debug("(3) adjust dynamic symbol %s\n", h->root.root.string);
++
++ htab = avr32_elf_hash_table(info);
++ havr = (struct elf_avr32_link_hash_entry *)h;
++ dynobj = elf_hash_table(info)->dynobj;
++
++ /* Make sure we know what is going on here. */
++ BFD_ASSERT (dynobj != NULL
++ && (h->u.weakdef != NULL
++ || (h->def_dynamic
++ && h->ref_regular
++ && !h->def_regular)));
++
++ /* We don't want dynamic relocations in read-only sections. */
++ if (havr->readonly_reloc_sec)
++ {
++ if (info->callbacks->reloc_dangerous
++ (info, _("dynamic relocation in read-only section"),
++ havr->readonly_reloc_sec->owner, havr->readonly_reloc_sec,
++ havr->readonly_reloc_offset) == FALSE)
++ return FALSE;
++ }
++
++ /* If this is a function, create a stub if possible and set the
++ symbol to the stub location. */
++ if (0 && !havr->no_fn_stub)
++ {
++ if (!h->def_regular)
++ {
++ asection *s = htab->sstub;
++
++ BFD_ASSERT(s != NULL);
++
++ h->root.u.def.section = s;
++ h->root.u.def.value = s->size;
++ h->plt.offset = s->size;
++ s->size += AVR32_FUNCTION_STUB_SIZE;
++
++ return TRUE;
++ }
++ }
++ else if (h->type == STT_FUNC)
++ {
++ /* This will set the entry for this symbol in the GOT to 0, and
++ the dynamic linker will take care of this. */
++ h->root.u.def.value = 0;
++ return TRUE;
++ }
++
++ /* If this is a weak symbol, and there is a real definition, the
++ processor independent code will have arranged for us to see the
++ real definition first, and we can just use the same value. */
++ if (h->u.weakdef != NULL)
++ {
++ BFD_ASSERT(h->u.weakdef->root.type == bfd_link_hash_defined
++ || h->u.weakdef->root.type == bfd_link_hash_defweak);
++ h->root.u.def.section = h->u.weakdef->root.u.def.section;
++ h->root.u.def.value = h->u.weakdef->root.u.def.value;
++ return TRUE;
++ }
++
++ /* This is a reference to a symbol defined by a dynamic object which
++ is not a function. */
++
++ return TRUE;
++}
++
++
++/* Garbage-collection of unused sections */
++
++static asection *
++avr32_elf_gc_mark_hook(asection *sec,
++ struct bfd_link_info *info ATTRIBUTE_UNUSED,
++ Elf_Internal_Rela *rel,
++ struct elf_link_hash_entry *h,
++ Elf_Internal_Sym *sym)
++{
++ if (h)
++ {
++ switch (ELF32_R_TYPE(rel->r_info))
++ {
++ /* TODO: VTINHERIT/VTENTRY */
++ default:
++ switch (h->root.type)
++ {
++ case bfd_link_hash_defined:
++ case bfd_link_hash_defweak:
++ return h->root.u.def.section;
++
++ case bfd_link_hash_common:
++ return h->root.u.c.p->section;
++
++ default:
++ break;
++ }
++ }
++ }
++ else
++ return bfd_section_from_elf_index(sec->owner, sym->st_shndx);
++
++ return NULL;
++}
++
++/* Update the GOT entry reference counts for the section being removed. */
++static bfd_boolean
++avr32_elf_gc_sweep_hook(bfd *abfd,
++ struct bfd_link_info *info ATTRIBUTE_UNUSED,
++ asection *sec,
++ const Elf_Internal_Rela *relocs)
++{
++ Elf_Internal_Shdr *symtab_hdr;
++ struct elf_avr32_link_hash_entry **sym_hashes;
++ struct got_entry **local_got_ents;
++ const Elf_Internal_Rela *rel, *relend;
++
++ if (!(sec->flags & SEC_ALLOC))
++ return TRUE;
++
++ symtab_hdr = &elf_tdata(abfd)->symtab_hdr;
++ sym_hashes = (struct elf_avr32_link_hash_entry **)elf_sym_hashes(abfd);
++ local_got_ents = elf_local_got_ents(abfd);
++
++ relend = relocs + sec->reloc_count;
++ for (rel = relocs; rel < relend; rel++)
++ {
++ unsigned long r_symndx;
++ unsigned int r_type;
++ struct elf_avr32_link_hash_entry *h = NULL;
++
++ r_symndx = ELF32_R_SYM(rel->r_info);
++ if (r_symndx >= symtab_hdr->sh_info)
++ {
++ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
++ while (h->root.root.type == bfd_link_hash_indirect
++ || h->root.root.type == bfd_link_hash_warning)
++ h = (struct elf_avr32_link_hash_entry *)h->root.root.u.i.link;
++ }
++
++ r_type = ELF32_R_TYPE(rel->r_info);
++
++ switch (r_type)
++ {
++ case R_AVR32_GOT32:
++ case R_AVR32_GOT16:
++ case R_AVR32_GOT8:
++ case R_AVR32_GOT21S:
++ case R_AVR32_GOT18SW:
++ case R_AVR32_GOT16S:
++ case R_AVR32_GOT7UW:
++ case R_AVR32_LDA_GOT:
++ case R_AVR32_GOTCALL:
++ if (h)
++ h->root.got.glist->refcount--;
++ else
++ local_got_ents[r_symndx]->refcount--;
++ break;
++
++ case R_AVR32_32:
++ if (info->shared || h)
++ {
++ if (h)
++ h->possibly_dynamic_relocs--;
++ else
++ avr32_elf_hash_table(info)->local_dynamic_relocs--;
++ }
++
++ default:
++ break;
++ }
++ }
++
++ return TRUE;
++}
++
++/* Sizing and refcounting of dynamic sections */
++
++static void
++insert_got_entry(struct elf_avr32_link_hash_table *htab, struct got_entry *got);
++static void
++unref_got_entry(struct elf_avr32_link_hash_table *htab, struct got_entry *got);
++static void
++ref_got_entry(struct elf_avr32_link_hash_table *htab, struct got_entry *got);
++static bfd_boolean
++assign_got_offsets(struct elf_avr32_link_hash_table *htab);
++static bfd_boolean
++allocate_dynrelocs(struct elf_link_hash_entry *h, void *_info);
++static bfd_boolean
++avr32_elf_size_dynamic_sections (bfd *output_bfd,
++ struct bfd_link_info *info);
++
++static void
++insert_got_entry(struct elf_avr32_link_hash_table *htab, struct got_entry *got)
++{
++ /* Any entries with got_refcount > htab->nr_got_holes end up in the
++ * last pigeonhole without any sorting. We expect the number of such
++ * entries to be small, so it is very unlikely to affect
++ * performance. */
++ int entry = got->refcount;