[toolchain/binutils]: add binutils 2.21
authorImre Kaloz <kaloz@openwrt.org>
Fri, 18 Feb 2011 09:52:19 +0000 (09:52 +0000)
committerImre Kaloz <kaloz@openwrt.org>
Fri, 18 Feb 2011 09:52:19 +0000 (09:52 +0000)
SVN-Revision: 25567

toolchain/binutils/Config.in
toolchain/binutils/Makefile
toolchain/binutils/patches/2.21/110-arm-eabi-conf.patch [new file with mode: 0644]
toolchain/binutils/patches/2.21/111-pr7093.elf32-arm.c.patch [new file with mode: 0644]
toolchain/binutils/patches/2.21/112-arm-uclibc-gas-needs-libm.patch [new file with mode: 0644]
toolchain/binutils/patches/2.21/120-sh-conf.patch [new file with mode: 0644]
toolchain/binutils/patches/2.21/200-mips_non_pic.patch [new file with mode: 0644]
toolchain/binutils/patches/2.21/300-001_ld_makefile_patch.patch [new file with mode: 0644]
toolchain/binutils/patches/2.21/300-012_check_ldrunpath_length.patch [new file with mode: 0644]
toolchain/binutils/patches/2.21/700-avr32.patch [new file with mode: 0644]

index be0605903307b309f85dc38d78868c7d75a63e10..207b2a05ac2c47bd1f5ad87a128296fa86cb639b 100644 (file)
@@ -14,6 +14,10 @@ choice
                 depends !ubicom32
                 bool "binutils 2.20.1"
 
+        config BINUTILS_VERSION_2_21
+                depends !ubicom32
+                bool "binutils 2.21"
+
        config BINUTILS_VERSION_CS
                depends !avr32
                depends !ubicom32
@@ -34,6 +38,7 @@ config BINUTILS_VERSION
        prompt "Binutils Version" if (TOOLCHAINOPTS && NULL)
        default "2.19.1"          if BINUTILS_VERSION_2_19_1
        default "2.20.1"          if BINUTILS_VERSION_2_20_1
+       default "2.21"            if BINUTILS_VERSION_2_21
        default "2.19.1+cs"       if BINUTILS_VERSION_CS
        default "2.19.1"          if ubicom32
        default "2.20.1"
index 7a19d12c96da411082811077191db3e9fb49b409..f2ea4d09802d47f45d7b4c82ca3c7d98d8bcb262 100644 (file)
@@ -26,6 +26,9 @@ endif
 ifeq ($(PKG_VERSION),2.20.1)
   PKG_MD5SUM:=9cdfb9d6ec0578c166d3beae5e15c4e5
 endif
+ifeq ($(PKG_VERSION),2.21)
+  PKG_MD5SUM:=c84c5acc9d266f1a7044b51c85a823f5
+endif
 
 PATCH_DIR:=./patches/$(PKG_VERSION)
 
diff --git a/toolchain/binutils/patches/2.21/110-arm-eabi-conf.patch b/toolchain/binutils/patches/2.21/110-arm-eabi-conf.patch
new file mode 100644 (file)
index 0000000..7a3dc8d
--- /dev/null
@@ -0,0 +1,22 @@
+--- a/configure
++++ b/configure
+@@ -3180,7 +3180,7 @@ case "${target}" in
+     noconfigdirs="$noconfigdirs target-libffi target-qthreads"
+     libgloss_dir=arm
+     ;;
+-  arm*-*-linux-gnueabi)
++  arm*-*-linux-*gnueabi)
+     noconfigdirs="$noconfigdirs target-qthreads"
+     case ${with_newlib} in
+       no) noconfigdirs="$noconfigdirs target-newlib target-libgloss"
+--- a/configure.ac
++++ b/configure.ac
+@@ -652,7 +652,7 @@ case "${target}" in
+     noconfigdirs="$noconfigdirs target-libffi target-qthreads"
+     libgloss_dir=arm
+     ;;
+-  arm*-*-linux-gnueabi)
++  arm*-*-linux-*gnueabi)
+     noconfigdirs="$noconfigdirs target-qthreads"
+     case ${with_newlib} in
+       no) noconfigdirs="$noconfigdirs target-newlib target-libgloss"
diff --git a/toolchain/binutils/patches/2.21/111-pr7093.elf32-arm.c.patch b/toolchain/binutils/patches/2.21/111-pr7093.elf32-arm.c.patch
new file mode 100644 (file)
index 0000000..7d6cb7b
--- /dev/null
@@ -0,0 +1,13 @@
+--- a/bfd/elf32-arm.c
++++ b/bfd/elf32-arm.c
+@@ -5631,6 +5631,10 @@ bfd_elf32_arm_init_maps (bfd *abfd)
+   if (! is_arm_elf (abfd))
+     return;
++  /* PR 7093: Make sure that we are dealing with an arm elf binary.  */
++  if (! is_arm_elf (abfd))
++    return;
++
+   if ((abfd->flags & DYNAMIC) != 0)
+     return;
diff --git a/toolchain/binutils/patches/2.21/112-arm-uclibc-gas-needs-libm.patch b/toolchain/binutils/patches/2.21/112-arm-uclibc-gas-needs-libm.patch
new file mode 100644 (file)
index 0000000..6366392
--- /dev/null
@@ -0,0 +1,35 @@
+Source: Khem Raj <raj.khem@gmail.com>
+Disposition: submit upstream.
+
+Description:
+
+We do not need to have the libtool patch anymore for binutils after
+libtool has been updated upstream it include support for it. However
+for building gas natively on uclibc systems we have to link it with
+-lm so that it picks up missing symbols.
+
+/local/build_area/BUILD/arm_v5t_le_uclibc/binutils-2.17.50/objdir/libiberty/pic/libiberty.a(floatformat.o): In function `floatformat_from_double':
+floatformat.c:(.text+0x1ec): undefined reference to `frexp'
+floatformat.c:(.text+0x2f8): undefined reference to `ldexp'
+/local/build_area/BUILD/arm_v5t_le_uclibc/binutils-2.17.50/objdir/libiberty/pic/libiberty.a(floatformat.o): In function `floatformat_to_double':
+floatformat.c:(.text+0x38a): undefined reference to `ldexp'
+floatformat.c:(.text+0x3d2): undefined reference to `ldexp'
+floatformat.c:(.text+0x43e): undefined reference to `ldexp'                     floatformat.c:(.text+0x4e2): undefined reference to `ldexp'
+collect2: ld returned 1 exit status
+make[4]: *** [as-new] Error 1
+
+--- a/gas/configure.tgt
++++ b/gas/configure.tgt
+@@ -431,6 +431,12 @@ case ${generic_target} in
+   *-*-netware)                                fmt=elf em=netware ;;
+ esac
++case ${generic_target} in
++  arm-*-*uclibc*)
++    need_libm=yes
++    ;;
++esac
++
+ case ${cpu_type} in
+   alpha | arm | i386 | ia64 | microblaze | mips | ns32k | pdp11 | ppc | sparc | z80 | z8k)
+     bfd_gas=yes
diff --git a/toolchain/binutils/patches/2.21/120-sh-conf.patch b/toolchain/binutils/patches/2.21/120-sh-conf.patch
new file mode 100644 (file)
index 0000000..caef550
--- /dev/null
@@ -0,0 +1,40 @@
+--- a/configure
++++ b/configure
+@@ -3148,7 +3148,7 @@ case "${target}" in
+   am33_2.0-*-linux*)
+     noconfigdirs="$noconfigdirs ${libgcj} target-newlib target-libgloss"
+     ;;
+-  sh-*-linux*)
++  sh*-*-linux*)
+     noconfigdirs="$noconfigdirs ${libgcj} target-newlib target-libgloss"
+     ;;
+   sh*-*-pe|mips*-*-pe|*arm-wince-pe)
+@@ -3487,7 +3487,7 @@ case "${target}" in
+   romp-*-*)
+     noconfigdirs="$noconfigdirs bfd binutils ld gas opcodes target-libgloss ${libgcj}"
+     ;;
+-  sh-*-* | sh64-*-*)
++  sh*-*-* | sh64-*-*)
+     case "${host}" in
+       i[3456789]86-*-vsta) ;; # don't add gprof back in
+       i[3456789]86-*-go32*) ;; # don't add gprof back in
+--- a/configure.ac
++++ b/configure.ac
+@@ -620,7 +620,7 @@ case "${target}" in
+   am33_2.0-*-linux*)
+     noconfigdirs="$noconfigdirs ${libgcj} target-newlib target-libgloss"
+     ;;
+-  sh-*-linux*)
++  sh*-*-linux*)
+     noconfigdirs="$noconfigdirs ${libgcj} target-newlib target-libgloss"
+     ;;    
+   sh*-*-pe|mips*-*-pe|*arm-wince-pe)
+@@ -959,7 +959,7 @@ case "${target}" in
+   romp-*-*)
+     noconfigdirs="$noconfigdirs bfd binutils ld gas opcodes target-libgloss ${libgcj}"
+     ;;
+-  sh-*-* | sh64-*-*)
++  sh*-*-* | sh64-*-*)
+     case "${host}" in
+       i[[3456789]]86-*-vsta) ;; # don't add gprof back in
+       i[[3456789]]86-*-go32*) ;; # don't add gprof back in
diff --git a/toolchain/binutils/patches/2.21/200-mips_non_pic.patch b/toolchain/binutils/patches/2.21/200-mips_non_pic.patch
new file mode 100644 (file)
index 0000000..298f3cb
--- /dev/null
@@ -0,0 +1,209 @@
+--- a/bfd/elf32-mips.c
++++ b/bfd/elf32-mips.c
+@@ -1663,6 +1663,15 @@ static const struct ecoff_debug_swap mip
+ #define elf_backend_plt_readonly      1
+ #define elf_backend_plt_sym_val               _bfd_mips_elf_plt_sym_val
++/* Most MIPS ELF files do not contain a traditional PLT; only VxWorks
++   and non-PIC dynamic executables do.  These settings only affect
++   _bfd_elf_create_dynamic_sections, which is only called when we
++   do want a traditional PLT.  */
++#undef elf_backend_want_plt_sym
++#define elf_backend_want_plt_sym              1
++#undef elf_backend_plt_readonly
++#define elf_backend_plt_readonly              1
++
+ #define elf_backend_discard_info      _bfd_mips_elf_discard_info
+ #define elf_backend_ignore_discarded_relocs \
+                                       _bfd_mips_elf_ignore_discarded_relocs
+@@ -1686,6 +1695,8 @@ static const struct ecoff_debug_swap mip
+ #define bfd_elf32_bfd_print_private_bfd_data \
+                                       _bfd_mips_elf_print_private_bfd_data
++#define elf_backend_plt_sym_val               _bfd_mips_elf_plt_sym_val
++
+ /* Support for SGI-ish mips targets.  */
+ #define TARGET_LITTLE_SYM             bfd_elf32_littlemips_vec
+ #define TARGET_LITTLE_NAME            "elf32-littlemips"
+@@ -1789,6 +1800,7 @@ mips_vxworks_final_write_processing (bfd
+ #undef elf_backend_additional_program_headers
+ #undef elf_backend_modify_segment_map
+ #undef elf_backend_symbol_processing
++#undef elf_backend_plt_sym_val
+ /* NOTE: elf_backend_rela_normal is not defined for MIPS.  */
+ #include "elf32-target.h"
+--- a/bfd/elfxx-mips.c
++++ b/bfd/elfxx-mips.c
+@@ -713,6 +713,11 @@ static bfd *reldyn_sorting_bfd;
+ /* Nonzero if ABFD is using NewABI conventions.  */
+ #define NEWABI_P(abfd) (ABI_N32_P (abfd) || ABI_64_P (abfd))
++/* Nonzero if ABFD is a non-PIC object.  */
++#define NON_PIC_P(abfd) \
++  (((elf_elfheader (abfd)->e_flags & EF_MIPS_PIC) == 0) \
++   && ((elf_elfheader (abfd)->e_flags & EF_MIPS_CPIC) == EF_MIPS_CPIC))
++
+ /* The IRIX compatibility level we are striving for.  */
+ #define IRIX_COMPAT(abfd) \
+   (get_elf_backend_data (abfd)->elf_backend_mips_irix_compat (abfd))
+@@ -725,6 +730,9 @@ static bfd *reldyn_sorting_bfd;
+ #define MIPS_ELF_OPTIONS_SECTION_NAME(abfd) \
+   (NEWABI_P (abfd) ? ".MIPS.options" : ".options")
++/* The name of the section holding non-PIC to PIC call stubs.  */
++#define NON_PIC_TO_PIC_STUB_SECTION_NAME ".MIPS.pic_stubs"
++
+ /* True if NAME is the recognized name of any SHT_MIPS_OPTIONS section.
+    Some IRIX system files do not use MIPS_ELF_OPTIONS_SECTION_NAME.  */
+ #define MIPS_ELF_OPTIONS_SECTION_NAME_P(NAME) \
+@@ -7686,7 +7694,9 @@ _bfd_mips_elf_check_relocs (bfd *abfd, s
+             /* We need a stub, not a plt entry for the undefined
+                function.  But we record it as if it needs plt.  See
+-               _bfd_elf_adjust_dynamic_symbol.  */
++               _bfd_elf_adjust_dynamic_symbol.  Note that these relocations
++               are always used for PIC calls, even when using the new
++               non-PIC ABI.  */
+             h->needs_plt = 1;
+             h->type = STT_FUNC;
+           }
+@@ -7793,6 +7803,8 @@ _bfd_mips_elf_check_relocs (bfd *abfd, s
+       case R_MIPS_32:
+       case R_MIPS_REL32:
+       case R_MIPS_64:
++        if (h != NULL)
++          h->non_got_ref = TRUE;
+         /* In VxWorks executables, references to external symbols
+            are handled using copy relocs or PLT stubs, so there's
+            no need to add a .rela.dyn entry for this relocation.  */
+@@ -7848,11 +7860,21 @@ _bfd_mips_elf_check_relocs (bfd *abfd, s
+       case R_MIPS_GPREL16:
+       case R_MIPS_LITERAL:
+       case R_MIPS_GPREL32:
++        if (h != NULL
++            && (r_type == R_MIPS_GPREL16 || r_type == R_MIPS_GPREL32))
++          h->non_got_ref = TRUE;
++
+         if (SGI_COMPAT (abfd))
+           mips_elf_hash_table (info)->compact_rel_size +=
+             sizeof (Elf32_External_crinfo);
+         break;
++      case R_MIPS_HI16:
++      case R_MIPS_LO16:
++        if (h != NULL && strcmp (h->root.root.string, "_gp_disp") != 0)
++          h->non_got_ref = TRUE;
++        break;
++
+         /* This relocation describes the C++ object vtable hierarchy.
+            Reconstruct it for later use during GC.  */
+       case R_MIPS_GNU_VTINHERIT:
+@@ -7875,20 +7897,20 @@ _bfd_mips_elf_check_relocs (bfd *abfd, s
+       /* We must not create a stub for a symbol that has relocations
+        related to taking the function's address.  This doesn't apply to
+-       VxWorks, where CALL relocs refer to a .got.plt entry instead of
+-       a normal .got entry.  */
++       VxWorks or the non-PIC ABI, where CALL relocs refer to a
++       .got.plt entry instead of a normal .got entry.  */
+       if (!htab->is_vxworks && h != NULL)
+       switch (r_type)
+         {
+-        default:
+-          ((struct mips_elf_link_hash_entry *) h)->no_fn_stub = TRUE;
+-          break;
+         case R_MIPS16_CALL16:
+         case R_MIPS_CALL16:
+         case R_MIPS_CALL_HI16:
+         case R_MIPS_CALL_LO16:
+         case R_MIPS_JALR:
+           break;
++        default:
++          ((struct mips_elf_link_hash_entry *) h)->no_fn_stub = TRUE;
++          break;
+         }
+       /* See if this reloc would need to refer to a MIPS16 hard-float stub,
+@@ -12601,7 +12623,9 @@ _bfd_mips_elf_merge_private_bfd_data (bf
+         break;
+       }
+     }
+-  if (null_input_bfd)
++  /* Dynamic objects normally have no sections, and do not reach
++     here - but they might if used as DYNOBJ.  */
++  if (null_input_bfd || (ibfd->flags & DYNAMIC) != 0)
+     return TRUE;
+   ok = TRUE;
+--- a/bfd/elfxx-mips.h
++++ b/bfd/elfxx-mips.h
+@@ -64,6 +64,9 @@ extern bfd_boolean _bfd_mips_elf_finish_
+ extern bfd_boolean _bfd_mips_vxworks_finish_dynamic_symbol
+   (bfd *, struct bfd_link_info *, struct elf_link_hash_entry *,
+    Elf_Internal_Sym *);
++extern bfd_boolean _bfd_mips_nonpic_finish_dynamic_symbol
++  (bfd *, struct bfd_link_info *, struct elf_link_hash_entry *,
++   Elf_Internal_Sym *);
+ extern bfd_boolean _bfd_mips_elf_finish_dynamic_sections
+   (bfd *, struct bfd_link_info *);
+ extern void _bfd_mips_elf_final_write_processing
+@@ -158,6 +161,15 @@ gprel16_reloc_p (unsigned int r_type)
+   return r_type == R_MIPS_GPREL16 || r_type == R_MIPS16_GPREL;
+ }
++extern bfd_vma _bfd_mips_elf_plt_sym_val
++  (bfd_vma, const asection *, const arelent *);
++extern void _bfd_mips_elf_begin_write_processing
++  (bfd *abfd, struct bfd_link_info *link_info);
++extern bfd_boolean bfd_mips_elf_maybe_create_non_pic_to_pic_stubs_section
++  (struct bfd_link_info *);
++extern void _bfd_mips_post_process_headers
++  (bfd *abfd, struct bfd_link_info *link_info);
++
+ #define elf_backend_common_definition   _bfd_mips_elf_common_definition
+ #define elf_backend_name_local_section_symbols \
+   _bfd_mips_elf_name_local_section_symbols
+--- a/gas/config/tc-mips.c
++++ b/gas/config/tc-mips.c
+@@ -1900,6 +1900,12 @@ md_begin (void)
+       as_bad (_("-G may not be used in position-independent code"));
+       g_switch_value = 0;
+     }
++  else if (mips_abicalls)
++    {
++      if (g_switch_seen && g_switch_value != 0)
++      as_bad (_("-G may not be used with abicalls"));
++      g_switch_value = 0;
++    }
+   if (! bfd_set_arch_mach (stdoutput, bfd_arch_mips, file_mips_arch))
+     as_warn (_("Could not set architecture and machine"));
+@@ -11270,6 +11276,7 @@ enum options
+     OPTION_PDR,
+     OPTION_NO_PDR,
+     OPTION_MVXWORKS_PIC,
++    OPTION_NON_PIC_ABICALLS,
+ #endif /* OBJ_ELF */
+     OPTION_END_OF_ENUM    
+   };
+@@ -11377,6 +11384,7 @@ struct option md_longopts[] =
+   {"mpdr", no_argument, NULL, OPTION_PDR},
+   {"mno-pdr", no_argument, NULL, OPTION_NO_PDR},
+   {"mvxworks-pic", no_argument, NULL, OPTION_MVXWORKS_PIC},
++  {"mnon-pic-abicalls", no_argument, NULL, OPTION_NON_PIC_ABICALLS},
+ #endif /* OBJ_ELF */
+   {NULL, no_argument, NULL, 0}
+@@ -11825,6 +11833,11 @@ md_parse_option (int c, char *arg)
+     case OPTION_MVXWORKS_PIC:
+       mips_pic = VXWORKS_PIC;
+       break;
++
++    case OPTION_NON_PIC_ABICALLS:
++      mips_pic = NO_PIC;
++      mips_abicalls = TRUE;
++      break;
+ #endif /* OBJ_ELF */
+     default:
diff --git a/toolchain/binutils/patches/2.21/300-001_ld_makefile_patch.patch b/toolchain/binutils/patches/2.21/300-001_ld_makefile_patch.patch
new file mode 100644 (file)
index 0000000..2759872
--- /dev/null
@@ -0,0 +1,22 @@
+--- a/ld/Makefile.am
++++ b/ld/Makefile.am
+@@ -37,7 +37,7 @@ endif
+ # We put the scripts in the directory $(scriptdir)/ldscripts.
+ # We can't put the scripts in $(datadir) because the SEARCH_DIR
+ # directives need to be different for native and cross linkers.
+-scriptdir = $(tooldir)/lib
++scriptdir = $(libdir)
+ EMUL = @EMUL@
+ EMULATION_OFILES = @EMULATION_OFILES@
+--- a/ld/Makefile.in
++++ b/ld/Makefile.in
+@@ -360,7 +360,7 @@ AM_CFLAGS = $(WARN_CFLAGS)
+ # We put the scripts in the directory $(scriptdir)/ldscripts.
+ # We can't put the scripts in $(datadir) because the SEARCH_DIR
+ # directives need to be different for native and cross linkers.
+-scriptdir = $(tooldir)/lib
++scriptdir = $(libdir)
+ BASEDIR = $(srcdir)/..
+ BFDDIR = $(BASEDIR)/bfd
+ INCDIR = $(BASEDIR)/include
diff --git a/toolchain/binutils/patches/2.21/300-012_check_ldrunpath_length.patch b/toolchain/binutils/patches/2.21/300-012_check_ldrunpath_length.patch
new file mode 100644 (file)
index 0000000..3746f03
--- /dev/null
@@ -0,0 +1,20 @@
+--- a/ld/emultempl/elf32.em
++++ b/ld/emultempl/elf32.em
+@@ -1270,6 +1270,8 @@ fragment <<EOF
+             && command_line.rpath == NULL)
+           {
+             lib_path = (const char *) getenv ("LD_RUN_PATH");
++            if ((lib_path) && (strlen (lib_path) == 0))
++              lib_path = NULL;
+             if (gld${EMULATION_NAME}_search_needed (lib_path, &n,
+                                                     force))
+               break;
+@@ -1497,6 +1499,8 @@ gld${EMULATION_NAME}_before_allocation (
+   rpath = command_line.rpath;
+   if (rpath == NULL)
+     rpath = (const char *) getenv ("LD_RUN_PATH");
++  if ((rpath) && (strlen (rpath) == 0))
++      rpath = NULL;
+   for (abfd = link_info.input_bfds; abfd; abfd = abfd->link_next)
+     if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
diff --git a/toolchain/binutils/patches/2.21/700-avr32.patch b/toolchain/binutils/patches/2.21/700-avr32.patch
new file mode 100644 (file)
index 0000000..c7e8ea3
--- /dev/null
@@ -0,0 +1,30759 @@
+--- a/bfd/archures.c
++++ b/bfd/archures.c
+@@ -373,6 +373,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). *}
+@@ -469,6 +475,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;
+@@ -546,6 +553,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/bfd-in2.h
++++ b/bfd/bfd-in2.h
+@@ -2053,6 +2053,12 @@ enum bfd_architecture
+ #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). */
+@@ -3989,6 +3995,88 @@ instructions  */
+   BFD_RELOC_RX_ABS16UL,
+   BFD_RELOC_RX_RELAX,
++/* Difference between two labels: L2 - L1. The value of L1 is encoded
++as sym + addend, while the initial difference after assembly is
++inserted into the object file by the assembler.  */
++  BFD_RELOC_AVR32_DIFF32,
++  BFD_RELOC_AVR32_DIFF16,
++  BFD_RELOC_AVR32_DIFF8,
++
++/* Reference to a symbol through the Global Offset Table. The linker
++will allocate an entry for symbol in the GOT and insert the offset
++of this entry as the relocation value.  */
++  BFD_RELOC_AVR32_GOT32,
++  BFD_RELOC_AVR32_GOT16,
++  BFD_RELOC_AVR32_GOT8,
++
++/* Normal (non-pc-relative) code relocations. Alignment and signedness
++is indicated by the suffixes. S means signed, U means unsigned. W
++means word-aligned, H means halfword-aligned, neither means
++byte-aligned (no alignment.) SUB5 is the same relocation as 16S.  */
++  BFD_RELOC_AVR32_21S,
++  BFD_RELOC_AVR32_16U,
++  BFD_RELOC_AVR32_16S,
++  BFD_RELOC_AVR32_SUB5,
++  BFD_RELOC_AVR32_8S_EXT,
++  BFD_RELOC_AVR32_8S,
++  BFD_RELOC_AVR32_15S,
++
++/* PC-relative relocations are signed if neither 'U' nor 'S' is
++specified. However, we explicitly tack on a 'B' to indicate no
++alignment, to avoid confusion with data relocs. All of these resolve
++to sym + addend - offset, except the one with 'N' (negated) suffix.
++This particular one resolves to offset - sym - addend.  */
++  BFD_RELOC_AVR32_22H_PCREL,
++  BFD_RELOC_AVR32_18W_PCREL,
++  BFD_RELOC_AVR32_16B_PCREL,
++  BFD_RELOC_AVR32_16N_PCREL,
++  BFD_RELOC_AVR32_14UW_PCREL,
++  BFD_RELOC_AVR32_11H_PCREL,
++  BFD_RELOC_AVR32_10UW_PCREL,
++  BFD_RELOC_AVR32_9H_PCREL,
++  BFD_RELOC_AVR32_9UW_PCREL,
++
++/* Subtract the link-time address of the GOT from (symbol + addend)
++and insert the result.  */
++  BFD_RELOC_AVR32_GOTPC,
++
++/* Reference to a symbol through the GOT. The linker will allocate an
++entry for symbol in the GOT and insert the offset of this entry as
++the relocation value. addend must be zero. As usual, 'S' means
++signed, 'W' means word-aligned, etc.  */
++  BFD_RELOC_AVR32_GOTCALL,
++  BFD_RELOC_AVR32_LDA_GOT,
++  BFD_RELOC_AVR32_GOT21S,
++  BFD_RELOC_AVR32_GOT18SW,
++  BFD_RELOC_AVR32_GOT16S,
++
++/* 32-bit constant pool entry. I don't think 8- and 16-bit entries make
++a whole lot of sense.  */
++  BFD_RELOC_AVR32_32_CPENT,
++
++/* Constant pool references. Some of these relocations are signed,
++others are unsigned. It doesn't really matter, since the constant
++pool always comes after the code that references it.  */
++  BFD_RELOC_AVR32_CPCALL,
++  BFD_RELOC_AVR32_16_CP,
++  BFD_RELOC_AVR32_9W_CP,
++
++/* sym must be the absolute symbol. The addend specifies the alignment
++order, e.g. if addend is 2, the linker must add padding so that the
++next address is aligned to a 4-byte boundary.  */
++  BFD_RELOC_AVR32_ALIGN,
++
++/* Code relocations that will never make it to the output file.  */
++  BFD_RELOC_AVR32_14UW,
++  BFD_RELOC_AVR32_10UW,
++  BFD_RELOC_AVR32_10SW,
++  BFD_RELOC_AVR32_STHH_W,
++  BFD_RELOC_AVR32_7UW,
++  BFD_RELOC_AVR32_6S,
++  BFD_RELOC_AVR32_6UW,
++  BFD_RELOC_AVR32_4UH,
++  BFD_RELOC_AVR32_3U,
++
+ /* Direct 12 bit.  */
+   BFD_RELOC_390_12,
+--- a/bfd/config.bfd
++++ b/bfd/config.bfd
+@@ -346,6 +346,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
++++ b/bfd/configure
+@@ -15040,6 +15040,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" ;;
+--- 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;
++
++  if (entry > htab->nr_got_holes)
++    entry = htab->nr_got_holes;
++
++  got->pprev = &htab->got_hole[entry];
++  got->next = htab->got_hole[entry];
++
++  if (got->next)
++    got->next->pprev = &got->next;
++
++  htab->got_hole[entry] = got;
++}
++
++/* Decrement the refcount of a GOT entry and update its position in
++   the pigeonhole array.  */
++static void
++unref_got_entry(struct elf_avr32_link_hash_table *htab, struct got_entry *got)
++{
++  BFD_ASSERT(got->refcount > 0);
++
++  if (got->next)
++    got->next->pprev = got->pprev;
++
++  *(got->pprev) = got->next;
++  got->refcount--;
++  insert_got_entry(htab, got);
++}
++
++static void
++ref_got_entry(struct elf_avr32_link_hash_table *htab, struct got_entry *got)
++{
++  if (got->next)
++    got->next->pprev = got->pprev;
++
++  *(got->pprev) = got->next;
++  got->refcount++;
++  insert_got_entry(htab, got);
++
++  BFD_ASSERT(got->refcount > 0);
++}
++
++/* Assign offsets to all GOT entries we intend to keep.  The entries
++   that are referenced most often are placed at low offsets so that we
++   can use compact instructions as much as possible.
++
++   Returns TRUE if any offsets or the total size of the GOT changed.  */
++
++static bfd_boolean
++assign_got_offsets(struct elf_avr32_link_hash_table *htab)
++{
++  struct got_entry *got;
++  bfd_size_type got_size = 0;
++  bfd_boolean changed = FALSE;
++  bfd_signed_vma offset;
++  int i;
++
++  /* The GOT header provides the address of the DYNAMIC segment, so
++     we need that even if the GOT is otherwise empty.  */
++  if (htab->root.dynamic_sections_created)
++    got_size = AVR32_GOT_HEADER_SIZE;
++
++  for (i = htab->nr_got_holes; i > 0; i--)
++    {
++      got = htab->got_hole[i];
++      while (got)
++      {
++        if (got->refcount > 0)
++          {
++            offset = got_size;
++            if (got->offset != offset)
++              {
++                RDBG("GOT offset changed: %ld -> %ld\n",
++                     got->offset, offset);
++                changed = TRUE;
++              }
++            got->offset = offset;
++            got_size += 4;
++          }
++        got = got->next;
++      }
++    }
++
++  if (htab->sgot->size != got_size)
++    {
++      RDBG("GOT size changed: %lu -> %lu\n", htab->sgot->size,
++         got_size);
++      changed = TRUE;
++    }
++  htab->sgot->size = got_size;
++
++  RDBG("assign_got_offsets: total size %lu (%s)\n",
++       got_size, changed ? "changed" : "no change");
++
++  return changed;
++}
++
++static bfd_boolean
++allocate_dynrelocs(struct elf_link_hash_entry *h, void *_info)
++{
++  struct bfd_link_info *info = _info;
++  struct elf_avr32_link_hash_table *htab;
++  struct elf_avr32_link_hash_entry *havr;
++  struct got_entry *got;
++
++  pr_debug("  (4b) allocate_dynrelocs: %s\n", h->root.root.string);
++
++  if (h->root.type == bfd_link_hash_indirect)
++    return TRUE;
++
++  if (h->root.type == bfd_link_hash_warning)
++    /* When warning symbols are created, they **replace** the "real"
++       entry in the hash table, thus we never get to see the real
++       symbol in a hash traversal.  So look at it now.  */
++    h = (struct elf_link_hash_entry *) h->root.u.i.link;
++
++  htab = avr32_elf_hash_table(info);
++  havr = (struct elf_avr32_link_hash_entry *)h;
++
++  got = h->got.glist;
++
++  /* If got is NULL, the symbol is never referenced through the GOT */
++  if (got && got->refcount > 0)
++    {
++      insert_got_entry(htab, got);
++
++      /* Shared libraries need relocs for all GOT entries unless the
++       symbol is forced local or -Bsymbolic is used.  Others need
++       relocs for everything that is not guaranteed to be defined in
++       a regular object.  */
++      if ((info->shared
++         && !info->symbolic
++         && h->dynindx != -1)
++        || (htab->root.dynamic_sections_created
++            && h->def_dynamic
++            && !h->def_regular))
++      htab->srelgot->size += sizeof(Elf32_External_Rela);
++    }
++
++  if (havr->possibly_dynamic_relocs
++      && (info->shared
++        || (elf_hash_table(info)->dynamic_sections_created
++            && h->def_dynamic
++            && !h->def_regular)))
++    {
++      pr_debug("Allocating %d dynamic reloc against symbol %s...\n",
++             havr->possibly_dynamic_relocs, h->root.root.string);
++      htab->srelgot->size += (havr->possibly_dynamic_relocs
++                            * sizeof(Elf32_External_Rela));
++    }
++
++  return TRUE;
++}
++
++/* (4) Calculate the sizes of the linker-generated sections and
++   allocate memory for them.  */
++
++static bfd_boolean
++avr32_elf_size_dynamic_sections (bfd *output_bfd,
++                               struct bfd_link_info *info)
++{
++  struct elf_avr32_link_hash_table *htab;
++  bfd *dynobj;
++  asection *s;
++  bfd *ibfd;
++  bfd_boolean relocs;
++
++  pr_debug("(4) size dynamic sections\n");
++
++  htab = avr32_elf_hash_table(info);
++  dynobj = htab->root.dynobj;
++  BFD_ASSERT(dynobj != NULL);
++
++  if (htab->root.dynamic_sections_created)
++    {
++      /* Initialize the contents of the .interp section to the name of
++       the dynamic loader */
++      if (info->executable)
++      {
++        s = bfd_get_section_by_name(dynobj, ".interp");
++        BFD_ASSERT(s != NULL);
++        s->size = sizeof(ELF_DYNAMIC_INTERPRETER);
++        s->contents = (unsigned char *)ELF_DYNAMIC_INTERPRETER;
++      }
++    }
++
++  if (htab->nr_got_holes > 0)
++    {
++      /* Allocate holes for the pigeonhole sort algorithm */
++      pr_debug("Highest GOT refcount: %d\n", htab->nr_got_holes);
++
++      /* Limit the memory usage by clipping the number of pigeonholes
++       * at a predefined maximum. All entries with a higher refcount
++       * will end up in the last pigeonhole.  */
++    if (htab->nr_got_holes >= MAX_NR_GOT_HOLES)
++    {
++        htab->nr_got_holes = MAX_NR_GOT_HOLES - 1;
++
++        pr_debug("Limiting maximum number of GOT pigeonholes to %u\n",
++                    htab->nr_got_holes);
++    }
++      htab->got_hole = bfd_zalloc(output_bfd,
++                                sizeof(struct got_entry *)
++                                * (htab->nr_got_holes + 1));
++      if (!htab->got_hole)
++      return FALSE;
++
++      /* Set up .got offsets for local syms.  */
++      for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
++      {
++        struct got_entry **local_got;
++        struct got_entry **end_local_got;
++        Elf_Internal_Shdr *symtab_hdr;
++        bfd_size_type locsymcount;
++
++        pr_debug("  (4a) processing file %s...\n", ibfd->filename);
++
++        BFD_ASSERT(bfd_get_flavour(ibfd) == bfd_target_elf_flavour);
++
++        local_got = elf_local_got_ents(ibfd);
++        if (!local_got)
++          continue;
++
++        symtab_hdr = &elf_tdata(ibfd)->symtab_hdr;
++        locsymcount = symtab_hdr->sh_info;
++        end_local_got = local_got + locsymcount;
++
++        for (; local_got < end_local_got; ++local_got)
++          insert_got_entry(htab, *local_got);
++      }
++    }
++
++  /* Allocate global sym .got entries and space for global sym
++     dynamic relocs */
++  elf_link_hash_traverse(&htab->root, allocate_dynrelocs, info);
++
++  /* Now that we have sorted the GOT entries, we are ready to
++     assign offsets and determine the initial size of the GOT. */
++  if (htab->sgot)
++    assign_got_offsets(htab);
++
++  /* Allocate space for local sym dynamic relocs */
++  BFD_ASSERT(htab->local_dynamic_relocs == 0 || info->shared);
++  if (htab->local_dynamic_relocs)
++    htab->srelgot->size += (htab->local_dynamic_relocs
++                          * sizeof(Elf32_External_Rela));
++
++  /* We now have determined the sizes of the various dynamic
++     sections. Allocate memory for them. */
++  relocs = FALSE;
++  for (s = dynobj->sections; s; s = s->next)
++    {
++      if ((s->flags & SEC_LINKER_CREATED) == 0)
++      continue;
++
++      if (s == htab->sgot
++        || s == htab->sstub)
++      {
++        /* Strip this section if we don't need it */
++      }
++      else if (strncmp (bfd_get_section_name(dynobj, s), ".rela", 5) == 0)
++      {
++        if (s->size != 0)
++          relocs = TRUE;
++
++        s->reloc_count = 0;
++      }
++      else
++      {
++        /* It's not one of our sections */
++        continue;
++      }
++
++      if (s->size == 0)
++      {
++        /* Strip unneeded sections */
++        pr_debug("Stripping section %s from output...\n", s->name);
++        /* deleted function in 2.17
++      _bfd_strip_section_from_output(info, s);
++      */
++        continue;
++      }
++
++      s->contents = bfd_zalloc(dynobj, s->size);
++      if (s->contents == NULL)
++      return FALSE;
++    }
++
++  if (htab->root.dynamic_sections_created)
++    {
++      /* Add some entries to the .dynamic section.  We fill in the
++       values later, in sh_elf_finish_dynamic_sections, but we
++       must add the entries now so that we get the correct size for
++       the .dynamic section.  The DT_DEBUG entry is filled in by the
++       dynamic linker and used by the debugger.  */
++#define add_dynamic_entry(TAG, VAL) _bfd_elf_add_dynamic_entry(info, TAG, VAL)
++
++      if (!add_dynamic_entry(DT_PLTGOT, 0))
++      return FALSE;
++      if (!add_dynamic_entry(DT_AVR32_GOTSZ, 0))
++      return FALSE;
++
++      if (info->executable)
++      {
++        if (!add_dynamic_entry(DT_DEBUG, 0))
++          return FALSE;
++      }
++      if (relocs)
++      {
++        if (!add_dynamic_entry(DT_RELA, 0)
++            || !add_dynamic_entry(DT_RELASZ, 0)
++            || !add_dynamic_entry(DT_RELAENT,
++                                  sizeof(Elf32_External_Rela)))
++          return FALSE;
++      }
++    }
++#undef add_dynamic_entry
++
++  return TRUE;
++}
++
++
++/* Access to internal relocations, section contents and symbols.
++   (stolen from the xtensa port)  */
++
++static Elf_Internal_Rela *
++retrieve_internal_relocs (bfd *abfd, asection *sec, bfd_boolean keep_memory);
++static void
++pin_internal_relocs (asection *sec, Elf_Internal_Rela *internal_relocs);
++static void
++release_internal_relocs (asection *sec, Elf_Internal_Rela *internal_relocs);
++static bfd_byte *
++retrieve_contents (bfd *abfd, asection *sec, bfd_boolean keep_memory);
++/*
++static void
++pin_contents (asection *sec, bfd_byte *contents);
++*/
++static void
++release_contents (asection *sec, bfd_byte *contents);
++static Elf_Internal_Sym *
++retrieve_local_syms (bfd *input_bfd, bfd_boolean keep_memory);
++/*
++static void
++pin_local_syms (bfd *input_bfd, Elf_Internal_Sym *isymbuf);
++*/
++static void
++release_local_syms (bfd *input_bfd, Elf_Internal_Sym *isymbuf);
++
++/* During relaxation, we need to modify relocations, section contents,
++   and symbol definitions, and we need to keep the original values from
++   being reloaded from the input files, i.e., we need to "pin" the
++   modified values in memory.  We also want to continue to observe the
++   setting of the "keep-memory" flag.  The following functions wrap the
++   standard BFD functions to take care of this for us.  */
++
++static Elf_Internal_Rela *
++retrieve_internal_relocs (bfd *abfd, asection *sec, bfd_boolean keep_memory)
++{
++  /* _bfd_elf_link_read_relocs knows about caching, so no need for us
++     to be clever here.  */
++  return _bfd_elf_link_read_relocs(abfd, sec, NULL, NULL, keep_memory);
++}
++
++static void
++pin_internal_relocs (asection *sec, Elf_Internal_Rela *internal_relocs)
++{
++  elf_section_data (sec)->relocs = internal_relocs;
++}
++
++static void
++release_internal_relocs (asection *sec, Elf_Internal_Rela *internal_relocs)
++{
++  if (internal_relocs
++      && elf_section_data (sec)->relocs != internal_relocs)
++    free (internal_relocs);
++}
++
++static bfd_byte *
++retrieve_contents (bfd *abfd, asection *sec, bfd_boolean keep_memory)
++{
++  bfd_byte *contents;
++  bfd_size_type sec_size;
++
++  sec_size = bfd_get_section_limit (abfd, sec);
++  contents = elf_section_data (sec)->this_hdr.contents;
++
++  if (contents == NULL && sec_size != 0)
++    {
++      if (!bfd_malloc_and_get_section (abfd, sec, &contents))
++      {
++        if (contents)
++          free (contents);
++        return NULL;
++      }
++      if (keep_memory)
++      elf_section_data (sec)->this_hdr.contents = contents;
++    }
++  return contents;
++}
++
++/*
++static void
++pin_contents (asection *sec, bfd_byte *contents)
++{
++  elf_section_data (sec)->this_hdr.contents = contents;
++}
++*/
++static void
++release_contents (asection *sec, bfd_byte *contents)
++{
++  if (contents && elf_section_data (sec)->this_hdr.contents != contents)
++    free (contents);
++}
++
++static Elf_Internal_Sym *
++retrieve_local_syms (bfd *input_bfd, bfd_boolean keep_memory)
++{
++  Elf_Internal_Shdr *symtab_hdr;
++  Elf_Internal_Sym *isymbuf;
++  size_t locsymcount;
++
++  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
++  locsymcount = symtab_hdr->sh_info;
++
++  isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
++  if (isymbuf == NULL && locsymcount != 0)
++    {
++      isymbuf = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, locsymcount, 0,
++                                    NULL, NULL, NULL);
++      if (isymbuf && keep_memory)
++      symtab_hdr->contents = (unsigned char *) isymbuf;
++    }
++
++  return isymbuf;
++}
++
++/*
++static void
++pin_local_syms (bfd *input_bfd, Elf_Internal_Sym *isymbuf)
++{
++  elf_tdata (input_bfd)->symtab_hdr.contents = (unsigned char *)isymbuf;
++}
++
++*/
++static void
++release_local_syms (bfd *input_bfd, Elf_Internal_Sym *isymbuf)
++{
++  if (isymbuf && (elf_tdata (input_bfd)->symtab_hdr.contents
++                != (unsigned char *)isymbuf))
++    free (isymbuf);
++}
++
++\f/* Data structures used during relaxation. */
++
++enum relax_state_id {
++  RS_ERROR = -1,
++  RS_NONE = 0,
++  RS_ALIGN,
++  RS_CPENT,
++  RS_PIC_CALL,
++  RS_PIC_MCALL,
++  RS_PIC_RCALL2,
++  RS_PIC_RCALL1,
++  RS_PIC_LDA,
++  RS_PIC_LDW4,
++  RS_PIC_LDW3,
++  RS_PIC_SUB5,
++  RS_NOPIC_MCALL,
++  RS_NOPIC_RCALL2,
++  RS_NOPIC_RCALL1,
++  RS_NOPIC_LDW4,
++  RS_NOPIC_LDDPC,
++  RS_NOPIC_SUB5,
++  RS_NOPIC_MOV2,
++  RS_NOPIC_MOV1,
++  RS_RCALL2,
++  RS_RCALL1,
++  RS_BRC2,
++  RS_BRC1,
++  RS_BRAL,
++  RS_RJMP,
++  RS_MAX,
++};
++
++enum reference_type {
++  REF_ABSOLUTE,
++  REF_PCREL,
++  REF_CPOOL,
++  REF_GOT,
++};
++
++struct relax_state
++{
++  const char *name;
++  enum relax_state_id id;
++  enum relax_state_id direct;
++  enum relax_state_id next;
++  enum relax_state_id prev;
++
++  enum reference_type reftype;
++
++  unsigned int r_type;
++
++  bfd_vma opcode;
++  bfd_vma opcode_mask;
++
++  bfd_signed_vma range_min;
++  bfd_signed_vma range_max;
++
++  bfd_size_type size;
++};
++
++/*
++ * This is for relocs that
++ *   a) has an addend or is of type R_AVR32_DIFF32, and
++ *   b) references a different section than it's in, and
++ *   c) references a section that is relaxable
++ *
++ * as well as relocs that references the constant pool, in which case
++ * the add_frag member points to the frag containing the constant pool
++ * entry.
++ *
++ * Such relocs must be fixed up whenever we delete any code. Sections
++ * that don't have any relocs with all of the above properties don't
++ * have any additional reloc data, but sections that do will have
++ * additional data for all its relocs.
++ */
++struct avr32_reloc_data
++{
++  struct fragment *add_frag;
++  struct fragment *sub_frag;
++};
++
++/*
++ * A 'fragment' is a relaxable entity, that is, code may be added or
++ * deleted at the end of a fragment. When this happens, all subsequent
++ * fragments in the list will have their offsets updated.
++ */
++struct fragment
++{
++  enum relax_state_id state;
++  enum relax_state_id initial_state;
++
++  Elf_Internal_Rela *rela;
++  bfd_size_type size;
++  bfd_vma offset;
++  int size_adjust;
++  int offset_adjust;
++  bfd_boolean has_grown;
++
++  /* Only used by constant pool entries.  When this drops to zero, the
++     frag is discarded (i.e. size_adjust is set to -4.)  */
++  int refcount;
++};
++
++struct avr32_relax_data
++{
++  unsigned int frag_count;
++  struct fragment *frag;
++  struct avr32_reloc_data *reloc_data;
++
++  /* TRUE if this section has one or more relaxable relocations */
++  bfd_boolean is_relaxable;
++  unsigned int iteration;
++};
++
++struct avr32_section_data
++{
++  struct bfd_elf_section_data elf;
++  struct avr32_relax_data relax_data;
++};
++
++\f/* Relax state definitions */
++
++#define PIC_MOV2_OPCODE               0xe0600000
++#define PIC_MOV2_MASK         0xe1e00000
++#define PIC_MOV2_RANGE_MIN    (-1048576 * 4)
++#define PIC_MOV2_RANGE_MAX    (1048575 * 4)
++#define PIC_MCALL_OPCODE      0xf0160000
++#define PIC_MCALL_MASK                0xffff0000
++#define PIC_MCALL_RANGE_MIN   (-131072)
++#define PIC_MCALL_RANGE_MAX   (131068)
++#define RCALL2_OPCODE         0xe0a00000
++#define RCALL2_MASK           0xe1ef0000
++#define RCALL2_RANGE_MIN      (-2097152)
++#define RCALL2_RANGE_MAX      (2097150)
++#define RCALL1_OPCODE         0xc00c0000
++#define RCALL1_MASK           0xf00c0000
++#define RCALL1_RANGE_MIN      (-1024)
++#define RCALL1_RANGE_MAX      (1022)
++#define PIC_LDW4_OPCODE               0xecf00000
++#define PIC_LDW4_MASK         0xfff00000
++#define PIC_LDW4_RANGE_MIN    (-32768)
++#define PIC_LDW4_RANGE_MAX    (32767)
++#define PIC_LDW3_OPCODE               0x6c000000
++#define PIC_LDW3_MASK         0xfe000000
++#define PIC_LDW3_RANGE_MIN    (0)
++#define PIC_LDW3_RANGE_MAX    (124)
++#define SUB5_PC_OPCODE                0xfec00000
++#define SUB5_PC_MASK          0xfff00000
++#define SUB5_PC_RANGE_MIN     (-32768)
++#define SUB5_PC_RANGE_MAX     (32767)
++#define NOPIC_MCALL_OPCODE    0xf01f0000
++#define NOPIC_MCALL_MASK      0xffff0000
++#define NOPIC_MCALL_RANGE_MIN PIC_MCALL_RANGE_MIN
++#define NOPIC_MCALL_RANGE_MAX PIC_MCALL_RANGE_MAX
++#define NOPIC_LDW4_OPCODE     0xfef00000
++#define NOPIC_LDW4_MASK               0xfff00000
++#define NOPIC_LDW4_RANGE_MIN  PIC_LDW4_RANGE_MIN
++#define NOPIC_LDW4_RANGE_MAX  PIC_LDW4_RANGE_MAX
++#define LDDPC_OPCODE          0x48000000
++#define LDDPC_MASK            0xf8000000
++#define LDDPC_RANGE_MIN               0
++#define LDDPC_RANGE_MAX               508
++
++#define NOPIC_MOV2_OPCODE  0xe0600000
++#define NOPIC_MOV2_MASK        0xe1e00000
++#define NOPIC_MOV2_RANGE_MIN   (-1048576)
++#define NOPIC_MOV2_RANGE_MAX   (1048575)
++#define NOPIC_MOV1_OPCODE  0x30000000
++#define NOPIC_MOV1_MASK        0xf0000000
++#define NOPIC_MOV1_RANGE_MIN   (-128)
++#define NOPIC_MOV1_RANGE_MAX   (127)
++
++/* Only brc2 variants with cond[3] == 0 is considered, since the
++   others are not relaxable.  bral is a special case and is handled
++   separately.  */
++#define BRC2_OPCODE           0xe0800000
++#define BRC2_MASK             0xe1e80000
++#define BRC2_RANGE_MIN                (-2097152)
++#define BRC2_RANGE_MAX                (2097150)
++#define BRC1_OPCODE           0xc0000000
++#define BRC1_MASK             0xf0080000
++#define BRC1_RANGE_MIN                (-256)
++#define BRC1_RANGE_MAX                (254)
++#define BRAL_OPCODE           0xe08f0000
++#define BRAL_MASK             0xe1ef0000
++#define BRAL_RANGE_MIN                BRC2_RANGE_MIN
++#define BRAL_RANGE_MAX                BRC2_RANGE_MAX
++#define RJMP_OPCODE           0xc0080000
++#define RJMP_MASK             0xf00c0000
++#define RJMP_RANGE_MIN                (-1024)
++#define RJMP_RANGE_MAX                (1022)
++
++/* Define a relax state using the GOT  */
++#define RG(id, dir, next, prev, r_type, opc, size)                    \
++  { "RS_"#id, RS_##id, RS_##dir, RS_##next, RS_##prev, REF_GOT,               \
++      R_AVR32_##r_type,       opc##_OPCODE, opc##_MASK,                       \
++      opc##_RANGE_MIN, opc##_RANGE_MAX, size }
++/* Define a relax state using the Constant Pool  */
++#define RC(id, dir, next, prev, r_type, opc, size)                    \
++  { "RS_"#id, RS_##id, RS_##dir, RS_##next, RS_##prev, REF_CPOOL,     \
++      R_AVR32_##r_type,       opc##_OPCODE, opc##_MASK,                       \
++      opc##_RANGE_MIN, opc##_RANGE_MAX, size }
++
++/* Define a relax state using pc-relative direct reference  */
++#define RP(id, dir, next, prev, r_type, opc, size)                    \
++  { "RS_"#id, RS_##id, RS_##dir, RS_##next, RS_##prev, REF_PCREL,     \
++      R_AVR32_##r_type,       opc##_OPCODE, opc##_MASK,                       \
++      opc##_RANGE_MIN, opc##_RANGE_MAX, size }
++
++/* Define a relax state using non-pc-relative direct reference */
++#define RD(id, dir, next, prev, r_type, opc, size)         \
++  { "RS_"#id, RS_##id, RS_##dir, RS_##next, RS_##prev, REF_ABSOLUTE,   \
++      R_AVR32_##r_type,    opc##_OPCODE, opc##_MASK,           \
++      opc##_RANGE_MIN, opc##_RANGE_MAX, size }
++
++/* Define a relax state that will be handled specially  */
++#define RS(id, r_type, size)                                          \
++  { "RS_"#id, RS_##id, RS_NONE, RS_NONE, RS_NONE, REF_ABSOLUTE,               \
++      R_AVR32_##r_type, 0, 0, 0, 0, size }
++
++const struct relax_state relax_state[RS_MAX] = {
++  RS(NONE, NONE, 0),
++  RS(ALIGN, ALIGN, 0),
++  RS(CPENT, 32_CPENT, 4),
++
++  RG(PIC_CALL, PIC_RCALL1, PIC_MCALL, NONE, GOTCALL, PIC_MOV2, 10),
++  RG(PIC_MCALL, PIC_RCALL1, NONE, PIC_CALL, GOT18SW, PIC_MCALL, 4),
++  RP(PIC_RCALL2, NONE, PIC_RCALL1, PIC_MCALL, 22H_PCREL, RCALL2, 4),
++  RP(PIC_RCALL1, NONE, NONE, PIC_RCALL2, 11H_PCREL, RCALL1, 2),
++
++  RG(PIC_LDA, PIC_SUB5, PIC_LDW4, NONE, LDA_GOT, PIC_MOV2, 8),
++  RG(PIC_LDW4, PIC_SUB5, PIC_LDW3, PIC_LDA, GOT16S, PIC_LDW4, 4),
++  RG(PIC_LDW3, PIC_SUB5, NONE, PIC_LDW4, GOT7UW, PIC_LDW3, 2),
++  RP(PIC_SUB5, NONE, NONE, PIC_LDW3, 16N_PCREL, SUB5_PC, 4),
++
++  RC(NOPIC_MCALL, NOPIC_RCALL1, NONE, NONE, CPCALL, NOPIC_MCALL, 4),
++  RP(NOPIC_RCALL2, NONE, NOPIC_RCALL1, NOPIC_MCALL, 22H_PCREL, RCALL2, 4),
++  RP(NOPIC_RCALL1, NONE, NONE, NOPIC_RCALL2, 11H_PCREL, RCALL1, 2),
++
++  RC(NOPIC_LDW4, NOPIC_MOV1, NOPIC_LDDPC, NONE, 16_CP, NOPIC_LDW4, 4),
++  RC(NOPIC_LDDPC, NOPIC_MOV1, NONE, NOPIC_LDW4, 9W_CP, LDDPC, 2),
++  RP(NOPIC_SUB5, NOPIC_MOV1, NONE, NOPIC_LDDPC, 16N_PCREL, SUB5_PC, 4),
++  RD(NOPIC_MOV2, NONE, NOPIC_MOV1, NOPIC_SUB5, 21S, NOPIC_MOV2, 4),
++  RD(NOPIC_MOV1, NONE, NONE, NOPIC_MOV2, 8S, NOPIC_MOV1, 2),
++
++  RP(RCALL2, NONE, RCALL1, NONE, 22H_PCREL, RCALL2, 4),
++  RP(RCALL1, NONE, NONE, RCALL2, 11H_PCREL, RCALL1, 2),
++  RP(BRC2, NONE, BRC1, NONE, 22H_PCREL, BRC2, 4),
++  RP(BRC1, NONE, NONE, BRC2, 9H_PCREL, BRC1, 2),
++  RP(BRAL, NONE, RJMP, NONE, 22H_PCREL, BRAL, 4),
++  RP(RJMP, NONE, NONE, BRAL, 11H_PCREL, RJMP, 2),
++};
++
++static bfd_boolean
++avr32_elf_new_section_hook(bfd *abfd, asection *sec)
++{
++  struct avr32_section_data *sdata;
++
++  sdata = bfd_zalloc(abfd, sizeof(struct avr32_section_data));
++  if (!sdata)
++    return FALSE;
++
++  sec->used_by_bfd = sdata;
++  return _bfd_elf_new_section_hook(abfd, sec);
++}
++
++static struct avr32_relax_data *
++avr32_relax_data(asection *sec)
++{
++  struct avr32_section_data *sdata;
++
++  BFD_ASSERT(sec->used_by_bfd);
++
++  sdata = (struct avr32_section_data *)elf_section_data(sec);
++  return &sdata->relax_data;
++}
++
++\f/* Link-time relaxation */
++
++static bfd_boolean
++avr32_elf_relax_section(bfd *abfd, asection *sec,
++                      struct bfd_link_info *info, bfd_boolean *again);
++
++enum relax_pass_id {
++  RELAX_PASS_SIZE_FRAGS,
++  RELAX_PASS_MOVE_DATA,
++};
++
++/* Stolen from the xtensa port */
++static int
++internal_reloc_compare (const void *ap, const void *bp)
++{
++  const Elf_Internal_Rela *a = (const Elf_Internal_Rela *) ap;
++  const Elf_Internal_Rela *b = (const Elf_Internal_Rela *) bp;
++
++  if (a->r_offset != b->r_offset)
++    return (a->r_offset - b->r_offset);
++
++  /* We don't need to sort on these criteria for correctness,
++     but enforcing a more strict ordering prevents unstable qsort
++     from behaving differently with different implementations.
++     Without the code below we get correct but different results
++     on Solaris 2.7 and 2.8.  We would like to always produce the
++     same results no matter the host.  */
++
++  if (a->r_info != b->r_info)
++    return (a->r_info - b->r_info);
++
++  return (a->r_addend - b->r_addend);
++}
++
++static enum relax_state_id
++get_pcrel22_relax_state(bfd *abfd, asection *sec, struct bfd_link_info *info,
++                      const Elf_Internal_Rela *rela)
++{
++  bfd_byte *contents;
++  bfd_vma insn;
++  enum relax_state_id rs = RS_NONE;
++
++  contents = retrieve_contents(abfd, sec, info->keep_memory);
++  if (!contents)
++    return RS_ERROR;
++
++  insn = bfd_get_32(abfd, contents + rela->r_offset);
++  if ((insn & RCALL2_MASK) == RCALL2_OPCODE)
++    rs = RS_RCALL2;
++  else if ((insn & BRAL_MASK) == BRAL_OPCODE)
++    /* Optimizing bral -> rjmp gets us into all kinds of
++       trouble with jump tables. Better not do it.  */
++    rs = RS_NONE;
++  else if ((insn & BRC2_MASK) == BRC2_OPCODE)
++    rs = RS_BRC2;
++
++  release_contents(sec, contents);
++
++  return rs;
++}
++
++static enum relax_state_id
++get_initial_relax_state(bfd *abfd, asection *sec, struct bfd_link_info *info,
++                      const Elf_Internal_Rela *rela)
++{
++  switch (ELF_R_TYPE(rela->r_info))
++    {
++    case R_AVR32_GOTCALL:
++      return RS_PIC_CALL;
++    case R_AVR32_GOT18SW:
++      return RS_PIC_MCALL;
++    case R_AVR32_LDA_GOT:
++      return RS_PIC_LDA;
++    case R_AVR32_GOT16S:
++      return RS_PIC_LDW4;
++    case R_AVR32_CPCALL:
++      return RS_NOPIC_MCALL;
++    case R_AVR32_16_CP:
++      return RS_NOPIC_LDW4;
++    case R_AVR32_9W_CP:
++      return RS_NOPIC_LDDPC;
++    case R_AVR32_ALIGN:
++      return RS_ALIGN;
++    case R_AVR32_32_CPENT:
++      return RS_CPENT;
++    case R_AVR32_22H_PCREL:
++      return get_pcrel22_relax_state(abfd, sec, info, rela);
++    case R_AVR32_9H_PCREL:
++      return RS_BRC1;
++    default:
++      return RS_NONE;
++    }
++}
++
++static bfd_boolean
++reloc_is_cpool_ref(const Elf_Internal_Rela *rela)
++{
++  switch (ELF_R_TYPE(rela->r_info))
++    {
++    case R_AVR32_CPCALL:
++    case R_AVR32_16_CP:
++    case R_AVR32_9W_CP:
++      return TRUE;
++    default:
++      return FALSE;
++    }
++}
++
++static struct fragment *
++new_frag(bfd *abfd ATTRIBUTE_UNUSED, asection *sec,
++       struct avr32_relax_data *rd, enum relax_state_id state,
++       Elf_Internal_Rela *rela)
++{
++  struct fragment *frag;
++  bfd_size_type r_size;
++  bfd_vma r_offset;
++  unsigned int i = rd->frag_count;
++
++  BFD_ASSERT(state >= RS_NONE && state < RS_MAX);
++
++  rd->frag_count++;
++  frag = bfd_realloc(rd->frag, sizeof(struct fragment) * rd->frag_count);
++  if (!frag)
++    return NULL;
++  rd->frag = frag;
++
++  frag += i;
++  memset(frag, 0, sizeof(struct fragment));
++
++  if (state == RS_ALIGN)
++    r_size = (((rela->r_offset + (1 << rela->r_addend) - 1)
++             & ~((1 << rela->r_addend) - 1)) - rela->r_offset);
++  else
++    r_size = relax_state[state].size;
++
++  if (rela)
++    r_offset = rela->r_offset;
++  else
++    r_offset = sec->size;
++
++  if (i == 0)
++    {
++      frag->offset = 0;
++      frag->size = r_offset + r_size;
++    }
++  else
++    {
++      frag->offset = rd->frag[i - 1].offset + rd->frag[i - 1].size;
++      frag->size = r_offset + r_size - frag->offset;
++    }
++
++  if (state != RS_CPENT)
++    /* Make sure we don't discard this frag */
++    frag->refcount = 1;
++
++  frag->initial_state = frag->state = state;
++  frag->rela = rela;
++
++  return frag;
++}
++
++static struct fragment *
++find_frag(asection *sec, bfd_vma offset)
++{
++  struct fragment *first, *last;
++  struct avr32_relax_data *rd = avr32_relax_data(sec);
++
++  if (rd->frag_count == 0)
++    return NULL;
++
++  first = &rd->frag[0];
++  last = &rd->frag[rd->frag_count - 1];
++
++  /* This may be a reloc referencing the end of a section.  The last
++     frag will never have a reloc associated with it, so its size will
++     never change, thus the offset adjustment of the last frag will
++     always be the same as the offset adjustment of the end of the
++     section.  */
++  if (offset == sec->size)
++    {
++      BFD_ASSERT(last->offset + last->size == sec->size);
++      BFD_ASSERT(!last->rela);
++      return last;
++    }
++
++  while (first <= last)
++    {
++      struct fragment *mid;
++
++      mid = (last - first) / 2 + first;
++      if ((mid->offset + mid->size) <= offset)
++      first = mid + 1;
++      else if (mid->offset > offset)
++      last = mid - 1;
++      else
++      return mid;
++    }
++
++  return NULL;
++}
++
++/* Look through all relocs in a section and determine if any relocs
++   may be affected by relaxation in other sections.  If so, allocate
++   an array of additional relocation data which links the affected
++   relocations to the frag(s) where the relaxation may occur.
++
++   This function also links cpool references to cpool entries and
++   increments the refcount of the latter when this happens.  */
++
++static bfd_boolean
++allocate_reloc_data(bfd *abfd, asection *sec, Elf_Internal_Rela *relocs,
++                  struct bfd_link_info *info)
++{
++  Elf_Internal_Shdr *symtab_hdr;
++  Elf_Internal_Sym *isymbuf = NULL;
++  struct avr32_relax_data *rd;
++  unsigned int i;
++  bfd_boolean ret = FALSE;
++
++  symtab_hdr = &elf_tdata(abfd)->symtab_hdr;
++  rd = avr32_relax_data(sec);
++
++  RDBG("%s<%s>: allocate_reloc_data\n", abfd->filename, sec->name);
++
++  for (i = 0; i < sec->reloc_count; i++)
++    {
++      Elf_Internal_Rela *rel = &relocs[i];
++      asection *sym_sec;
++      unsigned long r_symndx;
++      bfd_vma sym_value;
++
++      if (!rel->r_addend && ELF_R_TYPE(rel->r_info) != R_AVR32_DIFF32
++        && !reloc_is_cpool_ref(rel))
++      continue;
++
++      r_symndx = ELF_R_SYM(rel->r_info);
++
++      if (r_symndx < symtab_hdr->sh_info)
++      {
++        Elf_Internal_Sym *isym;
++
++        if (!isymbuf)
++          isymbuf = retrieve_local_syms(abfd, info->keep_memory);
++        if (!isymbuf)
++          return FALSE;
++
++        isym = &isymbuf[r_symndx];
++        sym_sec = bfd_section_from_elf_index(abfd, isym->st_shndx);
++        sym_value = isym->st_value;
++      }
++      else
++      {
++        struct elf_link_hash_entry *h;
++
++        h = elf_sym_hashes(abfd)[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->root.type != bfd_link_hash_defined
++            && h->root.type != bfd_link_hash_defweak)
++          continue;
++
++        sym_sec = h->root.u.def.section;
++        sym_value = h->root.u.def.value;
++      }
++
++      if (sym_sec && avr32_relax_data(sym_sec)->is_relaxable)
++      {
++        bfd_size_type size;
++        struct fragment *frag;
++
++        if (!rd->reloc_data)
++          {
++            size = sizeof(struct avr32_reloc_data) * sec->reloc_count;
++            rd->reloc_data = bfd_zalloc(abfd, size);
++            if (!rd->reloc_data)
++              goto out;
++          }
++
++        RDBG("[%3d] 0x%04lx: target: 0x%lx + 0x%lx",
++             i, rel->r_offset, sym_value, rel->r_addend);
++
++        frag = find_frag(sym_sec, sym_value + rel->r_addend);
++        BFD_ASSERT(frag);
++        rd->reloc_data[i].add_frag = frag;
++
++        RDBG(" -> %s<%s>:%04lx\n", sym_sec->owner->filename, sym_sec->name,
++             frag->rela ? frag->rela->r_offset : sym_sec->size);
++
++        if (reloc_is_cpool_ref(rel))
++          {
++            BFD_ASSERT(ELF_R_TYPE(frag->rela->r_info) == R_AVR32_32_CPENT);
++            frag->refcount++;
++          }
++
++        if (ELF_R_TYPE(rel->r_info) == R_AVR32_DIFF32)
++          {
++            bfd_byte *contents;
++            bfd_signed_vma diff;
++
++            contents = retrieve_contents(abfd, sec, info->keep_memory);
++            if (!contents)
++              goto out;
++
++            diff = bfd_get_signed_32(abfd, contents + rel->r_offset);
++            frag = find_frag(sym_sec, sym_value + rel->r_addend + diff);
++            BFD_ASSERT(frag);
++            rd->reloc_data[i].sub_frag = frag;
++
++            release_contents(sec, contents);
++          }
++      }
++    }
++
++  ret = TRUE;
++
++ out:
++  release_local_syms(abfd, isymbuf);
++  return ret;
++}
++
++static bfd_boolean
++global_sym_set_frag(struct elf_avr32_link_hash_entry *havr,
++                  struct bfd_link_info *info ATTRIBUTE_UNUSED)
++{
++  struct fragment *frag;
++  asection *sec;
++
++  if (havr->root.root.type != bfd_link_hash_defined
++      && havr->root.root.type != bfd_link_hash_defweak)
++    return TRUE;
++
++  sec = havr->root.root.u.def.section;
++  if (bfd_is_const_section(sec)
++      || !avr32_relax_data(sec)->is_relaxable)
++    return TRUE;
++
++  frag = find_frag(sec, havr->root.root.u.def.value);
++  if (!frag)
++    {
++      unsigned int i;
++      struct avr32_relax_data *rd = avr32_relax_data(sec);
++
++      RDBG("In %s: No frag for %s <%s+%lu> (limit %lu)\n",
++         sec->owner->filename, havr->root.root.root.string,
++         sec->name, havr->root.root.u.def.value, sec->size);
++      for (i = 0; i < rd->frag_count; i++)
++      RDBG("    %8lu - %8lu\n", rd->frag[i].offset,
++           rd->frag[i].offset + rd->frag[i].size);
++    }
++  BFD_ASSERT(frag);
++
++  havr->sym_frag = frag;
++  return TRUE;
++}
++
++static bfd_boolean
++analyze_relocations(struct bfd_link_info *info)
++{
++  bfd *abfd;
++  asection *sec;
++
++  /* Divide all relaxable sections into fragments */
++  for (abfd = info->input_bfds; abfd; abfd = abfd->link_next)
++    {
++      if (!(elf_elfheader(abfd)->e_flags & EF_AVR32_LINKRELAX))
++      {
++        if (!(*info->callbacks->warning)
++            (info, _("input is not relaxable"), NULL, abfd, NULL, 0))
++          return FALSE;
++        continue;
++      }
++
++      for (sec = abfd->sections; sec; sec = sec->next)
++      {
++        struct avr32_relax_data *rd;
++        struct fragment *frag;
++        Elf_Internal_Rela *relocs;
++        unsigned int i;
++        bfd_boolean ret = TRUE;
++
++        if (!(sec->flags & SEC_RELOC) || sec->reloc_count == 0)
++          continue;
++
++        rd = avr32_relax_data(sec);
++
++        relocs = retrieve_internal_relocs(abfd, sec, info->keep_memory);
++        if (!relocs)
++          return FALSE;
++
++        qsort(relocs, sec->reloc_count, sizeof(Elf_Internal_Rela),
++              internal_reloc_compare);
++
++        for (i = 0; i < sec->reloc_count; i++)
++          {
++            enum relax_state_id state;
++
++            ret = FALSE;
++            state = get_initial_relax_state(abfd, sec, info, &relocs[i]);
++            if (state == RS_ERROR)
++              break;
++
++            if (state)
++              {
++                frag = new_frag(abfd, sec, rd, state, &relocs[i]);
++                if (!frag)
++                  break;
++
++                pin_internal_relocs(sec, relocs);
++                rd->is_relaxable = TRUE;
++              }
++
++            ret = TRUE;
++          }
++
++        release_internal_relocs(sec, relocs);
++        if (!ret)
++          return ret;
++
++        if (rd->is_relaxable)
++          {
++            frag = new_frag(abfd, sec, rd, RS_NONE, NULL);
++            if (!frag)
++              return FALSE;
++          }
++      }
++    }
++
++  /* Link each global symbol to the fragment where it's defined.  */
++  elf_link_hash_traverse(elf_hash_table(info), global_sym_set_frag, info);
++
++  /* Do the same for local symbols. */
++  for (abfd = info->input_bfds; abfd; abfd = abfd->link_next)
++    {
++      Elf_Internal_Sym *isymbuf, *isym;
++      struct fragment **local_sym_frag;
++      unsigned int i, sym_count;
++
++      sym_count = elf_tdata(abfd)->symtab_hdr.sh_info;
++      if (sym_count == 0)
++      continue;
++
++      local_sym_frag = bfd_zalloc(abfd, sym_count * sizeof(struct fragment *));
++      if (!local_sym_frag)
++      return FALSE;
++      elf_tdata(abfd)->local_sym_frag = local_sym_frag;
++
++      isymbuf = retrieve_local_syms(abfd, info->keep_memory);
++      if (!isymbuf)
++      return FALSE;
++
++      for (i = 0; i < sym_count; i++)
++      {
++        struct avr32_relax_data *rd;
++        struct fragment *frag;
++        asection *sec;
++
++        isym = &isymbuf[i];
++
++        sec = bfd_section_from_elf_index(abfd, isym->st_shndx);
++        if (!sec)
++          continue;
++
++        rd = avr32_relax_data(sec);
++        if (!rd->is_relaxable)
++          continue;
++
++        frag = find_frag(sec, isym->st_value);
++        BFD_ASSERT(frag);
++
++        local_sym_frag[i] = frag;
++      }
++
++      release_local_syms(abfd, isymbuf);
++    }
++
++  /* And again for relocs with addends and constant pool references */
++  for (abfd = info->input_bfds; abfd; abfd = abfd->link_next)
++    for (sec = abfd->sections; sec; sec = sec->next)
++      {
++      Elf_Internal_Rela *relocs;
++      bfd_boolean ret;
++
++      if (!(sec->flags & SEC_RELOC) || sec->reloc_count == 0)
++        continue;
++
++      relocs = retrieve_internal_relocs(abfd, sec, info->keep_memory);
++      if (!relocs)
++        return FALSE;
++
++      ret = allocate_reloc_data(abfd, sec, relocs, info);
++
++      release_internal_relocs(sec, relocs);
++      if (ret == FALSE)
++        return ret;
++      }
++
++  return TRUE;
++}
++
++static bfd_boolean
++rs_is_good_enough(const struct relax_state *rs, struct fragment *frag,
++                bfd_vma symval, bfd_vma addr, struct got_entry *got,
++                struct avr32_reloc_data *ind_data,
++                bfd_signed_vma offset_adjust)
++{
++  bfd_signed_vma target = 0;
++
++  switch (rs->reftype)
++    {
++    case REF_ABSOLUTE:
++      target = symval;
++      break;
++    case REF_PCREL:
++      target = symval - addr;
++      break;
++    case REF_CPOOL:
++      /* cpool frags are always in the same section and always after
++       all frags referring to it.  So it's always correct to add in
++       offset_adjust here.  */
++      target = (ind_data->add_frag->offset + ind_data->add_frag->offset_adjust
++              + offset_adjust - frag->offset - frag->offset_adjust);
++      break;
++    case REF_GOT:
++      target = got->offset;
++      break;
++    default:
++      abort();
++    }
++
++  if (target >= rs->range_min && target <= rs->range_max)
++    return TRUE;
++  else
++    return FALSE;
++}
++
++static bfd_boolean
++avr32_size_frags(bfd *abfd, asection *sec, struct bfd_link_info *info)
++{
++  struct elf_avr32_link_hash_table *htab;
++  struct avr32_relax_data *rd;
++  Elf_Internal_Shdr *symtab_hdr;
++  Elf_Internal_Rela *relocs = NULL;
++  Elf_Internal_Sym *isymbuf = NULL;
++  struct got_entry **local_got_ents;
++  struct fragment **local_sym_frag;
++  bfd_boolean ret = FALSE;
++  bfd_signed_vma delta = 0;
++  unsigned int i;
++
++  htab = avr32_elf_hash_table(info);
++  rd = avr32_relax_data(sec);
++
++  if (sec == htab->sgot)
++    {
++      RDBG("Relaxing GOT section (vma: 0x%lx)\n",
++         sec->output_section->vma + sec->output_offset);
++      if (assign_got_offsets(htab))
++      htab->repeat_pass = TRUE;
++      return TRUE;
++    }
++
++  if (!rd->is_relaxable)
++    return TRUE;
++
++  if (!sec->rawsize)
++    sec->rawsize = sec->size;
++
++  symtab_hdr = &elf_tdata(abfd)->symtab_hdr;
++  relocs = retrieve_internal_relocs(abfd, sec, info->keep_memory);
++  if (!relocs)
++    goto out;
++
++  isymbuf = retrieve_local_syms(abfd, info->keep_memory);
++  if (!isymbuf)
++    goto out;
++
++  local_got_ents = elf_local_got_ents(abfd);
++  local_sym_frag = elf_tdata(abfd)->local_sym_frag;
++
++  RDBG("size_frags: %s<%s>\n  vma: 0x%08lx, size: 0x%08lx\n",
++       abfd->filename, sec->name,
++       sec->output_section->vma + sec->output_offset, sec->size);
++
++  for (i = 0; i < rd->frag_count; i++)
++    {
++      struct fragment *frag = &rd->frag[i];
++      struct avr32_reloc_data *r_data = NULL, *ind_data = NULL;
++      const struct relax_state *state, *next_state;
++      struct fragment *target_frag = NULL;
++      asection *sym_sec = NULL;
++      Elf_Internal_Rela *rela;
++      struct got_entry *got;
++      bfd_vma symval, r_offset, addend, addr;
++      bfd_signed_vma size_adjust = 0, distance;
++      unsigned long r_symndx;
++      bfd_boolean defined = TRUE, dynamic = FALSE;
++      unsigned char sym_type;
++
++      frag->offset_adjust += delta;
++      state = next_state = &relax_state[frag->state];
++      rela = frag->rela;
++
++      BFD_ASSERT(state->id == frag->state);
++
++      RDBG("  0x%04lx%c%d: %s [size %ld]", rela ? rela->r_offset : sec->rawsize,
++         (frag->offset_adjust < 0)?'-':'+',
++         abs(frag->offset_adjust), state->name, state->size);
++
++      if (!rela)
++      {
++        RDBG(": no reloc, ignoring\n");
++        continue;
++      }
++
++      BFD_ASSERT((unsigned int)(rela - relocs) < sec->reloc_count);
++      BFD_ASSERT(state != RS_NONE);
++
++      r_offset = rela->r_offset + frag->offset_adjust;
++      addr = sec->output_section->vma + sec->output_offset + r_offset;
++
++      switch (frag->state)
++      {
++      case RS_ALIGN:
++        size_adjust = ((addr + (1 << rela->r_addend) - 1)
++                       & ~((1 << rela->r_addend) - 1));
++        size_adjust -= (sec->output_section->vma + sec->output_offset
++                        + frag->offset + frag->offset_adjust
++                        + frag->size + frag->size_adjust);
++
++        RDBG(": adjusting size %lu -> %lu\n", frag->size + frag->size_adjust,
++             frag->size + frag->size_adjust + size_adjust);
++        break;
++
++      case RS_CPENT:
++        if (frag->refcount == 0 && frag->size_adjust == 0)
++          {
++            RDBG(": discarding frag\n");
++            size_adjust = -4;
++          }
++        else if (frag->refcount > 0 && frag->size_adjust < 0)
++          {
++            RDBG(": un-discarding frag\n");
++            size_adjust = 4;
++          }
++        break;
++
++      default:
++        if (rd->reloc_data)
++          r_data = &rd->reloc_data[frag->rela - relocs];
++
++        /* If this is a cpool reference, we want the symbol that the
++           cpool entry refers to, not the symbol for the cpool entry
++           itself, as we already know what frag it's in.  */
++        if (relax_state[frag->initial_state].reftype == REF_CPOOL)
++          {
++            Elf_Internal_Rela *irela = r_data->add_frag->rela;
++
++            r_symndx = ELF_R_SYM(irela->r_info);
++            addend = irela->r_addend;
++
++            /* The constant pool must be in the same section as the
++               reloc referring to it.  */
++            BFD_ASSERT((unsigned long)(irela - relocs) < sec->reloc_count);
++
++            ind_data = r_data;
++            r_data = &rd->reloc_data[irela - relocs];
++          }
++        else
++          {
++            r_symndx = ELF_R_SYM(rela->r_info);
++            addend = rela->r_addend;
++          }
++
++        /* Get the value of the symbol referred to by the reloc.  */
++        if (r_symndx < symtab_hdr->sh_info)
++          {
++            Elf_Internal_Sym *isym;
++
++            isym = isymbuf + r_symndx;
++            symval = 0;
++
++            RDBG(" local sym %lu: ", r_symndx);
++
++            if (isym->st_shndx == SHN_UNDEF)
++              defined = FALSE;
++            else if (isym->st_shndx == SHN_ABS)
++              sym_sec = bfd_abs_section_ptr;
++            else if (isym->st_shndx == SHN_COMMON)
++              sym_sec = bfd_com_section_ptr;
++            else
++              sym_sec = bfd_section_from_elf_index(abfd, isym->st_shndx);
++
++            symval = isym->st_value;
++            sym_type = ELF_ST_TYPE(isym->st_info);
++            target_frag = local_sym_frag[r_symndx];
++
++            if (local_got_ents)
++              got = local_got_ents[r_symndx];
++            else
++              got = NULL;
++          }
++        else
++          {
++            /* Global symbol */
++            unsigned long index;
++            struct elf_link_hash_entry *h;
++            struct elf_avr32_link_hash_entry *havr;
++
++            index = r_symndx - symtab_hdr->sh_info;
++            h = elf_sym_hashes(abfd)[index];
++            BFD_ASSERT(h != NULL);
++
++            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;
++
++            havr = (struct elf_avr32_link_hash_entry *)h;
++            got = h->got.glist;
++
++            symval = 0;
++
++            RDBG(" %s: ", h->root.root.string);
++
++            if (h->root.type != bfd_link_hash_defined
++                && h->root.type != bfd_link_hash_defweak)
++              {
++                RDBG("(undef)");
++                defined = FALSE;
++              }
++            else if ((info->shared && !info->symbolic && h->dynindx != -1)
++                     || (htab->root.dynamic_sections_created
++                         && h->def_dynamic && !h->def_regular))
++              {
++                RDBG("(dynamic)");
++                dynamic = TRUE;
++                sym_sec = h->root.u.def.section;
++              }
++            else
++              {
++                sym_sec = h->root.u.def.section;
++                symval = h->root.u.def.value;
++                target_frag = havr->sym_frag;
++              }
++
++            sym_type = h->type;
++          }
++
++        /* Thanks to elf32-ppc for this one.  */
++        if (sym_sec && sym_sec->sec_info_type == ELF_INFO_TYPE_MERGE)
++          {
++            /* At this stage in linking, no SEC_MERGE symbol has been
++               adjusted, so all references to such symbols need to be
++               passed through _bfd_merged_section_offset.  (Later, in
++               relocate_section, all SEC_MERGE symbols *except* for
++               section symbols have been adjusted.)
++
++               SEC_MERGE sections are not relaxed by us, as they
++               shouldn't contain any code.  */
++
++            BFD_ASSERT(!target_frag && !(r_data && r_data->add_frag));
++
++            /* gas may reduce relocations against symbols in SEC_MERGE
++               sections to a relocation against the section symbol when
++               the original addend was zero.  When the reloc is against
++               a section symbol we should include the addend in the
++               offset passed to _bfd_merged_section_offset, since the
++               location of interest is the original symbol.  On the
++               other hand, an access to "sym+addend" where "sym" is not
++               a section symbol should not include the addend;  Such an
++               access is presumed to be an offset from "sym";  The
++               location of interest is just "sym".  */
++            RDBG("\n    MERGE: %s: 0x%lx+0x%lx+0x%lx -> ",
++                 (sym_type == STT_SECTION)?"section":"not section",
++                 sym_sec->output_section->vma + sym_sec->output_offset,
++                 symval, addend);
++
++            if (sym_type == STT_SECTION)
++              symval += addend;
++
++            symval = (_bfd_merged_section_offset
++                      (abfd, &sym_sec,
++                       elf_section_data(sym_sec)->sec_info, symval));
++
++            if (sym_type != STT_SECTION)
++              symval += addend;
++          }
++        else
++          symval += addend;
++
++        if (defined && !dynamic)
++          {
++            RDBG("0x%lx+0x%lx",
++                 sym_sec->output_section->vma + sym_sec->output_offset,
++                 symval);
++            symval += sym_sec->output_section->vma + sym_sec->output_offset;
++          }
++
++        if (r_data && r_data->add_frag)
++          /* If the add_frag pointer is set, it means that this reloc
++             has an addend that may be affected by relaxation.  */
++          target_frag = r_data->add_frag;
++
++        if (target_frag)
++          {
++            symval += target_frag->offset_adjust;
++
++            /* If target_frag comes after this frag in the same
++               section, we should assume that it will be moved by
++               the same amount we are.  */
++            if ((target_frag - rd->frag) < (int)rd->frag_count
++                && target_frag > frag)
++              symval += delta;
++          }
++
++        distance = symval - addr;
++
++        /* First, try to make a direct reference.  If the symbol is
++           dynamic or undefined, we must take care not to change its
++           reference type, that is, we can't make it direct.
++
++           Also, it seems like some sections may actually be resized
++           after the relaxation code is done, so we can't really
++           trust that our "distance" is correct.  There's really no
++           easy solution to this problem, so we'll just disallow
++           direct references to SEC_DATA sections.
++
++           Oh, and .bss isn't actually SEC_DATA, so we disallow
++           !SEC_HAS_CONTENTS as well. */
++        if (!dynamic && defined
++            && (htab->direct_data_refs
++                || (!(sym_sec->flags & SEC_DATA)
++                    && (sym_sec->flags & SEC_HAS_CONTENTS)))
++            && next_state->direct)
++          {
++            next_state = &relax_state[next_state->direct];
++            RDBG(" D-> %s", next_state->name);
++          }
++
++        /* Iterate backwards until we find a state that fits.  */
++        while (next_state->prev
++               && !rs_is_good_enough(next_state, frag, symval, addr,
++                                     got, ind_data, delta))
++          {
++            next_state = &relax_state[next_state->prev];
++            RDBG(" P-> %s", next_state->name);
++          }
++
++        /* Then try to find the best possible state.  */
++        while (next_state->next)
++          {
++            const struct relax_state *candidate;
++
++            candidate = &relax_state[next_state->next];
++            if (!rs_is_good_enough(candidate, frag, symval, addr, got,
++                                   ind_data, delta))
++              break;
++
++            next_state = candidate;
++            RDBG(" N-> %s", next_state->name);
++          }
++
++        RDBG(" [size %ld]\n", next_state->size);
++
++        BFD_ASSERT(next_state->id);
++        BFD_ASSERT(!dynamic || next_state->reftype == REF_GOT);
++
++        size_adjust = next_state->size - state->size;
++
++        /* There's a theoretical possibility that shrinking one frag
++           may cause another to grow, which may cause the first one to
++           grow as well, and we're back where we started.  Avoid this
++           scenario by disallowing a frag that has grown to ever
++           shrink again.  */
++        if (state->reftype == REF_GOT && next_state->reftype != REF_GOT)
++          {
++            if (frag->has_grown)
++              next_state = state;
++            else
++              unref_got_entry(htab, got);
++          }
++        else if (state->reftype != REF_GOT && next_state->reftype == REF_GOT)
++          {
++            ref_got_entry(htab, got);
++            frag->has_grown = TRUE;
++          }
++        else if (state->reftype == REF_CPOOL
++                 && next_state->reftype != REF_CPOOL)
++          {
++            if (frag->has_grown)
++              next_state = state;
++            else
++              ind_data->add_frag->refcount--;
++          }
++        else if (state->reftype != REF_CPOOL
++                 && next_state->reftype == REF_CPOOL)
++          {
++            ind_data->add_frag->refcount++;
++            frag->has_grown = TRUE;
++          }
++        else
++          {
++            if (frag->has_grown && size_adjust < 0)
++              next_state = state;
++            else if (size_adjust > 0)
++              frag->has_grown = TRUE;
++          }
++
++        size_adjust = next_state->size - state->size;
++        frag->state = next_state->id;
++
++        break;
++      }
++
++      if (size_adjust)
++      htab->repeat_pass = TRUE;
++
++      frag->size_adjust += size_adjust;
++      sec->size += size_adjust;
++      delta += size_adjust;
++
++      BFD_ASSERT((frag->offset + frag->offset_adjust
++                + frag->size + frag->size_adjust)
++               == (frag[1].offset + frag[1].offset_adjust + delta));
++    }
++
++  ret = TRUE;
++
++ out:
++  release_local_syms(abfd, isymbuf);
++  release_internal_relocs(sec, relocs);
++  return ret;
++}
++
++static bfd_boolean
++adjust_global_symbol(struct elf_avr32_link_hash_entry *havr,
++                   struct bfd_link_info *info ATTRIBUTE_UNUSED)
++{
++  struct elf_link_hash_entry *h = &havr->root;
++
++  if (havr->sym_frag && (h->root.type == bfd_link_hash_defined
++                       || h->root.type == bfd_link_hash_defweak))
++    {
++      RDBG("adjust_global_symbol: %s 0x%08lx -> 0x%08lx\n",
++         h->root.root.string, h->root.u.def.value,
++         h->root.u.def.value + havr->sym_frag->offset_adjust);
++      h->root.u.def.value += havr->sym_frag->offset_adjust;
++    }
++  return TRUE;
++}
++
++static bfd_boolean
++adjust_syms(struct bfd_link_info *info)
++{
++  struct elf_avr32_link_hash_table *htab;
++  bfd *abfd;
++
++  htab = avr32_elf_hash_table(info);
++  elf_link_hash_traverse(&htab->root, adjust_global_symbol, info);
++
++  for (abfd = info->input_bfds; abfd; abfd = abfd->link_next)
++    {
++      Elf_Internal_Sym *isymbuf;
++      struct fragment **local_sym_frag, *frag;
++      unsigned int i, sym_count;
++
++      sym_count = elf_tdata(abfd)->symtab_hdr.sh_info;
++      if (sym_count == 0)
++      continue;
++
++      isymbuf = retrieve_local_syms(abfd, info->keep_memory);
++      if (!isymbuf)
++      return FALSE;
++
++      local_sym_frag = elf_tdata(abfd)->local_sym_frag;
++
++      for (i = 0; i < sym_count; i++)
++      {
++        frag = local_sym_frag[i];
++        if (frag)
++          {
++            RDBG("adjust_local_symbol: %s[%u] 0x%08lx -> 0x%08lx\n",
++                 abfd->filename, i, isymbuf[i].st_value,
++                 isymbuf[i].st_value + frag->offset_adjust);
++            isymbuf[i].st_value += frag->offset_adjust;
++          }
++      }
++
++      release_local_syms(abfd, isymbuf);
++    }
++
++  htab->symbols_adjusted = TRUE;
++  return TRUE;
++}
++
++static bfd_boolean
++adjust_relocs(bfd *abfd, asection *sec, struct bfd_link_info *info)
++{
++  struct avr32_relax_data *rd;
++  Elf_Internal_Rela *relocs;
++  Elf_Internal_Shdr *symtab_hdr;
++  unsigned int i;
++  bfd_boolean ret = FALSE;
++
++  rd = avr32_relax_data(sec);
++  if (!rd->reloc_data)
++    return TRUE;
++
++  RDBG("adjust_relocs: %s<%s> (count: %u)\n", abfd->filename, sec->name,
++       sec->reloc_count);
++
++  relocs = retrieve_internal_relocs(abfd, sec, info->keep_memory);
++  if (!relocs)
++    return FALSE;
++
++  symtab_hdr = &elf_tdata(abfd)->symtab_hdr;
++
++  for (i = 0; i < sec->reloc_count; i++)
++    {
++      Elf_Internal_Rela *rela = &relocs[i];
++      struct avr32_reloc_data *r_data = &rd->reloc_data[i];
++      struct fragment *sym_frag;
++      unsigned long r_symndx;
++
++      if (r_data->add_frag)
++      {
++        r_symndx = ELF_R_SYM(rela->r_info);
++
++        if (r_symndx < symtab_hdr->sh_info)
++          sym_frag = elf_tdata(abfd)->local_sym_frag[r_symndx];
++        else
++          {
++            struct elf_link_hash_entry *h;
++
++            h = elf_sym_hashes(abfd)[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;
++
++            BFD_ASSERT(h->root.type == bfd_link_hash_defined
++                       || h->root.type == bfd_link_hash_defweak);
++
++            sym_frag = ((struct elf_avr32_link_hash_entry *)h)->sym_frag;
++          }
++
++        RDBG("    addend: 0x%08lx -> 0x%08lx\n",
++             rela->r_addend,
++             rela->r_addend + r_data->add_frag->offset_adjust
++             - (sym_frag ? sym_frag->offset_adjust : 0));
++
++        /* If this is against a section symbol, we won't find any
++           sym_frag, so we'll just adjust the addend.  */
++        rela->r_addend += r_data->add_frag->offset_adjust;
++        if (sym_frag)
++          rela->r_addend -= sym_frag->offset_adjust;
++
++        if (r_data->sub_frag)
++          {
++            bfd_byte *contents;
++            bfd_signed_vma diff;
++
++            contents = retrieve_contents(abfd, sec, info->keep_memory);
++            if (!contents)
++              goto out;
++
++            /* I realize now that sub_frag is misnamed.  It's
++               actually add_frag which is subtracted in this
++               case...  */
++            diff = bfd_get_signed_32(abfd, contents + rela->r_offset);
++            diff += (r_data->sub_frag->offset_adjust
++                     - r_data->add_frag->offset_adjust);
++            bfd_put_32(abfd, diff, contents + rela->r_offset);
++
++            RDBG("   0x%lx: DIFF32 updated: 0x%lx\n", rela->r_offset, diff);
++
++            release_contents(sec, contents);
++          }
++      }
++      else
++      BFD_ASSERT(!r_data->sub_frag);
++    }
++
++  ret = TRUE;
++
++ out:
++  release_internal_relocs(sec, relocs);
++  return ret;
++}
++
++static bfd_boolean
++avr32_move_data(bfd *abfd, asection *sec, struct bfd_link_info *info)
++{
++  struct elf_avr32_link_hash_table *htab;
++  struct avr32_relax_data *rd;
++  struct fragment *frag, *fragend;
++  Elf_Internal_Rela *relocs = NULL;
++  bfd_byte *contents = NULL;
++  unsigned int i;
++  bfd_boolean ret = FALSE;
++
++  htab = avr32_elf_hash_table(info);
++  rd = avr32_relax_data(sec);
++
++  if (!htab->symbols_adjusted)
++    if (!adjust_syms(info))
++      return FALSE;
++
++  if (rd->is_relaxable)
++    {
++      /* Resize the section first, so that we can be sure that enough
++       memory is allocated in case the section has grown.  */
++      if (sec->size > sec->rawsize
++        && elf_section_data(sec)->this_hdr.contents)
++      {
++        /* We must not use cached data if the section has grown.  */
++        free(elf_section_data(sec)->this_hdr.contents);
++        elf_section_data(sec)->this_hdr.contents = NULL;
++      }
++
++      relocs = retrieve_internal_relocs(abfd, sec, info->keep_memory);
++      if (!relocs)
++      goto out;
++      contents = retrieve_contents(abfd, sec, info->keep_memory);
++      if (!contents)
++      goto out;
++
++      fragend = rd->frag + rd->frag_count;
++
++      RDBG("move_data: %s<%s>: relocs=%p, contents=%p\n",
++         abfd->filename, sec->name, relocs, contents);
++
++      /* First, move the data into place. We must take care to move
++       frags in the right order so that we don't accidentally
++       overwrite parts of the next frag.  */
++      for (frag = rd->frag; frag < fragend; frag++)
++      {
++        RDBG("    0x%08lx%c0x%x: size 0x%lx%c0x%x\n",
++             frag->offset, frag->offset_adjust >= 0 ? '+' : '-',
++             abs(frag->offset_adjust),
++             frag->size, frag->size_adjust >= 0 ? '+' : '-',
++             abs(frag->size_adjust));
++        if (frag->offset_adjust > 0)
++          {
++            struct fragment *prev = frag - 1;
++            struct fragment *last;
++
++            for (last = frag; last < fragend && last->offset_adjust > 0;
++                 last++) ;
++
++            if (last == fragend)
++              last--;
++
++            for (frag = last; frag != prev; frag--)
++              {
++                if (frag->offset_adjust
++                    && frag->size + frag->size_adjust > 0)
++                  {
++                    RDBG("memmove 0x%lx -> 0x%lx (size %lu)\n",
++                         frag->offset, frag->offset + frag->offset_adjust,
++                         frag->size + frag->size_adjust);
++                    memmove(contents + frag->offset + frag->offset_adjust,
++                            contents + frag->offset,
++                            frag->size + frag->size_adjust);
++                  }
++              }
++            frag = last;
++          }
++        else if (frag->offset_adjust && frag->size + frag->size_adjust > 0)
++          {
++            RDBG("memmove 0x%lx -> 0x%lx (size %lu)\n",
++                 frag->offset, frag->offset + frag->offset_adjust,
++                 frag->size + frag->size_adjust);
++            memmove(contents + frag->offset + frag->offset_adjust,
++                    contents + frag->offset,
++                    frag->size + frag->size_adjust);
++          }
++      }
++
++      i = 0;
++
++      for (frag = rd->frag; frag < fragend; frag++)
++      {
++        const struct relax_state *state, *istate;
++        struct avr32_reloc_data *r_data = NULL;
++
++        istate = &relax_state[frag->initial_state];
++        state = &relax_state[frag->state];
++
++        if (rd->reloc_data)
++          r_data = &rd->reloc_data[frag->rela - relocs];
++
++        BFD_ASSERT((long)(frag->size + frag->size_adjust) >= 0);
++        BFD_ASSERT(state->reftype != REF_CPOOL
++                   || r_data->add_frag->refcount > 0);
++
++        if (istate->reftype == REF_CPOOL && state->reftype != REF_CPOOL)
++          {
++            struct fragment *ifrag;
++
++            /* An indirect reference through the cpool has been
++               converted to a direct reference.  We must update the
++               reloc to point to the symbol itself instead of the
++               constant pool entry.  The reloc type will be updated
++               later.  */
++            ifrag = r_data->add_frag;
++            frag->rela->r_info = ifrag->rela->r_info;
++            frag->rela->r_addend = ifrag->rela->r_addend;
++
++            /* Copy the reloc data so the addend will be adjusted
++               correctly later.  */
++            *r_data = rd->reloc_data[ifrag->rela - relocs];
++          }
++
++        /* Move all relocs covered by this frag.  */
++        if (frag->rela)
++          BFD_ASSERT(&relocs[i] <= frag->rela);
++        else
++          BFD_ASSERT((frag + 1) == fragend && frag->state == RS_NONE);
++
++        if (frag == rd->frag)
++          BFD_ASSERT(i == 0);
++        else
++          BFD_ASSERT(&relocs[i] > frag[-1].rela);
++
++        /* If non-null, frag->rela is the last relocation in the
++           fragment.  frag->rela can only be null in the last
++           fragment, so in that case, we'll just do the rest.  */
++        for (; (i < sec->reloc_count
++                && (!frag->rela || &relocs[i] <= frag->rela)); i++)
++          {
++            RDBG("[%4u] r_offset 0x%08lx -> 0x%08lx\n", i, relocs[i].r_offset,
++                 relocs[i].r_offset + frag->offset_adjust);
++            relocs[i].r_offset += frag->offset_adjust;
++          }
++
++        if (frag->refcount == 0)
++          {
++            /* If this frag is to be discarded, make sure we won't
++               relocate it later on.  */
++            BFD_ASSERT(frag->state == RS_CPENT);
++            frag->rela->r_info = ELF_R_INFO(ELF_R_SYM(frag->rela->r_info),
++                                          R_AVR32_NONE);
++          }
++        else if (frag->state == RS_ALIGN)
++          {
++            bfd_vma addr, addr_end;
++
++            addr = frag->rela->r_offset;
++            addr_end = (frag->offset + frag->offset_adjust
++                        + frag->size + frag->size_adjust);
++
++            /* If the section is executable, insert NOPs.
++               Otherwise, insert zeroes.  */
++            if (sec->flags & SEC_CODE)
++              {
++                if (addr & 1)
++                  {
++                    bfd_put_8(abfd, 0, contents + addr);
++                    addr++;
++                  }
++
++                BFD_ASSERT(!((addr_end - addr) & 1));
++
++                while (addr < addr_end)
++                  {
++                    bfd_put_16(abfd, NOP_OPCODE, contents + addr);
++                    addr += 2;
++                  }
++              }
++            else
++              memset(contents + addr, 0, addr_end - addr);
++          }
++        else if (state->opcode_mask)
++          {
++            bfd_vma insn;
++
++            /* Update the opcode and the relocation type unless it's a
++               "special" relax state (i.e. RS_NONE, RS_ALIGN or
++               RS_CPENT.), in which case the opcode mask is zero.  */
++            insn = bfd_get_32(abfd, contents + frag->rela->r_offset);
++            insn &= ~state->opcode_mask;
++            insn |= state->opcode;
++            RDBG("    0x%lx: inserting insn %08lx\n",
++                 frag->rela->r_offset, insn);
++            bfd_put_32(abfd, insn, contents + frag->rela->r_offset);
++
++            frag->rela->r_info = ELF_R_INFO(ELF_R_SYM(frag->rela->r_info),
++                                            state->r_type);
++          }
++
++        if ((frag + 1) == fragend)
++          BFD_ASSERT((frag->offset + frag->size + frag->offset_adjust
++                      + frag->size_adjust) == sec->size);
++        else
++          BFD_ASSERT((frag->offset + frag->size + frag->offset_adjust
++                      + frag->size_adjust)
++                     == (frag[1].offset + frag[1].offset_adjust));
++      }
++    }
++
++  /* Adjust reloc addends and DIFF32 differences */
++  if (!adjust_relocs(abfd, sec, info))
++    return FALSE;
++
++  ret = TRUE;
++
++ out:
++  release_contents(sec, contents);
++  release_internal_relocs(sec, relocs);
++  return ret;
++}
++
++static bfd_boolean
++avr32_elf_relax_section(bfd *abfd, asection *sec,
++                      struct bfd_link_info *info, bfd_boolean *again)
++{
++  struct elf_avr32_link_hash_table *htab;
++  struct avr32_relax_data *rd;
++
++  *again = FALSE;
++  if (info->relocatable)
++    return TRUE;
++
++  htab = avr32_elf_hash_table(info);
++  if ((!(sec->flags & SEC_RELOC) || sec->reloc_count == 0)
++      && sec != htab->sgot)
++    return TRUE;
++
++  if (!htab->relocations_analyzed)
++    {
++      if (!analyze_relocations(info))
++      return FALSE;
++      htab->relocations_analyzed = TRUE;
++    }
++
++  rd = avr32_relax_data(sec);
++
++  if (rd->iteration != htab->relax_iteration)
++    {
++      if (!htab->repeat_pass)
++      htab->relax_pass++;
++      htab->relax_iteration++;
++      htab->repeat_pass = FALSE;
++    }
++
++  rd->iteration++;
++
++  switch (htab->relax_pass)
++    {
++    case RELAX_PASS_SIZE_FRAGS:
++      if (!avr32_size_frags(abfd, sec, info))
++      return FALSE;
++      *again = TRUE;
++      break;
++    case RELAX_PASS_MOVE_DATA:
++      if (!avr32_move_data(abfd, sec, info))
++      return FALSE;
++      break;
++  }
++
++  return TRUE;
++}
++
++
++/* Relocation */
++
++static bfd_reloc_status_type
++avr32_check_reloc_value(asection *sec, Elf_Internal_Rela *rela,
++                      bfd_signed_vma relocation, reloc_howto_type *howto);
++static bfd_reloc_status_type
++avr32_final_link_relocate(reloc_howto_type *howto, bfd *input_bfd,
++                        asection *input_section, bfd_byte *contents,
++                        Elf_Internal_Rela *rel, bfd_vma value);
++static bfd_boolean
++avr32_elf_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);
++
++
++#define symbol_address(symbol) \
++  symbol->value + symbol->section->output_section->vma \
++  + symbol->section->output_offset
++
++#define avr32_elf_insert_field(size, field, abfd, reloc_entry, data)  \
++  do                                                                  \
++    {                                                                 \
++      unsigned long x;                                                        \
++      x = bfd_get_##size (abfd, data + reloc_entry->address);         \
++      x &= ~reloc_entry->howto->dst_mask;                             \
++      x |= field & reloc_entry->howto->dst_mask;                      \
++      bfd_put_##size (abfd, (bfd_vma) x, data + reloc_entry->address);        \
++    }                                                                 \
++  while(0)
++
++static bfd_reloc_status_type
++avr32_check_reloc_value(asection *sec ATTRIBUTE_UNUSED,
++                      Elf_Internal_Rela *rela ATTRIBUTE_UNUSED,
++                      bfd_signed_vma relocation,
++                      reloc_howto_type *howto)
++{
++  bfd_vma reloc_u;
++
++  /* We take "complain_overflow_dont" to mean "don't complain on
++     alignment either". This way, we don't have to special-case
++     R_AVR32_HI16 */
++  if (howto->complain_on_overflow == complain_overflow_dont)
++    return bfd_reloc_ok;
++
++  /* Check if the value is correctly aligned */
++  if (relocation & ((1 << howto->rightshift) - 1))
++    {
++      RDBG("misaligned: %s<%s+%lx>: %s: 0x%lx (align %u)\n",
++         sec->owner->filename, sec->name, rela->r_offset,
++         howto->name, relocation, howto->rightshift);
++      return bfd_reloc_overflow;
++    }
++
++  /* Now, get rid of the unnecessary bits */
++  relocation >>= howto->rightshift;
++  reloc_u = (bfd_vma)relocation;
++
++  switch (howto->complain_on_overflow)
++    {
++    case complain_overflow_unsigned:
++    case complain_overflow_bitfield:
++      if (reloc_u > (unsigned long)((1 << howto->bitsize) - 1))
++      {
++        RDBG("unsigned overflow: %s<%s+%lx>: %s: 0x%lx (size %u)\n",
++             sec->owner->filename, sec->name, rela->r_offset,
++             howto->name, reloc_u, howto->bitsize);
++        RDBG("reloc vma: 0x%lx\n",
++             sec->output_section->vma + sec->output_offset + rela->r_offset);
++
++        return bfd_reloc_overflow;
++      }
++      break;
++    case complain_overflow_signed:
++      if (relocation > (1 << (howto->bitsize - 1)) - 1)
++      {
++        RDBG("signed overflow: %s<%s+%lx>: %s: 0x%lx (size %u)\n",
++             sec->owner->filename, sec->name, rela->r_offset,
++             howto->name, reloc_u, howto->bitsize);
++        RDBG("reloc vma: 0x%lx\n",
++             sec->output_section->vma + sec->output_offset + rela->r_offset);
++
++        return bfd_reloc_overflow;
++      }
++      if (relocation < -(1 << (howto->bitsize - 1)))
++      {
++        RDBG("signed overflow: %s<%s+%lx>: %s: -0x%lx (size %u)\n",
++             sec->owner->filename, sec->name, rela->r_offset,
++             howto->name, -relocation, howto->bitsize);
++        RDBG("reloc vma: 0x%lx\n",
++             sec->output_section->vma + sec->output_offset + rela->r_offset);
++
++        return bfd_reloc_overflow;
++      }
++      break;
++    default:
++      abort();
++    }
++
++  return bfd_reloc_ok;
++}
++
++
++static bfd_reloc_status_type
++avr32_final_link_relocate(reloc_howto_type *howto,
++                        bfd *input_bfd,
++                        asection *input_section,
++                        bfd_byte *contents,
++                        Elf_Internal_Rela *rel,
++                        bfd_vma value)
++{
++  bfd_vma field;
++  bfd_vma relocation;
++  bfd_reloc_status_type status;
++  bfd_byte *p = contents + rel->r_offset;
++  unsigned long x;
++
++  pr_debug("  (6b) final link relocate\n");
++
++  /* Sanity check the address */
++  if (rel->r_offset > input_section->size)
++    {
++      (*_bfd_error_handler)
++      ("%B: %A+0x%lx: offset out of range (section size: 0x%lx)",
++       input_bfd, input_section, rel->r_offset, input_section->size);
++      return bfd_reloc_outofrange;
++    }
++
++  relocation = value + rel->r_addend;
++
++  if (howto->pc_relative)
++    {
++      bfd_vma addr;
++
++      addr = input_section->output_section->vma
++      + input_section->output_offset + rel->r_offset;
++      addr &= ~0UL << howto->rightshift;
++      relocation -= addr;
++    }
++
++  switch (ELF32_R_TYPE(rel->r_info))
++    {
++    case R_AVR32_16N_PCREL:
++      /* sub reg, pc, . - (sym + addend) */
++      relocation = -relocation;
++      break;
++    }
++
++  status = avr32_check_reloc_value(input_section, rel, relocation, howto);
++
++  relocation >>= howto->rightshift;
++  if (howto->bitsize == 21)
++    field = (relocation & 0xffff)
++      | ((relocation & 0x10000) << 4)
++      | ((relocation & 0x1e0000) << 8);
++  else if (howto->bitsize == 12)
++    field = (relocation & 0xff) | ((relocation & 0xf00) << 4);
++  else if (howto->bitsize == 10)
++    field = ((relocation & 0xff) << 4)
++      | ((relocation & 0x300) >> 8);
++  else
++    field = relocation << howto->bitpos;
++
++  switch (howto->size)
++    {
++    case 0:
++      x = bfd_get_8 (input_bfd, p);
++      x &= ~howto->dst_mask;
++      x |= field & howto->dst_mask;
++      bfd_put_8 (input_bfd, (bfd_vma) x, p);
++      break;
++    case 1:
++      x = bfd_get_16 (input_bfd, p);
++      x &= ~howto->dst_mask;
++      x |= field & howto->dst_mask;
++      bfd_put_16 (input_bfd, (bfd_vma) x, p);
++      break;
++    case 2:
++      x = bfd_get_32 (input_bfd, p);
++      x &= ~howto->dst_mask;
++      x |= field & howto->dst_mask;
++      bfd_put_32 (input_bfd, (bfd_vma) x, p);
++      break;
++    default:
++      abort();
++    }
++
++  return status;
++}
++
++/* (6) Apply relocations to the normal (non-dynamic) sections */
++
++static bfd_boolean
++avr32_elf_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)
++{
++  struct elf_avr32_link_hash_table *htab;
++  Elf_Internal_Shdr *symtab_hdr;
++  Elf_Internal_Rela *rel, *relend;
++  struct elf_link_hash_entry **sym_hashes;
++  struct got_entry **local_got_ents;
++  asection *sgot;
++  asection *srelgot;
++
++  pr_debug("(6) relocate section %s:<%s> (size 0x%lx)\n",
++         input_bfd->filename, input_section->name, input_section->size);
++
++  /* If we're doing a partial link, we don't have to do anything since
++     we're using RELA relocations */
++  if (info->relocatable)
++    return TRUE;
++
++  htab = avr32_elf_hash_table(info);
++  symtab_hdr = &elf_tdata(input_bfd)->symtab_hdr;
++  sym_hashes = elf_sym_hashes(input_bfd);
++  local_got_ents = elf_local_got_ents(input_bfd);
++  sgot = htab->sgot;
++  srelgot = htab->srelgot;
++
++  relend = relocs + input_section->reloc_count;
++  for (rel = relocs; rel < relend; rel++)
++    {
++      unsigned long r_type, r_symndx;
++      reloc_howto_type *howto;
++      Elf_Internal_Sym *sym = NULL;
++      struct elf_link_hash_entry *h = NULL;
++      asection *sec = NULL;
++      bfd_vma value;
++      bfd_vma offset;
++      bfd_reloc_status_type status;
++
++      r_type = ELF32_R_TYPE(rel->r_info);
++      r_symndx = ELF32_R_SYM(rel->r_info);
++
++      if (r_type == R_AVR32_NONE
++        || r_type == R_AVR32_ALIGN
++        || r_type == R_AVR32_DIFF32
++        || r_type == R_AVR32_DIFF16
++        || r_type == R_AVR32_DIFF8)
++      continue;
++
++      /* Sanity check */
++      if (r_type > R_AVR32_max)
++      {
++        bfd_set_error(bfd_error_bad_value);
++        return FALSE;
++      }
++
++      howto = &elf_avr32_howto_table[r_type];
++
++      if (r_symndx < symtab_hdr->sh_info)
++      {
++        sym = local_syms + r_symndx;
++        sec = local_sections[r_symndx];
++
++        pr_debug("  (6a) processing %s against local symbol %lu\n",
++                 howto->name, r_symndx);
++
++        /* The following function changes rel->r_addend behind our back. */
++        value = _bfd_elf_rela_local_sym(output_bfd, sym, &sec, rel);
++        pr_debug("    => value: %lx, addend: %lx\n", value, rel->r_addend);
++      }
++      else
++      {
++        if (sym_hashes == NULL)
++          return FALSE;
++
++        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;
++
++        pr_debug("  (6a) processing %s against symbol %s\n",
++                 howto->name, h->root.root.string);
++
++        if (h->root.type == bfd_link_hash_defined
++            || h->root.type == bfd_link_hash_defweak)
++          {
++            bfd_boolean dyn;
++
++            dyn = htab->root.dynamic_sections_created;
++            sec = h->root.u.def.section;
++
++            if (sec->output_section)
++              value = (h->root.u.def.value
++                       + sec->output_section->vma
++                       + sec->output_offset);
++            else
++              value = h->root.u.def.value;
++          }
++        else if (h->root.type == bfd_link_hash_undefweak)
++          value = 0;
++        else if (info->unresolved_syms_in_objects == RM_IGNORE
++                 && ELF_ST_VISIBILITY(h->other) == STV_DEFAULT)
++          value = 0;
++        else
++          {
++            bfd_boolean err;
++            err = (info->unresolved_syms_in_objects == RM_GENERATE_ERROR
++                   || ELF_ST_VISIBILITY(h->other) != STV_DEFAULT);
++            if (!info->callbacks->undefined_symbol
++                (info, h->root.root.string, input_bfd,
++                 input_section, rel->r_offset, err))
++              return FALSE;
++            value = 0;
++          }
++
++        pr_debug("    => value: %lx, addend: %lx\n", value, rel->r_addend);
++      }
++
++      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:
++        BFD_ASSERT(sgot != NULL);
++
++        if (h != NULL)
++          {
++            BFD_ASSERT(h->got.glist->refcount > 0);
++            offset = h->got.glist->offset;
++
++            BFD_ASSERT(offset < sgot->size);
++            if (!elf_hash_table(info)->dynamic_sections_created
++                || (h->def_regular
++                    && (!info->shared
++                        || info->symbolic
++                        || h->dynindx == -1)))
++              {
++                /* This is actually a static link, or it is a
++                   -Bsymbolic link and the symbol is defined
++                   locally, or the symbol was forced to be local.  */
++                bfd_put_32(output_bfd, value, sgot->contents + offset);
++              }
++          }
++        else
++          {
++            BFD_ASSERT(local_got_ents &&
++                       local_got_ents[r_symndx]->refcount > 0);
++            offset = local_got_ents[r_symndx]->offset;
++
++            /* Local GOT entries don't have relocs.  If this is a
++               shared library, the dynamic linker will add the load
++               address to the initial value at startup.  */
++            BFD_ASSERT(offset < sgot->size);
++            pr_debug("Initializing GOT entry at offset %lu: 0x%lx\n",
++                     offset, value);
++            bfd_put_32 (output_bfd, value, sgot->contents + offset);
++          }
++
++        value = sgot->output_offset + offset;
++        pr_debug("GOT reference: New value %lx\n", value);
++        break;
++
++      case R_AVR32_GOTPC:
++        /* This relocation type is for constant pool entries used in
++           the calculation "Rd = PC - (PC - GOT)", where the
++           constant pool supplies the constant (PC - GOT)
++           offset. The symbol value + addend indicates where the
++           value of PC is taken. */
++        value -= sgot->output_section->vma;
++        break;
++
++      case R_AVR32_32_PCREL:
++        /* We must adjust r_offset to account for discarded data in
++           the .eh_frame section.  This is probably not the right
++           way to do this, since AFAICS all other architectures do
++           it some other way.  I just can't figure out how...  */
++        {
++          bfd_vma r_offset;
++
++          r_offset = _bfd_elf_section_offset(output_bfd, info,
++                                             input_section,
++                                             rel->r_offset);
++          if (r_offset == (bfd_vma)-1
++              || r_offset == (bfd_vma)-2)
++            continue;
++          rel->r_offset = r_offset;
++        }
++        break;
++
++      case R_AVR32_32:
++        /* We need to emit a run-time relocation in the following cases:
++             - we're creating a shared library
++             - the symbol is not defined in any regular objects
++
++           Of course, sections that aren't going to be part of the
++           run-time image will not get any relocs, and undefined
++           symbols won't have any either (only weak undefined
++           symbols should get this far).  */
++        if ((info->shared
++             || (elf_hash_table(info)->dynamic_sections_created
++                 && h != NULL
++                 && h->def_dynamic
++                 && !h->def_regular))
++            && r_symndx != 0
++            && (input_section->flags & SEC_ALLOC))
++          {
++            Elf_Internal_Rela outrel;
++            bfd_byte *loc;
++            bfd_boolean skip, relocate;
++            struct elf_avr32_link_hash_entry *avrh;
++
++            pr_debug("Going to generate dynamic reloc...\n");
++
++            skip = FALSE;
++            relocate = FALSE;
++
++            outrel.r_offset = _bfd_elf_section_offset(output_bfd, info,
++                                                      input_section,
++                                                      rel->r_offset);
++            if (outrel.r_offset == (bfd_vma)-1)
++              skip = TRUE;
++            else if (outrel.r_offset == (bfd_vma)-2)
++              skip = TRUE, relocate = TRUE;
++
++            outrel.r_offset += (input_section->output_section->vma
++                                + input_section->output_offset);
++
++            pr_debug("    ... offset %lx, dynindx %ld\n",
++                     outrel.r_offset, h ? h->dynindx : -1);
++
++            if (skip)
++              memset(&outrel, 0, sizeof(outrel));
++            else
++              {
++                avrh = (struct elf_avr32_link_hash_entry *)h;
++                /* h->dynindx may be -1 if this symbol was marked to
++                   become local.  */
++                if (h == NULL
++                    || ((info->symbolic || h->dynindx == -1)
++                        && h->def_regular))
++                  {
++                    relocate = TRUE;
++                    outrel.r_info = ELF32_R_INFO(0, R_AVR32_RELATIVE);
++                    outrel.r_addend = value + rel->r_addend;
++                    pr_debug("    ... R_AVR32_RELATIVE\n");
++                  }
++                else
++                  {
++                    BFD_ASSERT(h->dynindx != -1);
++                    relocate = TRUE;
++                    outrel.r_info = ELF32_R_INFO(h->dynindx, R_AVR32_GLOB_DAT);
++                    outrel.r_addend = rel->r_addend;
++                    pr_debug("    ... R_AVR32_GLOB_DAT\n");
++                  }
++              }
++
++            pr_debug("srelgot reloc_count: %d, size %lu\n",
++                     srelgot->reloc_count, srelgot->size);
++
++            loc = srelgot->contents;
++            loc += srelgot->reloc_count++ * sizeof(Elf32_External_Rela);
++            bfd_elf32_swap_reloca_out(output_bfd, &outrel, loc);
++
++            BFD_ASSERT(srelgot->reloc_count * sizeof(Elf32_External_Rela)
++                       <= srelgot->size);
++
++            if (!relocate)
++              continue;
++          }
++        break;
++      }
++
++      status = avr32_final_link_relocate(howto, input_bfd, input_section,
++                                       contents, rel, value);
++
++      switch (status)
++      {
++      case bfd_reloc_ok:
++        break;
++
++      case bfd_reloc_overflow:
++        {
++          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 (!((*info->callbacks->reloc_overflow)
++                (info, (h ? &h->root : NULL), name, howto->name,
++                 rel->r_addend, input_bfd, input_section, rel->r_offset)))
++            return FALSE;
++        }
++        break;
++
++      case bfd_reloc_outofrange:
++      default:
++        abort();
++      }
++    }
++
++  return TRUE;
++}
++
++
++/* Additional processing of dynamic sections after relocation */
++
++static bfd_boolean
++avr32_elf_finish_dynamic_symbol(bfd *output_bfd, struct bfd_link_info *info,
++                              struct elf_link_hash_entry *h,
++                              Elf_Internal_Sym *sym);
++static bfd_boolean
++avr32_elf_finish_dynamic_sections(bfd *output_bfd, struct bfd_link_info *info);
++
++
++/* (7) Initialize the contents of a dynamic symbol and/or emit
++   relocations for it */
++
++static bfd_boolean
++avr32_elf_finish_dynamic_symbol(bfd *output_bfd, struct bfd_link_info *info,
++                              struct elf_link_hash_entry *h,
++                              Elf_Internal_Sym *sym)
++{
++  struct elf_avr32_link_hash_table *htab;
++  struct got_entry *got;
++
++  pr_debug("(7) finish dynamic symbol: %s\n", h->root.root.string);
++
++  htab = avr32_elf_hash_table(info);
++  got = h->got.glist;
++
++  if (got && got->refcount > 0)
++    {
++      asection *sgot;
++      asection *srelgot;
++      Elf_Internal_Rela rel;
++      bfd_byte *loc;
++
++      /* This symbol has an entry in the GOT. Set it up. */
++      sgot = htab->sgot;
++      srelgot = htab->srelgot;
++      BFD_ASSERT(sgot && srelgot);
++
++      rel.r_offset = (sgot->output_section->vma
++                    + sgot->output_offset
++                    + got->offset);
++
++      /* If this is a static link, or it is a -Bsymbolic link and the
++       symbol is defined locally or was forced to be local because
++       of a version file, we just want to emit a RELATIVE reloc. The
++       entry in the global offset table will already have been
++       initialized in the relocate_section function. */
++      if ((info->shared
++         && !info->symbolic
++         && h->dynindx != -1)
++        || (htab->root.dynamic_sections_created
++            && h->def_dynamic
++            && !h->def_regular))
++      {
++        bfd_put_32(output_bfd, 0, sgot->contents + got->offset);
++        rel.r_info = ELF32_R_INFO(h->dynindx, R_AVR32_GLOB_DAT);
++        rel.r_addend = 0;
++
++        pr_debug("GOT reloc R_AVR32_GLOB_DAT, dynindx: %ld\n", h->dynindx);
++        pr_debug("    srelgot reloc_count: %d, size: %lu\n",
++                 srelgot->reloc_count, srelgot->size);
++
++        loc = (srelgot->contents
++               + srelgot->reloc_count++ * sizeof(Elf32_External_Rela));
++        bfd_elf32_swap_reloca_out(output_bfd, &rel, loc);
++
++        BFD_ASSERT(srelgot->reloc_count * sizeof(Elf32_External_Rela)
++                   <= srelgot->size);
++      }
++    }
++
++  /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute */
++  if (strcmp(h->root.root.string, "_DYNAMIC") == 0
++      || strcmp(h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
++    sym->st_shndx = SHN_ABS;
++
++  return TRUE;
++}
++
++/* (8) Do any remaining initialization of the dynamic sections */
++
++static bfd_boolean
++avr32_elf_finish_dynamic_sections(bfd *output_bfd, struct bfd_link_info *info)
++{
++  struct elf_avr32_link_hash_table *htab;
++  asection *sgot, *sdyn;
++
++  pr_debug("(8) finish dynamic sections\n");
++
++  htab = avr32_elf_hash_table(info);
++  sgot = htab->sgot;
++  sdyn = bfd_get_section_by_name(htab->root.dynobj, ".dynamic");
++
++  if (htab->root.dynamic_sections_created)
++    {
++      Elf32_External_Dyn *dyncon, *dynconend;
++
++      BFD_ASSERT(sdyn && sgot && sgot->size >= AVR32_GOT_HEADER_SIZE);
++
++      dyncon = (Elf32_External_Dyn *)sdyn->contents;
++      dynconend = (Elf32_External_Dyn *)(sdyn->contents + sdyn->size);
++      for (; dyncon < dynconend; dyncon++)
++      {
++        Elf_Internal_Dyn dyn;
++        asection *s;
++
++        bfd_elf32_swap_dyn_in(htab->root.dynobj, dyncon, &dyn);
++
++        switch (dyn.d_tag)
++          {
++          default:
++            break;
++
++          case DT_PLTGOT:
++            s = sgot->output_section;
++            BFD_ASSERT(s != NULL);
++            dyn.d_un.d_ptr = s->vma;
++            bfd_elf32_swap_dyn_out(output_bfd, &dyn, dyncon);
++            break;
++
++          case DT_AVR32_GOTSZ:
++            s = sgot->output_section;
++            BFD_ASSERT(s != NULL);
++            dyn.d_un.d_val = s->size;
++            bfd_elf32_swap_dyn_out(output_bfd, &dyn, dyncon);
++            break;
++          }
++      }
++
++      /* Fill in the first two entries in the global offset table */
++      bfd_put_32(output_bfd,
++               sdyn->output_section->vma + sdyn->output_offset,
++               sgot->contents);
++
++      /* The runtime linker will fill this one in with the address of
++       the run-time link map */
++      bfd_put_32(output_bfd, 0, sgot->contents + 4);
++    }
++
++  if (sgot)
++    elf_section_data(sgot->output_section)->this_hdr.sh_entsize = 4;
++
++  return TRUE;
++}
++
++
++/* AVR32-specific private ELF data */
++
++static bfd_boolean
++avr32_elf_set_private_flags(bfd *abfd, flagword flags);
++static bfd_boolean
++avr32_elf_copy_private_bfd_data(bfd *ibfd, bfd *obfd);
++static bfd_boolean
++avr32_elf_merge_private_bfd_data(bfd *ibfd, bfd *obfd);
++static bfd_boolean
++avr32_elf_print_private_bfd_data(bfd *abfd, void *ptr);
++
++static bfd_boolean
++avr32_elf_set_private_flags(bfd *abfd, flagword flags)
++{
++  elf_elfheader(abfd)->e_flags = flags;
++  elf_flags_init(abfd) = TRUE;
++
++  return TRUE;
++}
++
++/* Copy backend specific data from one object module to another.  */
++
++static bfd_boolean
++avr32_elf_copy_private_bfd_data(bfd *ibfd, bfd *obfd)
++{
++  elf_elfheader(obfd)->e_flags = elf_elfheader(ibfd)->e_flags;
++  return TRUE;
++}
++
++/* Merge backend specific data from an object file to the output
++   object file when linking.  */
++
++static bfd_boolean
++avr32_elf_merge_private_bfd_data(bfd *ibfd, bfd *obfd)
++{
++  flagword out_flags, in_flags;
++
++  pr_debug("(0) merge_private_bfd_data: %s -> %s\n",
++         ibfd->filename, obfd->filename);
++
++  in_flags = elf_elfheader(ibfd)->e_flags;
++  out_flags = elf_elfheader(obfd)->e_flags;
++
++  if (elf_flags_init(obfd))
++    {
++      /* If one of the inputs are non-PIC, the output must be
++       considered non-PIC.  The same applies to linkrelax.  */
++      if (!(in_flags & EF_AVR32_PIC))
++      out_flags &= ~EF_AVR32_PIC;
++      if (!(in_flags & EF_AVR32_LINKRELAX))
++      out_flags &= ~EF_AVR32_LINKRELAX;
++    }
++  else
++    {
++      elf_flags_init(obfd) = TRUE;
++      out_flags = in_flags;
++    }
++
++  elf_elfheader(obfd)->e_flags = out_flags;
++
++  return TRUE;
++}
++
++static bfd_boolean
++avr32_elf_print_private_bfd_data(bfd *abfd, void *ptr)
++{
++  FILE *file = (FILE *)ptr;
++  unsigned long flags;
++
++  BFD_ASSERT(abfd != NULL && ptr != NULL);
++
++  _bfd_elf_print_private_bfd_data(abfd, ptr);
++
++  flags = elf_elfheader(abfd)->e_flags;
++
++  fprintf(file, _("private flags = %lx:"), elf_elfheader(abfd)->e_flags);
++
++  if (flags & EF_AVR32_PIC)
++    fprintf(file, " [PIC]");
++  if (flags & EF_AVR32_LINKRELAX)
++    fprintf(file, " [linker relaxable]");
++
++  flags &= ~(EF_AVR32_PIC | EF_AVR32_LINKRELAX);
++
++  if (flags)
++    fprintf(file, _("<Unrecognized flag bits set>"));
++
++  fputc('\n', file);
++
++  return TRUE;
++}
++
++/* Set avr32-specific linker options.  */
++void bfd_elf32_avr32_set_options(struct bfd_link_info *info,
++                               int direct_data_refs)
++{
++  struct elf_avr32_link_hash_table *htab;
++
++  htab = avr32_elf_hash_table (info);
++  htab->direct_data_refs = !!direct_data_refs;
++}
++
++
++
++/* Understanding core dumps */
++
++static bfd_boolean
++avr32_elf_grok_prstatus(bfd *abfd, Elf_Internal_Note *note);
++static bfd_boolean
++avr32_elf_grok_psinfo(bfd *abfd, Elf_Internal_Note *note);
++
++static bfd_boolean
++avr32_elf_grok_prstatus(bfd *abfd, Elf_Internal_Note *note)
++{
++  /* Linux/AVR32B elf_prstatus */
++  if (note->descsz != 148)
++    return FALSE;
++
++  /* pr_cursig */
++  elf_tdata(abfd)->core_signal = bfd_get_16(abfd, note->descdata + 12);
++
++  /* pr_pid */
++  elf_tdata(abfd)->core_pid = bfd_get_32(abfd, note->descdata + 24);
++
++  /* Make a ".reg/999" section for pr_reg. The size is for 16
++     general-purpose registers, SR and r12_orig (18 * 4 = 72).  */
++  return _bfd_elfcore_make_pseudosection(abfd, ".reg", 72,
++                                       note->descpos + 72);
++}
++
++static bfd_boolean
++avr32_elf_grok_psinfo(bfd *abfd, Elf_Internal_Note *note)
++{
++  /* Linux/AVR32B elf_prpsinfo */
++  if (note->descsz != 128)
++    return FALSE;
++
++  elf_tdata(abfd)->core_program
++    = _bfd_elfcore_strndup(abfd, note->descdata + 32, 16);
++  elf_tdata(abfd)->core_command
++    = _bfd_elfcore_strndup(abfd, note->descdata + 48, 80);
++
++  /* Note that for some reason, a spurious space is tacked
++     onto the end of the args in some (at least one anyway)
++     implementations, so strip it off if it exists.  */
++
++  {
++    char *command = elf_tdata (abfd)->core_command;
++    int n = strlen (command);
++
++    if (0 < n && command[n - 1] == ' ')
++      command[n - 1] = '\0';
++  }
++
++  return TRUE;
++}
++
++
++#define ELF_ARCH                      bfd_arch_avr32
++#define ELF_MACHINE_CODE              EM_AVR32
++#define ELF_MAXPAGESIZE                       1024
++
++#define TARGET_BIG_SYM                        bfd_elf32_avr32_vec
++#define TARGET_BIG_NAME                       "elf32-avr32"
++
++#define elf_backend_grok_prstatus     avr32_elf_grok_prstatus
++#define elf_backend_grok_psinfo               avr32_elf_grok_psinfo
++
++/* Only RELA relocations are used */
++#define elf_backend_may_use_rel_p     0
++#define elf_backend_may_use_rela_p    1
++#define elf_backend_default_use_rela_p        1
++#define elf_backend_rela_normal               1
++#define elf_info_to_howto_rel         NULL
++#define elf_info_to_howto             avr32_info_to_howto
++
++#define bfd_elf32_bfd_copy_private_bfd_data   avr32_elf_copy_private_bfd_data
++#define bfd_elf32_bfd_merge_private_bfd_data  avr32_elf_merge_private_bfd_data
++#define bfd_elf32_bfd_set_private_flags               avr32_elf_set_private_flags
++#define bfd_elf32_bfd_print_private_bfd_data  avr32_elf_print_private_bfd_data
++#define bfd_elf32_new_section_hook            avr32_elf_new_section_hook
++
++#define elf_backend_gc_mark_hook              avr32_elf_gc_mark_hook
++#define elf_backend_gc_sweep_hook             avr32_elf_gc_sweep_hook
++#define elf_backend_relocate_section  avr32_elf_relocate_section
++#define elf_backend_copy_indirect_symbol avr32_elf_copy_indirect_symbol
++#define elf_backend_create_dynamic_sections avr32_elf_create_dynamic_sections
++#define bfd_elf32_bfd_link_hash_table_create avr32_elf_link_hash_table_create
++#define elf_backend_adjust_dynamic_symbol avr32_elf_adjust_dynamic_symbol
++#define elf_backend_size_dynamic_sections avr32_elf_size_dynamic_sections
++#define elf_backend_finish_dynamic_symbol avr32_elf_finish_dynamic_symbol
++#define elf_backend_finish_dynamic_sections avr32_elf_finish_dynamic_sections
++
++#define bfd_elf32_bfd_relax_section   avr32_elf_relax_section
++
++/* Find out which symbols need an entry in .got. */
++#define elf_backend_check_relocs      avr32_check_relocs
++#define elf_backend_can_refcount      1
++#define elf_backend_can_gc_sections   1
++#define elf_backend_plt_readonly      1
++#define elf_backend_plt_not_loaded    1
++#define elf_backend_want_plt_sym      0
++#define elf_backend_plt_alignment     2
++#define elf_backend_want_dynbss               0
++#define elf_backend_want_got_plt      0
++#define elf_backend_want_got_sym      1
++#define elf_backend_got_header_size   AVR32_GOT_HEADER_SIZE
++
++#include "elf32-target.h"
+--- /dev/null
++++ b/bfd/elf32-avr32.h
+@@ -0,0 +1,23 @@
++/* AVR32-specific support for 32-bit ELF.
++   Copyright 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. */
++
++void bfd_elf32_avr32_set_options(struct bfd_link_info *info,
++                               int direct_data_refs);
+--- a/bfd/elf-bfd.h
++++ b/bfd/elf-bfd.h
+@@ -1553,6 +1553,10 @@ struct elf_obj_tdata
+      find_nearest_line.  */
+   struct mips_elf_find_line *find_line_info;
++  /* Used by AVR32 ELF relaxation code.  Contains an array of pointers
++     for each local symbol to the fragment where it is defined.  */
++  struct fragment **local_sym_frag;
++
+   /* A place to stash dwarf1 info for this bfd.  */
+   struct dwarf1_debug *dwarf1_find_line_info;
+--- a/bfd/libbfd.h
++++ b/bfd/libbfd.h
+@@ -1783,6 +1783,48 @@ static const char *const bfd_reloc_code_
+   "BFD_RELOC_AVR_LDI",
+   "BFD_RELOC_AVR_6",
+   "BFD_RELOC_AVR_6_ADIW",
++  "BFD_RELOC_AVR32_DIFF32",
++  "BFD_RELOC_AVR32_DIFF16",
++  "BFD_RELOC_AVR32_DIFF8",
++  "BFD_RELOC_AVR32_GOT32",
++  "BFD_RELOC_AVR32_GOT16",
++  "BFD_RELOC_AVR32_GOT8",
++  "BFD_RELOC_AVR32_21S",
++  "BFD_RELOC_AVR32_16U",
++  "BFD_RELOC_AVR32_16S",
++  "BFD_RELOC_AVR32_SUB5",
++  "BFD_RELOC_AVR32_8S_EXT",
++  "BFD_RELOC_AVR32_8S",
++  "BFD_RELOC_AVR32_15S",
++  "BFD_RELOC_AVR32_22H_PCREL",
++  "BFD_RELOC_AVR32_18W_PCREL",
++  "BFD_RELOC_AVR32_16B_PCREL",
++  "BFD_RELOC_AVR32_16N_PCREL",
++  "BFD_RELOC_AVR32_14UW_PCREL",
++  "BFD_RELOC_AVR32_11H_PCREL",
++  "BFD_RELOC_AVR32_10UW_PCREL",
++  "BFD_RELOC_AVR32_9H_PCREL",
++  "BFD_RELOC_AVR32_9UW_PCREL",
++  "BFD_RELOC_AVR32_GOTPC",
++  "BFD_RELOC_AVR32_GOTCALL",
++  "BFD_RELOC_AVR32_LDA_GOT",
++  "BFD_RELOC_AVR32_GOT21S",
++  "BFD_RELOC_AVR32_GOT18SW",
++  "BFD_RELOC_AVR32_GOT16S",
++  "BFD_RELOC_AVR32_32_CPENT",
++  "BFD_RELOC_AVR32_CPCALL",
++  "BFD_RELOC_AVR32_16_CP",
++  "BFD_RELOC_AVR32_9W_CP",
++  "BFD_RELOC_AVR32_ALIGN",
++  "BFD_RELOC_AVR32_14UW",
++  "BFD_RELOC_AVR32_10UW",
++  "BFD_RELOC_AVR32_10SW",
++  "BFD_RELOC_AVR32_STHH_W",
++  "BFD_RELOC_AVR32_7UW",
++  "BFD_RELOC_AVR32_6S",
++  "BFD_RELOC_AVR32_6UW",
++  "BFD_RELOC_AVR32_4UH",
++  "BFD_RELOC_AVR32_3U",
+   "BFD_RELOC_RX_NEG8",
+   "BFD_RELOC_RX_NEG16",
+   "BFD_RELOC_RX_NEG24",
+--- a/bfd/Makefile.am
++++ b/bfd/Makefile.am
+@@ -75,6 +75,7 @@ ALL_MACHINES = \
+       cpu-arc.lo \
+       cpu-arm.lo \
+       cpu-avr.lo \
++      cpu-avr32.lo \
+       cpu-bfin.lo \
+       cpu-cr16.lo \
+       cpu-cr16c.lo \
+@@ -272,6 +273,7 @@ BFD32_BACKENDS = \
+       elf32-arc.lo \
+       elf32-arm.lo \
+       elf32-avr.lo \
++      elf32-avr32.lo \
+       elf32-bfin.lo \
+       elf32-cr16.lo \
+       elf32-cr16c.lo \
+--- a/bfd/reloc.c
++++ b/bfd/reloc.c
+@@ -4275,6 +4275,131 @@ ENUMDOC
+   Renesas RX Relocations.
+ ENUM
++  BFD_RELOC_AVR32_DIFF32
++ENUMX
++  BFD_RELOC_AVR32_DIFF16
++ENUMX
++  BFD_RELOC_AVR32_DIFF8
++ENUMDOC
++  Difference between two labels: L2 - L1. The value of L1 is encoded
++  as sym + addend, while the initial difference after assembly is
++  inserted into the object file by the assembler.
++ENUM
++  BFD_RELOC_AVR32_GOT32
++ENUMX
++  BFD_RELOC_AVR32_GOT16
++ENUMX
++  BFD_RELOC_AVR32_GOT8
++ENUMDOC
++  Reference to a symbol through the Global Offset Table. The linker
++  will allocate an entry for symbol in the GOT and insert the offset
++  of this entry as the relocation value.
++ENUM
++  BFD_RELOC_AVR32_21S
++ENUMX
++  BFD_RELOC_AVR32_16U
++ENUMX
++  BFD_RELOC_AVR32_16S
++ENUMX
++  BFD_RELOC_AVR32_SUB5
++ENUMX
++  BFD_RELOC_AVR32_8S_EXT
++ENUMX
++  BFD_RELOC_AVR32_8S
++ENUMX
++  BFD_RELOC_AVR32_15S
++ENUMDOC
++  Normal (non-pc-relative) code relocations. Alignment and signedness
++  is indicated by the suffixes. S means signed, U means unsigned. W
++  means word-aligned, H means halfword-aligned, neither means
++  byte-aligned (no alignment.) SUB5 is the same relocation as 16S.
++ENUM
++  BFD_RELOC_AVR32_22H_PCREL
++ENUMX
++  BFD_RELOC_AVR32_18W_PCREL
++ENUMX
++  BFD_RELOC_AVR32_16B_PCREL
++ENUMX
++  BFD_RELOC_AVR32_16N_PCREL
++ENUMX
++  BFD_RELOC_AVR32_14UW_PCREL
++ENUMX
++  BFD_RELOC_AVR32_11H_PCREL
++ENUMX
++  BFD_RELOC_AVR32_10UW_PCREL
++ENUMX
++  BFD_RELOC_AVR32_9H_PCREL
++ENUMX
++  BFD_RELOC_AVR32_9UW_PCREL
++ENUMDOC
++  PC-relative relocations are signed if neither 'U' nor 'S' is
++  specified. However, we explicitly tack on a 'B' to indicate no
++  alignment, to avoid confusion with data relocs. All of these resolve
++  to sym + addend - offset, except the one with 'N' (negated) suffix.
++  This particular one resolves to offset - sym - addend.
++ENUM
++  BFD_RELOC_AVR32_GOTPC
++ENUMDOC
++  Subtract the link-time address of the GOT from (symbol + addend)
++  and insert the result.
++ENUM
++  BFD_RELOC_AVR32_GOTCALL
++ENUMX
++  BFD_RELOC_AVR32_LDA_GOT
++ENUMX
++  BFD_RELOC_AVR32_GOT21S
++ENUMX
++  BFD_RELOC_AVR32_GOT18SW
++ENUMX
++  BFD_RELOC_AVR32_GOT16S
++ENUMDOC
++  Reference to a symbol through the GOT. The linker will allocate an
++  entry for symbol in the GOT and insert the offset of this entry as
++  the relocation value. addend must be zero. As usual, 'S' means
++  signed, 'W' means word-aligned, etc.
++ENUM
++  BFD_RELOC_AVR32_32_CPENT
++ENUMDOC
++  32-bit constant pool entry. I don't think 8- and 16-bit entries make
++  a whole lot of sense.
++ENUM
++  BFD_RELOC_AVR32_CPCALL
++ENUMX
++  BFD_RELOC_AVR32_16_CP
++ENUMX
++  BFD_RELOC_AVR32_9W_CP
++ENUMDOC
++  Constant pool references. Some of these relocations are signed,
++  others are unsigned. It doesn't really matter, since the constant
++  pool always comes after the code that references it.
++ENUM
++  BFD_RELOC_AVR32_ALIGN
++ENUMDOC
++  sym must be the absolute symbol. The addend specifies the alignment
++  order, e.g. if addend is 2, the linker must add padding so that the
++  next address is aligned to a 4-byte boundary.
++ENUM
++  BFD_RELOC_AVR32_14UW
++ENUMX
++  BFD_RELOC_AVR32_10UW
++ENUMX
++  BFD_RELOC_AVR32_10SW
++ENUMX
++  BFD_RELOC_AVR32_STHH_W
++ENUMX
++  BFD_RELOC_AVR32_7UW
++ENUMX
++  BFD_RELOC_AVR32_6S
++ENUMX
++  BFD_RELOC_AVR32_6UW
++ENUMX
++  BFD_RELOC_AVR32_4UH
++ENUMX
++  BFD_RELOC_AVR32_3U
++ENUMDOC
++  Code relocations that will never make it to the output file.
++
++ENUM
+   BFD_RELOC_390_12
+ ENUMDOC
+    Direct 12 bit.
+--- a/bfd/targets.c
++++ b/bfd/targets.c
+@@ -579,6 +579,7 @@ extern const bfd_target b_out_vec_big_ho
+ extern const bfd_target b_out_vec_little_host;
+ extern const bfd_target bfd_pei_ia64_vec;
+ extern const bfd_target bfd_elf32_avr_vec;
++extern const bfd_target bfd_elf32_avr32_vec;
+ extern const bfd_target bfd_elf32_bfin_vec;
+ extern const bfd_target bfd_elf32_bfinfdpic_vec;
+ extern const bfd_target bfd_elf32_big_generic_vec;
+@@ -917,6 +918,7 @@ static const bfd_target * const _bfd_tar
+       &bfd_pei_ia64_vec,
+ #endif
+       &bfd_elf32_avr_vec,
++      &bfd_elf32_avr32_vec,
+       &bfd_elf32_bfin_vec,
+       &bfd_elf32_bfinfdpic_vec,
+--- a/binutils/doc/binutils.info
++++ b/binutils/doc/binutils.info
+@@ -1705,6 +1705,10 @@ equivalent.  At least one option from th
+      useful when attempting to disassemble thumb code produced by other
+      compilers.
++     For the AVR32 architectures that support Floating point unit (FPU),
++     specifying '-M decode-fpu' will enable disassembler to print the 
++     floating point instruction instead of 'cop' instructions.
++
+      For the x86, some of the options duplicate functions of the `-m'
+      switch, but allow finer grained control.  Multiple selections from
+      the following may be specified as a comma separated string.
+--- a/binutils/doc/binutils.texi
++++ b/binutils/doc/binutils.texi
+@@ -1980,6 +1980,10 @@ using the switch @option{--disassembler-
+ useful when attempting to disassemble thumb code produced by other
+ compilers.
++For the AVR32 architectures that support Floating point unit (FPU), 
++specifying @option{-M decode-fpu} will enable disassembler to print the
++floating point instructions instead of 'cop' instructions. 
++
+ For the x86, some of the options duplicate functions of the @option{-m}
+ switch, but allow finer grained control.  Multiple selections from the
+ following may be specified as a comma separated string.
+--- a/binutils/doc/objdump.1
++++ b/binutils/doc/objdump.1
+@@ -425,6 +425,10 @@ using the switch \fB\-\-disassembler\-op
+ useful when attempting to disassemble thumb code produced by other
+ compilers.
+ .Sp
++For the \s-1AVR32\s0 architectures that support Floating point unit (FPU),
++specifying \fB\-M decode\-fpu\fR will enable disassembler to print the
++floating point instructions instead of 'cop' instructions.
++.Sp
+ For the x86, some of the options duplicate functions of the \fB\-m\fR
+ switch, but allow finer grained control.  Multiple selections from the
+ following may be specified as a comma separated string.
+--- a/binutils/readelf.c
++++ b/binutils/readelf.c
+@@ -95,6 +95,7 @@
+ #include "elf/arc.h"
+ #include "elf/arm.h"
+ #include "elf/avr.h"
++#include "elf/avr32.h"
+ #include "elf/bfin.h"
+ #include "elf/cr16.h"
+ #include "elf/cris.h"
+@@ -619,6 +620,7 @@ guess_is_rela (unsigned int e_machine)
+     case EM_ALPHA:
+     case EM_ALTERA_NIOS2:
+     case EM_AVR:
++    case EM_AVR32:
+     case EM_AVR_OLD:
+     case EM_BLACKFIN:
+     case EM_CR16:
+@@ -1072,6 +1074,10 @@ dump_relocations (FILE * file,
+         rtype = elf_avr_reloc_type (type);
+         break;
++      case EM_AVR32:
++        rtype = elf_avr32_reloc_type (type);
++        break;
++
+       case EM_OLD_SPARCV9:
+       case EM_SPARC32PLUS:
+       case EM_SPARCV9:
+--- a/gas/as.c
++++ b/gas/as.c
+@@ -459,10 +459,10 @@ parse_args (int * pargc, char *** pargv)
+        the end of the preceeding line so that it is simpler to
+        selectively add and remove lines from this list.  */
+     {"alternate", no_argument, NULL, OPTION_ALTERNATE}
+-    /* The entry for "a" is here to prevent getopt_long_only() from
+-       considering that -a is an abbreviation for --alternate.  This is
+-       necessary because -a=<FILE> is a valid switch but getopt would
+-       normally reject it since --alternate does not take an argument.  */
++    /* The next two entries are here to prevent getopt_long_only() from
++       considering that -a or -al is an abbreviation for --alternate.
++       This is necessary because -a=<FILE> is a valid switch but getopt
++       would normally reject it since --alternate does not take an argument.  */
+     ,{"a", optional_argument, NULL, 'a'}
+     /* Handle -al=<FILE>.  */
+     ,{"al", optional_argument, NULL, OPTION_AL}
+@@ -839,8 +839,15 @@ This program has absolutely no warranty.
+       case 'a':
+         if (optarg)
+           {
+-            if (optarg != old_argv[optind] && optarg[-1] == '=')
++            /* If optarg is part of the -a switch and not a separate argument
++               in its own right, then scan backwards to the just after the -a.
++               This means skipping over both '=' and 'l' which might have been
++               taken to be part of the -a switch itself.  */
++            if (optarg != old_argv[optind])
++              {
++                while (optarg[-1] == '=' || optarg[-1] == 'l')
+               --optarg;
++              }
+             if (md_parse_option (optc, optarg) != 0)
+               break;
+--- a/gas/as.h
++++ b/gas/as.h
+@@ -82,6 +82,7 @@
+ #endif
+ #define gas_assert(P) \
+   ((void) ((P) ? 0 : (as_assert (__FILE__, __LINE__, __PRETTY_FUNCTION__), 0)))
++#define assert(P)   gas_assert(P)
+ #undef abort
+ #define abort()               as_abort (__FILE__, __LINE__, __PRETTY_FUNCTION__)
+--- a/gas/atof-generic.c
++++ b/gas/atof-generic.c
+@@ -121,6 +121,21 @@ atof_generic (/* return pointer to just
+   switch (first_digit[0])
+     {
++    case 's':
++    case 'S':
++    case 'q':
++    case 'Q':
++      if (!strncasecmp ("nan", first_digit+1, 3))
++      {
++        address_of_generic_floating_point_number->sign = 0;
++        address_of_generic_floating_point_number->exponent = 0;
++        address_of_generic_floating_point_number->leader =
++          address_of_generic_floating_point_number->low;
++        *address_of_string_pointer = first_digit + 4;
++        return 0;
++      }
++      break;
++
+     case 'n':
+     case 'N':
+       if (!strncasecmp ("nan", first_digit, 3))
+--- a/gas/config/atof-vax.c
++++ b/gas/config/atof-vax.c
+@@ -268,9 +268,27 @@ flonum_gen2vax (int format_letter,        /* On
+         int exponent_skippage;
+         LITTLENUM_TYPE word1;
+-        /* JF: Deal with new Nan, +Inf and -Inf codes.  */
++        /* JF: Deal with new +/-(q/Q/s/S)Nan, +Inf and -Inf codes.  */
+         if (f->sign != '-' && f->sign != '+')
+           {
++          if (f->sign == 0)
++            {
++              /* All NaNs are 0.  */
++              memset (words, 0x00, sizeof (LITTLENUM_TYPE) * precision);
++            }
++          else if (f->sign == 'P')
++            {
++              /* Positive Infinity.  */
++              memset (words, 0xff, sizeof (LITTLENUM_TYPE) * precision);
++              words[0] &= 0x7fff;
++            }
++          else if (f->sign == 'N')
++            {
++              /* Negative Infinity.  */
++              memset (words, 0x00, sizeof (LITTLENUM_TYPE) * precision);
++              words[0] = 0x0080;
++            }
++          else
+             make_invalid_floating_point_number (words);
+             return return_value;
+           }
+--- /dev/null
++++ b/gas/config/tc-avr32.c
+@@ -0,0 +1,4839 @@
++/* Assembler implementation for AVR32.
++   Copyright 2003,2004,2005,2006,2007,2008,2009,2010 Atmel Corporation.
++
++   Written by Haavard Skinnemoen, Atmel Norway, <hskinnemoen@atmel.com>
++
++   This file is part of GAS, the GNU Assembler.
++
++   GAS 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, or (at your option)
++   any later version.
++
++   GAS 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 GAS; see the file COPYING.  If not, write to the Free
++   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
++   02111-1307, USA.  */
++
++#include <stdio.h>
++#include "as.h"
++#include "safe-ctype.h"
++#include "subsegs.h"
++#include "symcat.h"
++#include "opcodes/avr32-opc.h"
++#include "opcodes/avr32-asm.h"
++#include "elf/avr32.h"
++#include "dwarf2dbg.h"
++
++#define xDEBUG
++#define xOPC_CONSISTENCY_CHECK
++
++#ifdef DEBUG
++# define pr_debug(fmt, args...) fprintf(stderr, fmt, ##args)
++#else
++# define pr_debug(fmt, args...)
++#endif
++
++/* 3 MSB of instruction word indicate group. Group 7 -> extended */
++#define AVR32_COMPACT_P(opcode) ((opcode[0] & 0xe0) != 0xe0)
++
++#define streq(a, b)           (strcmp(a, b) == 0)
++#define skip_whitespace(str)  do { while(*(str) == ' ') ++(str); } while(0)
++
++/* Flags given on the command line */
++static int avr32_pic  = FALSE;
++int linkrelax = FALSE;
++int avr32_iarcompat   = FALSE;
++
++/* This array holds the chars that always start a comment. */
++const char comment_chars[]            = "#";
++
++/* This array holds the chars that only start a comment at the
++   beginning of a line.  We must include '#' here because the compiler
++   may produce #APP and #NO_APP in its output.  */
++const char line_comment_chars[]               = "#";
++
++/* These may be used instead of newline (same as ';' in C).  */
++const char line_separator_chars[]     = ";";
++
++/* Chars that can be used to separate mantissa from exponent in
++   floating point numbers.  */
++const char EXP_CHARS[]                        = "eE";
++
++/* Chars that mean this number is a floating point constant.  */
++const char FLT_CHARS[]                        = "dD";
++
++/* Pre-defined "_GLOBAL_OFFSET_TABLE_"  */
++symbolS *GOT_symbol;
++
++static struct hash_control *avr32_mnemonic_htab;
++
++struct avr32_ifield_data
++{
++  bfd_vma value;
++  /* FIXME: Get rid of align_order and complain. complain is never
++     used, align_order is used in one place.  Try to use the relax
++     table instead.  */
++  unsigned int align_order;
++};
++
++struct avr32_insn
++{
++  const struct avr32_syntax *syntax;
++  expressionS immediate;
++  int pcrel;
++  int force_extended;
++  unsigned int next_slot;
++  bfd_reloc_code_real_type r_type;
++  struct avr32_ifield_data field_value[AVR32_MAX_FIELDS];
++};
++
++static struct avr32_insn current_insn;
++
++/* The target specific pseudo-ops we support. */
++static void s_rseg (int);
++static void s_cpool(int);
++
++const pseudo_typeS md_pseudo_table[] =
++{
++  /* Make sure that .word is 32 bits */
++  { "word", cons, 4 },
++  { "file", (void (*) PARAMS ((int))) dwarf2_directive_file, 0 },
++  { "loc", dwarf2_directive_loc, 0 },
++
++  /* .lcomm requires an explicit alignment parameter */
++  { "lcomm", s_lcomm, 1 },
++
++  /* AVR32-specific pseudo-ops */
++  { "cpool", s_cpool, 0},
++
++  /* IAR compatible pseudo-ops */
++  { "program", s_ignore, 0 },
++  { "public", s_globl, 0 },
++  { "extern", s_ignore, 0 },
++  { "module", s_ignore, 0 },
++  { "rseg", s_rseg, 0 },
++  { "dc8", cons, 1 },
++  { "dc16", cons, 2 },
++  { "dc32", cons, 4 },
++
++  { NULL, NULL, 0 }
++};
++
++/* Questionable stuff starts here */
++
++enum avr32_opinfo {
++  AVR32_OPINFO_NONE = BFD_RELOC_NONE,
++  AVR32_OPINFO_GOT,
++  AVR32_OPINFO_TLSGD,
++  AVR32_OPINFO_HI,
++  AVR32_OPINFO_LO,
++};
++
++enum avr32_arch {
++  ARCH_TYPE_AP,
++  ARCH_TYPE_UCR1,
++  ARCH_TYPE_UCR2,
++  ARCH_TYPE_UCR3,
++  ARCH_TYPE_UCR3FP
++};
++
++struct arch_type_s
++{
++  /* Architecture name */
++  char *name;
++  /* Instruction Set Architecture Flags */
++  unsigned long isa_flags;
++};
++
++struct part_type_s
++{
++  /* Part name */
++  char *name;
++  /* Architecture type */
++  unsigned int arch;
++};
++
++static struct arch_type_s arch_types[] =
++{
++    {"ap", AVR32_V1 | AVR32_SIMD | AVR32_DSP | AVR32_PICO},
++    {"ucr1", AVR32_V1 | AVR32_DSP | AVR32_RMW},
++    {"ucr2", AVR32_V1 | AVR32_V2 | AVR32_DSP | AVR32_RMW},
++    {"ucr3", AVR32_V1 | AVR32_V2 | AVR32_V3 | AVR32_DSP | AVR32_RMW},
++    {"ucr3fp", AVR32_V1 | AVR32_V2 | AVR32_V3 | AVR32_DSP | AVR32_RMW | AVR32_V3FP},
++    {"all-insn", AVR32_V1 | AVR32_V2 | AVR32_V3 | AVR32_SIMD | AVR32_DSP | AVR32_RMW | AVR32_V3FP | AVR32_PICO},
++    {NULL, 0}
++};
++
++static struct part_type_s part_types[] =
++{
++    {"ap7000",        ARCH_TYPE_AP},
++    {"ap7001",        ARCH_TYPE_AP},
++    {"ap7002",        ARCH_TYPE_AP},
++    {"ap7200",        ARCH_TYPE_AP},
++    {"uc3a0128",      ARCH_TYPE_UCR2},
++    {"uc3a0256",      ARCH_TYPE_UCR2},
++    {"uc3a0512es",    ARCH_TYPE_UCR1},
++    {"uc3a0512",      ARCH_TYPE_UCR2},
++    {"uc3a1128",      ARCH_TYPE_UCR2},
++    {"uc3a1256es",    ARCH_TYPE_UCR1},
++    {"uc3a1256",      ARCH_TYPE_UCR2},
++    {"uc3a1512es",    ARCH_TYPE_UCR1},
++    {"uc3a1512",      ARCH_TYPE_UCR2},
++    {"uc3a364",       ARCH_TYPE_UCR2},
++    {"uc3a364s",      ARCH_TYPE_UCR2},
++    {"uc3a3128",      ARCH_TYPE_UCR2},
++    {"uc3a3128s",     ARCH_TYPE_UCR2},
++    {"uc3a3256",      ARCH_TYPE_UCR2},
++    {"uc3a3256s",     ARCH_TYPE_UCR2},
++    {"uc3b064",       ARCH_TYPE_UCR1},
++    {"uc3b0128",      ARCH_TYPE_UCR1},
++    {"uc3b0256es",    ARCH_TYPE_UCR1},
++    {"uc3b0256",      ARCH_TYPE_UCR1},
++    {"uc3b0512",      ARCH_TYPE_UCR2},
++    {"uc3b0512revc",  ARCH_TYPE_UCR2},
++    {"uc3b164",       ARCH_TYPE_UCR1},
++    {"uc3b1128",      ARCH_TYPE_UCR1},
++    {"uc3b1256",      ARCH_TYPE_UCR1},
++    {"uc3b1256es",    ARCH_TYPE_UCR1},
++    {"uc3b1512",      ARCH_TYPE_UCR2},
++    {"uc3b1512revc",  ARCH_TYPE_UCR2},
++    {"uc3c0512crevc", ARCH_TYPE_UCR3},
++    {"uc3c1512crevc", ARCH_TYPE_UCR3},
++    {"uc3c2512crevc", ARCH_TYPE_UCR3},
++    {"atuc3l0256",    ARCH_TYPE_UCR3},
++    {"mxt768e",       ARCH_TYPE_UCR3},
++    {"uc3l064",       ARCH_TYPE_UCR3},
++    {"uc3l032",       ARCH_TYPE_UCR3},
++    {"uc3l016",       ARCH_TYPE_UCR3},
++    {"uc3l064revb",   ARCH_TYPE_UCR3},
++    {"uc3c064c",  ARCH_TYPE_UCR3FP},
++    {"uc3c0128c",   ARCH_TYPE_UCR3FP},
++    {"uc3c0256c",   ARCH_TYPE_UCR3FP},
++    {"uc3c0512c",   ARCH_TYPE_UCR3FP},
++    {"uc3c164c",  ARCH_TYPE_UCR3FP},
++    {"uc3c1128c",   ARCH_TYPE_UCR3FP},
++    {"uc3c1256c",   ARCH_TYPE_UCR3FP},
++    {"uc3c1512c",   ARCH_TYPE_UCR3FP},
++    {"uc3c264c",  ARCH_TYPE_UCR3FP},
++    {"uc3c2128c",   ARCH_TYPE_UCR3FP},
++    {"uc3c2256c",   ARCH_TYPE_UCR3FP},
++    {"uc3c2512c",   ARCH_TYPE_UCR3FP},
++    {NULL, 0}
++};
++
++/* Current architecture type.  */
++static struct arch_type_s default_arch = {"all-insn", AVR32_V1 | AVR32_V2 | AVR32_V3 | AVR32_SIMD | AVR32_DSP | AVR32_RMW | AVR32_V3FP | AVR32_PICO };
++static struct arch_type_s *avr32_arch = &default_arch;
++
++/* Display nicely formatted list of known part- and architecture names.  */
++
++static void
++show_arch_list (FILE *stream)
++{
++  int i, x;
++
++  fprintf (stream, _("Known architecture names:"));
++  x = 1000;
++
++  for (i = 0; arch_types[i].name; i++)
++    {
++      int len = strlen (arch_types[i].name);
++
++      x += len + 1;
++
++      if (x < 75)
++      fprintf (stream, " %s", arch_types[i].name);
++      else
++      {
++        fprintf (stream, "\n  %s", arch_types[i].name);
++        x = len + 2;
++      }
++    }
++
++  fprintf (stream, "\n");
++}
++
++static void
++show_part_list (FILE *stream)
++{
++  int i, x;
++
++  fprintf (stream, _("Known part names:"));
++  x = 1000;
++
++  for (i = 0; part_types[i].name; i++)
++    {
++      int len = strlen(part_types[i].name);
++
++      x += len + 1;
++
++      if (x < 75)
++      fprintf (stream, " %s", part_types[i].name);
++      else
++      {
++        fprintf(stream, "\n  %s", part_types[i].name);
++        x = len + 2;
++      }
++    }
++
++  fprintf (stream, "\n");
++}
++
++const char *md_shortopts = "";
++struct option md_longopts[] =
++{
++#define OPTION_ARCH           (OPTION_MD_BASE)
++#define OPTION_PART           (OPTION_ARCH + 1)
++#define OPTION_IAR            (OPTION_PART + 1)
++#define OPTION_PIC            (OPTION_IAR + 1)
++#define OPTION_NOPIC          (OPTION_PIC + 1)
++#define OPTION_LINKRELAX      (OPTION_NOPIC + 1)
++#define OPTION_NOLINKRELAX    (OPTION_LINKRELAX + 1)
++#define OPTION_DIRECT_DATA_REFS (OPTION_NOLINKRELAX + 1)
++  {"march",           required_argument, NULL, OPTION_ARCH},
++  {"mpart",           required_argument, NULL, OPTION_PART},
++  {"iar",             no_argument, NULL, OPTION_IAR},
++  {"pic",             no_argument, NULL, OPTION_PIC},
++  {"no-pic",          no_argument, NULL, OPTION_NOPIC},
++  {"linkrelax",               no_argument, NULL, OPTION_LINKRELAX},
++  {"no-linkrelax",    no_argument, NULL, OPTION_NOLINKRELAX},
++  /* deprecated alias for -mpart=xxx */
++  {"mcpu",            required_argument, NULL, OPTION_PART},
++  {NULL,              no_argument, NULL, 0}
++};
++
++size_t md_longopts_size = sizeof (md_longopts);
++
++void
++md_show_usage (FILE *stream)
++{
++  fprintf (stream, _("\
++AVR32 options:\n\
++  -march=[arch-name]      Select cpu architecture. [Default `all-insn']\n\
++  -mpart=[part-name]      Select specific part. [Default `none']\n\
++  --pic                   Produce Position-Independent Code\n\
++  --no-pic                Don't produce Position-Independent Code\n\
++  --linkrelax             Produce output suitable for linker relaxing\n\
++  --no-linkrelax          Don't produce output suitable for linker relaxing\n"));
++  show_arch_list(stream);
++}
++
++int
++md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
++{
++  switch (c)
++    {
++    case OPTION_ARCH:
++      {
++      int i;
++      char *s = alloca (strlen (arg) + 1);
++
++      {
++        char *t = s;
++        char *arg1 = arg;
++
++        do
++          *t = TOLOWER (*arg1++);
++        while (*t++);
++      }
++
++        /* Add backward compability */
++        if (strcmp ("uc", s)== 0)
++          {
++            as_warn("Deprecated arch `%s' specified. "
++                    "Please use '-march=ucr1' instead. "
++                    "Converting to arch 'ucr1'\n",
++                     s);
++            s="ucr1";
++          }
++
++      for (i = 0; arch_types[i].name; ++i)
++        if (strcmp (arch_types[i].name, s) == 0)
++          break;
++
++      if (!arch_types[i].name)
++        {
++          show_arch_list (stderr);
++          as_fatal (_("unknown architecture: %s\n"), arg);
++        }
++
++        avr32_arch = &arch_types[i];
++      break;
++      }
++    case OPTION_PART:
++      {
++      int i;
++      char *s = alloca (strlen (arg) + 1);
++      char *t = s;
++      char *p = arg;
++
++      /* If arch type has already been set, don't bother.
++         -march= always overrides -mpart=  */
++      if (avr32_arch != &default_arch)
++        break;
++
++      do
++        *t = TOLOWER (*p++);
++      while (*t++);
++
++      for (i = 0; part_types[i].name; ++i)
++        if (strcmp (part_types[i].name, s) == 0)
++          break;
++
++      if (!part_types[i].name)
++        {
++          show_part_list (stderr);
++          as_fatal (_("unknown part: %s\n"), arg);
++        }
++
++      avr32_arch = &arch_types[part_types[i].arch];
++      break;
++      }
++    case OPTION_IAR:
++      avr32_iarcompat = 1;
++      break;
++    case OPTION_PIC:
++      avr32_pic = 1;
++      break;
++    case OPTION_NOPIC:
++      avr32_pic = 0;
++      break;
++    case OPTION_LINKRELAX:
++      linkrelax = 1;
++      break;
++    case OPTION_NOLINKRELAX:
++      linkrelax = 0;
++      break;
++    default:
++      return 0;
++    }
++  return 1;
++}
++
++/* Can't use symbol_new here, so have to create a symbol and then at
++   a later date assign it a value. Thats what these functions do.
++
++   Shamelessly stolen from ARM.  */
++
++static void
++symbol_locate (symbolS *    symbolP,
++             const char * name,       /* It is copied, the caller can modify.  */
++             segT         segment,    /* Segment identifier (SEG_<something>).  */
++             valueT       valu,       /* Symbol value.  */
++             fragS *      frag)       /* Associated fragment.  */
++{
++  unsigned int name_length;
++  char * preserved_copy_of_name;
++
++  name_length = strlen (name) + 1;   /* +1 for \0.  */
++  obstack_grow (&notes, name, name_length);
++  preserved_copy_of_name = obstack_finish (&notes);
++#ifdef STRIP_UNDERSCORE
++  if (preserved_copy_of_name[0] == '_')
++    preserved_copy_of_name++;
++#endif
++
++#ifdef tc_canonicalize_symbol_name
++  preserved_copy_of_name =
++    tc_canonicalize_symbol_name (preserved_copy_of_name);
++#endif
++
++  S_SET_NAME (symbolP, preserved_copy_of_name);
++
++  S_SET_SEGMENT (symbolP, segment);
++  S_SET_VALUE (symbolP, valu);
++  symbol_clear_list_pointers (symbolP);
++
++  symbol_set_frag (symbolP, frag);
++
++  /* Link to end of symbol chain.  */
++  {
++    extern int symbol_table_frozen;
++
++    if (symbol_table_frozen)
++      abort ();
++  }
++
++  symbol_append (symbolP, symbol_lastP, & symbol_rootP, & symbol_lastP);
++
++  obj_symbol_new_hook (symbolP);
++
++#ifdef tc_symbol_new_hook
++  tc_symbol_new_hook (symbolP);
++#endif
++
++#ifdef DEBUG_SYMS
++  verify_symbol_chain (symbol_rootP, symbol_lastP);
++#endif /* DEBUG_SYMS  */
++}
++
++struct cpool_entry
++{
++  int                 refcount;
++  offsetT             offset;
++  expressionS         exp;
++};
++
++struct cpool
++{
++  struct cpool                *next;
++  int                 used;
++  struct cpool_entry  *literals;
++  unsigned int                padding;
++  unsigned int                next_free_entry;
++  unsigned int                id;
++  symbolS             *symbol;
++  segT                        section;
++  subsegT             sub_section;
++};
++
++struct cpool *cpool_list = NULL;
++
++static struct cpool *
++find_cpool(segT section, subsegT sub_section)
++{
++  struct cpool *pool;
++
++  for (pool = cpool_list; pool != NULL; pool = pool->next)
++    {
++      if (!pool->used
++        && pool->section == section
++        && pool->sub_section == sub_section)
++      break;
++    }
++
++  return pool;
++}
++
++static struct cpool *
++find_or_make_cpool(segT section, subsegT sub_section)
++{
++  static unsigned int next_cpool_id = 0;
++  struct cpool *pool;
++
++  pool = find_cpool(section, sub_section);
++
++  if (!pool)
++    {
++      pool = xmalloc(sizeof(*pool));
++      if (!pool)
++      return NULL;
++
++      pool->used = 0;
++      pool->literals = NULL;
++      pool->padding = 0;
++      pool->next_free_entry = 0;
++      pool->section = section;
++      pool->sub_section = sub_section;
++      pool->next = cpool_list;
++      pool->symbol = NULL;
++
++      cpool_list = pool;
++    }
++
++  /* NULL symbol means that the pool is new or has just been emptied.  */
++  if (!pool->symbol)
++    {
++      pool->symbol = symbol_create(FAKE_LABEL_NAME, undefined_section,
++                                 0, &zero_address_frag);
++      pool->id = next_cpool_id++;
++    }
++
++  return pool;
++}
++
++static struct cpool *
++add_to_cpool(expressionS *exp, unsigned int *index, int ref)
++{
++  struct cpool *pool;
++  unsigned int entry;
++
++  pool = find_or_make_cpool(now_seg, now_subseg);
++
++  /* Check if this constant is already in the pool.  */
++  for (entry = 0; entry < pool->next_free_entry; entry++)
++    {
++      if ((pool->literals[entry].exp.X_op == exp->X_op)
++        && (exp->X_op == O_constant)
++        && (pool->literals[entry].exp.X_add_number
++            == exp->X_add_number)
++        && (pool->literals[entry].exp.X_unsigned
++            == exp->X_unsigned))
++      break;
++
++      if ((pool->literals[entry].exp.X_op == exp->X_op)
++        && (exp->X_op == O_symbol)
++        && (pool->literals[entry].exp.X_add_number
++            == exp->X_add_number)
++        && (pool->literals[entry].exp.X_add_symbol
++            == exp->X_add_symbol)
++        && (pool->literals[entry].exp.X_op_symbol
++            == exp->X_op_symbol))
++      break;
++    }
++
++  /* Create an entry if we didn't find a match */
++  if (entry == pool->next_free_entry)
++    {
++      pool->literals = xrealloc(pool->literals,
++                              sizeof(struct cpool_entry) * (entry + 1));
++      pool->literals[entry].exp = *exp;
++      pool->literals[entry].refcount = 0;
++      pool->next_free_entry++;
++    }
++
++  if (index)
++    *index = entry;
++  if (ref)
++    pool->literals[entry].refcount++;
++
++  return pool;
++}
++
++struct avr32_operand
++{
++  int id;
++  int is_signed;
++  int is_pcrel;
++  int align_order;
++  int (*match)(char *str);
++  void (*parse)(const struct avr32_operand *op, char *str, int opindex);
++};
++
++static int
++match_anything(char *str ATTRIBUTE_UNUSED)
++{
++  return 1;
++}
++
++static int
++match_intreg(char *str)
++{
++  int regid, ret = 1;
++
++  regid = avr32_parse_intreg(str);
++  if (regid < 0)
++    ret = 0;
++
++  pr_debug("match_intreg: `%s': %d\n", str, ret);
++
++  return ret;
++}
++
++static int
++match_intreg_predec(char *str)
++{
++  int regid;
++
++  if (str[0] != '-' || str[1] != '-')
++    return 0;
++
++  regid = avr32_parse_intreg(str + 2);
++  if (regid < 0)
++    return 0;
++
++  return 1;
++}
++
++static int
++match_intreg_postinc(char *str)
++{
++  int regid, ret = 1;
++  char *p, c;
++
++  for (p = str; *p; p++)
++    if (*p == '+')
++      break;
++
++  if (p[0] != '+' || p[1] != '+')
++    return 0;
++
++  c = *p, *p = 0;
++  regid = avr32_parse_intreg(str);
++  if (regid < 0)
++    ret = 0;
++
++  *p = c;
++  return ret;
++}
++
++static int
++match_intreg_lsl(char *str)
++{
++  int regid, ret = 1;
++  char *p, c;
++
++  for (p = str; *p; p++)
++    if (*p == '<')
++      break;
++
++  if (p[0] && p[1] != '<')
++    return 0;
++
++  c = *p, *p = 0;
++  regid = avr32_parse_intreg(str);
++  if (regid < 0)
++    ret = 0;
++
++  *p = c;
++  return ret;
++}
++
++static int
++match_intreg_lsr(char *str)
++{
++  int regid, ret = 1;
++  char *p, c;
++
++  for (p = str; *p; p++)
++    if (*p == '>')
++      break;
++
++  if (p[0] && p[1] != '>')
++    return 0;
++
++  c = *p, *p = 0;
++
++  regid = avr32_parse_intreg(str);
++  if (regid < 0)
++    ret = 0;
++
++  *p = c;
++  return ret;
++}
++
++static int
++match_intreg_part(char *str)
++{
++  int regid, ret = 1;
++  char *p, c;
++
++  for (p = str; *p; p++)
++    if (*p == ':')
++      break;
++
++  if (p[0] != ':' || !ISPRINT(p[1]) || p[2] != '\0')
++    return 0;
++
++  c = *p, *p = 0;
++  regid = avr32_parse_intreg(str);
++  if (regid < 0)
++    ret = 0;
++
++  *p = c;
++
++  return ret;
++}
++
++#define match_intreg_disp match_anything
++
++static int
++match_intreg_index(char *str)
++{
++  int regid, ret = 1;
++  char *p, *end, c;
++
++  for (p = str; *p; p++)
++    if (*p == '[')
++      break;
++
++  /* don't allow empty displacement here (it makes no sense) */
++  if (p[0] != '[')
++    return 0;
++
++  for (end = p + 1; *end; end++) ;
++  if (*(--end) != ']')
++    return 0;
++
++  c = *end, *end = 0;
++  if (!match_intreg_lsl(p + 1))
++    ret = 0;
++  *end = c;
++
++  if (ret)
++    {
++      c = *p, *p = 0;
++      regid = avr32_parse_intreg(str);
++      if (regid < 0)
++      ret = 0;
++      *p = c;
++    }
++
++  return ret;
++}
++
++static int
++match_intreg_xindex(char *str)
++{
++  int regid, ret = 1;
++  char *p, *end, c;
++
++  for (p = str; *p; p++)
++    if (*p == '[')
++      break;
++
++  /* empty displacement makes no sense here either */
++  if (p[0] != '[')
++    return 0;
++
++  for (end = p + 1; *end; end++)
++    if (*end == '<')
++      break;
++
++  if (!streq(end, "<<2]"))
++    return 0;
++
++  c = *end, *end = 0;
++  if (!match_intreg_part(p + 1))
++    ret = 0;
++  *end = c;
++
++  if (ret)
++    {
++      c = *p, *p = 0;
++      regid = avr32_parse_intreg(str);
++      if (regid < 0)
++      ret = 0;
++      *p = c;
++    }
++
++  return ret;
++}
++
++/* The PC_UDISP_W operator may show up as a label or as a pc[disp]
++   expression.  So there's no point in attempting to match this...  */
++#define match_pc_disp match_anything
++
++static int
++match_sp(char *str)
++{
++  /* SP in any form will do */
++  return avr32_parse_intreg(str) == AVR32_REG_SP;
++}
++
++static int
++match_sp_disp(char *str)
++{
++  int regid, ret = 1;
++  char *p, c;
++
++  for (p = str; *p; p++)
++    if (*p == '[')
++      break;
++
++  /* allow empty displacement, meaning zero */
++  if (p[0] == '[')
++    {
++      char *end;
++      for (end = p + 1; *end; end++) ;
++      if (end[-1] != ']')
++      return 0;
++    }
++
++  c = *p, *p = 0;
++  regid = avr32_parse_intreg(str);
++  if (regid != AVR32_REG_SP)
++    ret = 0;
++
++  *p = c;
++  return ret;
++}
++
++static int
++match_cpno(char *str)
++{
++  if (strncasecmp(str, "cp", 2) != 0)
++    return 0;
++  return 1;
++}
++
++static int
++match_cpreg(char *str)
++{
++  if (strncasecmp(str, "cr", 2) != 0)
++    return 0;
++  return 1;
++}
++
++/* We allow complex expressions, and register names may show up as
++   symbols.  Just make sure immediate expressions are always matched
++   last.  */
++#define match_const           match_anything
++#define match_jmplabel                match_anything
++#define match_number          match_anything
++
++/* Mnemonics that take reglists never accept anything else */
++#define match_reglist8                match_anything
++#define match_reglist9                match_anything
++#define match_reglist16               match_anything
++#define match_reglist_ldm     match_anything
++#define match_reglist_cp8     match_anything
++#define match_reglist_cpd8    match_anything
++
++/* Ditto for retval, jospinc and mcall */
++#define match_retval          match_anything
++#define match_jospinc         match_anything
++#define match_mcall           match_anything
++
++/* COH is used to select between two different syntaxes */
++static int
++match_coh(char *str)
++{
++  return strcasecmp(str, "coh") == 0;
++}
++#if 0
++static int
++match_fpreg(char *str)
++{
++  unsigned long regid;
++  char *endptr;
++
++  if ((str[0] != 'f' && str[0] != 'F')
++      || (str[1] != 'r' && str[1] != 'R'))
++    return 0;
++
++  str += 2;
++  regid = strtoul(str, &endptr, 10);
++  if (!*str || *endptr)
++    return 0;
++
++  return 1;
++}
++#endif
++
++static int
++match_picoreg(char *str)
++{
++  int regid;
++
++  regid = avr32_parse_picoreg(str);
++  if (regid < 0)
++    return 0;
++  return 1;
++}
++
++#define match_pico_reglist_w  match_anything
++#define match_pico_reglist_d  match_anything
++
++static int
++match_pico_in(char *str)
++{
++  unsigned long regid;
++  char *end;
++
++  if (strncasecmp(str, "in", 2) != 0)
++    return 0;
++
++  str += 2;
++  regid = strtoul(str, &end, 10);
++  if (!*str || *end)
++    return 0;
++
++  return 1;
++}
++
++static int
++match_pico_out0(char *str)
++{
++  if (strcasecmp(str, "out0") != 0)
++    return 0;
++  return 1;
++}
++
++static int
++match_pico_out1(char *str)
++{
++  if (strcasecmp(str, "out1") != 0)
++    return 0;
++  return 1;
++}
++
++static int
++match_pico_out2(char *str)
++{
++  if (strcasecmp(str, "out2") != 0)
++    return 0;
++  return 1;
++}
++
++static int
++match_pico_out3(char *str)
++{
++  if (strcasecmp(str, "out3") != 0)
++    return 0;
++  return 1;
++}
++
++static void parse_nothing(const struct avr32_operand *op ATTRIBUTE_UNUSED,
++                        char *str ATTRIBUTE_UNUSED,
++                        int opindex ATTRIBUTE_UNUSED)
++{
++  /* Do nothing (this is used for "match-only" operands like COH) */
++}
++
++static void
++parse_const(const struct avr32_operand *op, char *str,
++          int opindex ATTRIBUTE_UNUSED)
++{
++  expressionS *exp = &current_insn.immediate;
++  expressionS *sym_exp;
++  int slot;
++  char *save;
++
++  pr_debug("parse_const: `%s' (signed: %d, pcrel: %d, align: %d)\n",
++         str, op->is_signed, op->is_pcrel, op->align_order);
++
++  save = input_line_pointer;
++  input_line_pointer = str;
++
++  expression(exp);
++
++  slot = current_insn.next_slot++;
++  current_insn.field_value[slot].align_order = op->align_order;
++  current_insn.pcrel = op->is_pcrel;
++
++  switch (exp->X_op)
++    {
++    case O_illegal:
++      as_bad(_("illegal operand"));
++      break;
++    case O_absent:
++      as_bad(_("missing operand"));
++      break;
++    case O_constant:
++      pr_debug("  -> constant: %ld\n", (long)exp->X_add_number);
++      current_insn.field_value[slot].value = exp->X_add_number;
++      break;
++    case O_uminus:
++      pr_debug("  -> uminus\n");
++      sym_exp = symbol_get_value_expression(exp->X_add_symbol);
++      switch (sym_exp->X_op) {
++      case O_subtract:
++      pr_debug("     -> subtract: switching operands\n");
++      exp->X_op_symbol = sym_exp->X_add_symbol;
++      exp->X_add_symbol = sym_exp->X_op_symbol;
++      exp->X_op = O_subtract;
++      /* TODO: Remove the old X_add_symbol */
++      break;
++      default:
++      as_bad(_("Expression too complex\n"));
++      break;
++      }
++      break;
++#if 0
++    case O_subtract:
++      /* Any expression subtracting a symbol from the current section
++       can be made PC-relative by adding the right offset.  */
++      if (S_GET_SEGMENT(exp->X_op_symbol) == now_seg)
++      current_insn.pcrel = TRUE;
++      pr_debug("  -> subtract: pcrel? %s\n",
++             current_insn.pcrel ? "yes" : "no");
++      /* fall through */
++#endif
++    default:
++      pr_debug("  -> (%p <%d> %p + %d)\n",
++             exp->X_add_symbol, exp->X_op, exp->X_op_symbol,
++             exp->X_add_number);
++      current_insn.field_value[slot].value = 0;
++      break;
++    }
++
++  input_line_pointer = save;
++}
++
++static void
++parse_jmplabel(const struct avr32_operand *op, char *str,
++             int opindex ATTRIBUTE_UNUSED)
++{
++  expressionS *exp = &current_insn.immediate;
++  int slot;
++  char *save;
++
++  pr_debug("parse_jmplabel: `%s' (signed: %d, pcrel: %d, align: %d)\n",
++         str, op->is_signed, op->is_pcrel, op->align_order);
++
++  save = input_line_pointer;
++  input_line_pointer = str;
++
++  expression(exp);
++
++  slot = current_insn.next_slot++;
++  current_insn.field_value[slot].align_order = op->align_order;
++  current_insn.pcrel = TRUE;
++
++  switch (exp->X_op)
++    {
++    case O_illegal:
++      as_bad(_("illegal operand"));
++      break;
++    case O_absent:
++      as_bad(_("missing operand"));
++      break;
++    case O_constant:
++      pr_debug("  -> constant: %ld\n", (long)exp->X_add_number);
++      current_insn.field_value[slot].value = exp->X_add_number;
++      current_insn.pcrel = 0;
++      break;
++    default:
++      pr_debug("  -> (%p <%d> %p + %d)\n",
++             exp->X_add_symbol, exp->X_op, exp->X_op_symbol,
++             exp->X_add_number);
++      current_insn.field_value[slot].value = 0;
++      break;
++    }
++
++  input_line_pointer = save;
++}
++
++static void
++parse_intreg(const struct avr32_operand *op ATTRIBUTE_UNUSED,
++           char *str, int opindex ATTRIBUTE_UNUSED)
++{
++  int regid, slot;
++
++  pr_debug("parse_intreg: `%s'\n", str);
++
++  regid = avr32_parse_intreg(str);
++  assert(regid >= 0);
++
++  slot = current_insn.next_slot++;
++  current_insn.field_value[slot].value = regid;
++  current_insn.field_value[slot].align_order = op->align_order;
++}
++
++static void
++parse_intreg_predec(const struct avr32_operand *op, char *str, int opindex)
++{
++  parse_intreg(op, str + 2, opindex);
++}
++
++static void
++parse_intreg_postinc(const struct avr32_operand *op, char *str, int opindex)
++{
++  char *p, c;
++
++  pr_debug("parse_intreg_postinc: `%s'\n", str);
++
++  for (p = str; *p != '+'; p++) ;
++
++  c = *p, *p = 0;
++  parse_intreg(op, str, opindex);
++  *p = c;
++}
++
++static void
++parse_intreg_shift(const struct avr32_operand *op ATTRIBUTE_UNUSED,
++                 char *str, int opindex ATTRIBUTE_UNUSED)
++{
++  int regid, slot, shift = 0;
++  char *p, c;
++  char shiftop;
++
++  pr_debug("parse Ry<<sa: `%s'\n", str);
++
++  for (p = str; *p; p++)
++    if (*p == '<' || *p == '>')
++      break;
++
++  shiftop = *p;
++
++  c = *p, *p = 0;
++  regid = avr32_parse_intreg(str);
++  assert(regid >= 0);
++  *p = c;
++
++  if (c)
++    {
++      if (p[0] != shiftop || p[1] != shiftop)
++      as_bad(_("expected shift operator in `%s'"), p);
++      else
++      {
++        expressionS exp;
++        char *saved;
++
++        saved = input_line_pointer;
++        input_line_pointer = p + 2;
++        expression(&exp);
++        input_line_pointer = saved;
++
++        if (exp.X_op != O_constant)
++          as_bad(_("shift amount must be a numeric constant"));
++        else
++          shift = exp.X_add_number;
++      }
++    }
++
++  slot = current_insn.next_slot++;
++  current_insn.field_value[slot].value = regid;
++  slot = current_insn.next_slot++;
++  current_insn.field_value[slot].value = shift;
++}
++
++/* The match() function selected the right opcode, so it doesn't
++   matter which way we shift any more.  */
++#define parse_intreg_lsl      parse_intreg_shift
++#define parse_intreg_lsr      parse_intreg_shift
++
++static void
++parse_intreg_part(const struct avr32_operand *op, char *str,
++                int opindex ATTRIBUTE_UNUSED)
++{
++  static const char bparts[] = { 'b', 'l', 'u', 't' };
++  static const char hparts[] = { 'b', 't' };
++  unsigned int slot, sel;
++  int regid;
++  char *p, c;
++
++  pr_debug("parse reg:part `%s'\n", str);
++
++  for (p = str; *p; p++)
++    if (*p == ':')
++      break;
++
++  c = *p, *p = 0;
++  regid = avr32_parse_intreg(str);
++  assert(regid >= 0);
++  *p = c;
++
++  assert(c == ':');
++
++  if (op->align_order)
++    {
++      for (sel = 0; sel < sizeof(hparts); sel++)
++      if (TOLOWER(p[1]) == hparts[sel])
++        break;
++
++      if (sel >= sizeof(hparts))
++      {
++        as_bad(_("invalid halfword selector `%c' (must be either b or t)"),
++               p[1]);
++        sel = 0;
++      }
++    }
++  else
++    {
++      for (sel = 0; sel < sizeof(bparts); sel++)
++      if (TOLOWER(p[1]) == bparts[sel])
++        break;
++
++      if (sel >= sizeof(bparts))
++      {
++        as_bad(_("invalid byte selector `%c' (must be one of b,l,u,t)"),
++               p[1]);
++        sel = 0;
++      }
++    }
++
++  slot = current_insn.next_slot++;
++  current_insn.field_value[slot].value = regid;
++  slot = current_insn.next_slot++;
++  current_insn.field_value[slot].value = sel;
++}
++
++/* This is the parser for "Rp[displacement]" expressions.  In addition
++   to the "official" syntax, we accept a label as a replacement for
++   the register expression.  This syntax implies Rp=PC and the
++   displacement is the pc-relative distance to the label.  */
++static void
++parse_intreg_disp(const struct avr32_operand *op, char *str, int opindex)
++{
++  expressionS *exp = &current_insn.immediate;
++  int slot, regid;
++  char *save, *p, c;
++
++  pr_debug("parse_intreg_disp: `%s' (signed: %d, pcrel: %d, align: %d)\n",
++         str, op->is_signed, op->is_pcrel, op->align_order);
++
++  for (p = str; *p; p++)
++    if (*p == '[')
++      break;
++
++  slot = current_insn.next_slot++;
++
++  /* First, check if we have a valid register either before '[' or as
++     the sole expression.  If so, we use the Rp[disp] syntax.  */
++  c = *p, *p = 0;
++  regid = avr32_parse_intreg(str);
++  *p = c;
++
++  if (regid >= 0)
++    {
++      current_insn.field_value[slot].value = regid;
++
++      slot = current_insn.next_slot++;
++      current_insn.field_value[slot].align_order = op->align_order;
++
++      if (c == '[')
++      {
++        save = input_line_pointer;
++        input_line_pointer = p + 1;
++
++        expression(exp);
++
++        if (*input_line_pointer != ']')
++          as_bad(_("junk after displacement expression"));
++
++        input_line_pointer = save;
++
++        switch (exp->X_op)
++          {
++          case O_illegal:
++            as_bad(_("illegal displacement expression"));
++            break;
++          case O_absent:
++            as_bad(_("missing displacement expression"));
++            break;
++          case O_constant:
++            pr_debug("  -> constant: %ld\n", exp->X_add_number);
++            current_insn.field_value[slot].value = exp->X_add_number;
++            break;
++#if 0
++          case O_subtract:
++            if (S_GET_SEGMENT(exp->X_op_symbol) == now_seg)
++              current_insn.pcrel = TRUE;
++            pr_debug("  -> subtract: pcrel? %s\n",
++                     current_insn.pcrel ? "yes" : "no");
++            /* fall through */
++#endif
++          default:
++            pr_debug("  -> (%p <%d> %p + %d)\n",
++                     exp->X_add_symbol, exp->X_op, exp->X_op_symbol,
++                     exp->X_add_number);
++            current_insn.field_value[slot].value = 0;
++          }
++      }
++      else
++      {
++        exp->X_op = O_constant;
++        exp->X_add_number = 0;
++        current_insn.field_value[slot].value = 0;
++      }
++    }
++  else
++    {
++      /* Didn't find a valid register.  Try parsing it as a label.  */
++      current_insn.field_value[slot].value = AVR32_REG_PC;
++      parse_jmplabel(op, str, opindex);
++    }
++}
++
++static void
++parse_intreg_index(const struct avr32_operand *op ATTRIBUTE_UNUSED,
++                 char *str, int opindex ATTRIBUTE_UNUSED)
++{
++  int slot, regid;
++  char *p, *end, c;
++
++  for (p = str; *p; p++)
++    if (*p == '[')
++      break;
++
++  assert(*p);
++
++  c = *p, *p = 0;
++  regid = avr32_parse_intreg(str);
++  assert(regid >= 0);
++  *p = c;
++
++  slot = current_insn.next_slot++;
++  current_insn.field_value[slot].value = regid;
++
++  p++;
++  for (end = p; *end; end++)
++    if (*end == ']' || *end == '<')
++      break;
++
++  assert(*end);
++
++  c = *end, *end = 0;
++  regid = avr32_parse_intreg(p);
++  assert(regid >= 0);
++  *end = c;
++
++  slot = current_insn.next_slot++;
++  current_insn.field_value[slot].value = regid;
++
++  slot = current_insn.next_slot++;
++  current_insn.field_value[slot].value = 0;
++
++  if (*end == '<')
++    {
++      expressionS exp;
++      char *save;
++
++      p = end + 2;
++      for (end = p; *end; end++)
++      if (*end == ']')
++        break;
++
++      assert(*end == ']');
++
++      c = *end, *end = 0;
++      save = input_line_pointer;
++      input_line_pointer = p;
++      expression(&exp);
++
++      if (*input_line_pointer)
++      as_bad(_("junk after shift expression"));
++
++      *end = c;
++      input_line_pointer = save;
++
++      if (exp.X_op == O_constant)
++      current_insn.field_value[slot].value = exp.X_add_number;
++      else
++      as_bad(_("shift expression too complex"));
++    }
++}
++
++static void
++parse_intreg_xindex(const struct avr32_operand *op, char *str, int opindex)
++{
++  int slot, regid;
++  char *p, *end, c;
++
++  for (p = str; *p; p++)
++    if (*p == '[')
++      break;
++
++  assert(*p);
++
++  c = *p, *p = 0;
++  regid = avr32_parse_intreg(str);
++  assert(regid >= 0);
++  *p = c;
++
++  slot = current_insn.next_slot++;
++  current_insn.field_value[slot].value = regid;
++
++  p++;
++  for (end = p; *end; end++)
++    if (*end == '<')
++      break;
++
++  assert(*end);
++
++  c = *end, *end = 0;
++  parse_intreg_part(op, p, opindex);
++  *end = c;
++}
++
++static void
++parse_pc_disp(const struct avr32_operand *op, char *str, int opindex)
++{
++  char *p, c;
++
++  for (p = str; *p; p++)
++    if (*p == '[')
++      break;
++
++  /* The lddpc instruction comes in two different syntax variants:
++       lddpc reg, expression
++       lddpc reg, pc[disp]
++     If the operand contains a '[', we use the second form.  */
++  if (*p)
++    {
++      int regid;
++
++      c = *p, *p = 0;
++      regid = avr32_parse_intreg(str);
++      *p = c;
++      if (regid == AVR32_REG_PC)
++      {
++        char *end;
++
++        for (end = ++p; *end; end++) ;
++        if (*(--end) != ']')
++          as_bad(_("unrecognized form of instruction: `%s'"), str);
++        else
++          {
++            c = *end, *end = 0;
++            parse_const(op, p, opindex);
++            *end = c;
++            current_insn.pcrel = 0;
++          }
++      }
++      else
++      as_bad(_("unrecognized form of instruction: `%s'"), str);
++    }
++  else
++    {
++      parse_jmplabel(op, str, opindex);
++    }
++}
++
++static void parse_sp(const struct avr32_operand *op ATTRIBUTE_UNUSED,
++                   char *str ATTRIBUTE_UNUSED,
++                   int opindex ATTRIBUTE_UNUSED)
++{
++  int slot;
++
++  slot = current_insn.next_slot++;
++  current_insn.field_value[slot].value = AVR32_REG_SP;
++}
++
++static void
++parse_sp_disp(const struct avr32_operand *op, char *str, int opindex)
++{
++  char *p, c;
++
++  for (; *str; str++)
++    if (*str == '[')
++      break;
++
++  assert(*str);
++
++  for (p = ++str; *p; p++)
++    if (*p == ']')
++      break;
++
++  c = *p, *p = 0;
++  parse_const(op, str, opindex);
++  *p = c;
++}
++
++static void
++parse_cpno(const struct avr32_operand *op ATTRIBUTE_UNUSED, char *str,
++         int opindex ATTRIBUTE_UNUSED)
++{
++  int slot;
++
++  str += 2;
++  if (*str == '#')
++    str++;
++  if (*str < '0' || *str > '7' || str[1])
++    as_bad(_("invalid coprocessor `%s'"), str);
++
++  slot = current_insn.next_slot++;
++  current_insn.field_value[slot].value = *str - '0';
++}
++
++static void
++parse_cpreg(const struct avr32_operand *op, char *str,
++          int opindex ATTRIBUTE_UNUSED)
++{
++  unsigned int crid;
++  int slot;
++  char *endptr;
++
++  str += 2;
++  crid = strtoul(str, &endptr, 10);
++  if (*endptr || crid > 15 || crid & ((1 << op->align_order) - 1))
++    as_bad(_("invalid coprocessor register `%s'"), str);
++
++  crid >>= op->align_order;
++
++  slot = current_insn.next_slot++;
++  current_insn.field_value[slot].value = crid;
++}
++
++static void
++parse_number(const struct avr32_operand *op, char *str,
++           int opindex ATTRIBUTE_UNUSED)
++{
++  expressionS exp;
++  int slot;
++  char *save;
++
++  save = input_line_pointer;
++  input_line_pointer = str;
++  expression(&exp);
++  input_line_pointer = save;
++
++  slot = current_insn.next_slot++;
++  current_insn.field_value[slot].align_order = op->align_order;
++
++  if (exp.X_op == O_constant)
++      current_insn.field_value[slot].value = exp.X_add_number;
++  else
++      as_bad(_("invalid numeric expression `%s'"), str);
++}
++
++static void
++parse_reglist8(const struct avr32_operand *op ATTRIBUTE_UNUSED,
++             char *str, int opindex ATTRIBUTE_UNUSED)
++{
++  unsigned long regmask;
++  unsigned long value = 0;
++  int slot;
++  char *tail;
++
++  regmask = avr32_parse_reglist(str, &tail);
++  if (*tail)
++    as_bad(_("invalid register list `%s'"), str);
++  else
++    {
++      if (avr32_make_regmask8(regmask, &value))
++      as_bad(_("register list `%s' doesn't fit"), str);
++    }
++
++  slot = current_insn.next_slot++;
++  current_insn.field_value[slot].value = value;
++}
++
++static int
++parse_reglist_tail(char *str, unsigned long regmask)
++{
++  expressionS exp;
++  char *save, *p, c;
++  int regid;
++
++  for (p = str + 1; *p; p++)
++    if (*p == '=')
++      break;
++
++  if (!*p)
++    {
++      as_bad(_("invalid register list `%s'"), str);
++      return -2;
++    }
++
++  c = *p, *p = 0;
++  regid = avr32_parse_intreg(str);
++  *p = c;
++
++  if (regid != 12)
++    {
++      as_bad(_("invalid register list `%s'"), str);
++      return -2;
++    }
++
++  /* If we have an assignment, we must pop PC and we must _not_
++     pop LR or R12 */
++  if (!(regmask & (1 << AVR32_REG_PC)))
++    {
++      as_bad(_("return value specified for non-return instruction"));
++      return -2;
++    }
++  else if (regmask & ((1 << AVR32_REG_R12) | (1 << AVR32_REG_LR)))
++    {
++      as_bad(_("can't pop LR or R12 when specifying return value"));
++      return -2;
++    }
++
++  save = input_line_pointer;
++  input_line_pointer = p + 1;
++  expression(&exp);
++  input_line_pointer = save;
++
++  if (exp.X_op != O_constant
++      || exp.X_add_number < -1
++      || exp.X_add_number > 1)
++    {
++      as_bad(_("invalid return value `%s'"), str);
++      return -2;
++    }
++
++  return exp.X_add_number;
++}
++
++static void
++parse_reglist9(const struct avr32_operand *op ATTRIBUTE_UNUSED,
++             char *str, int opindex ATTRIBUTE_UNUSED)
++{
++  unsigned long regmask;
++  unsigned long value = 0, kbit = 0;
++  int slot;
++  char *tail;
++
++  regmask = avr32_parse_reglist(str, &tail);
++  /* printf("parsed reglist16: %04lx, tail: `%s'\n", regmask, tail); */
++  if (*tail)
++    {
++      int retval;
++
++      retval = parse_reglist_tail(tail, regmask);
++
++      switch (retval)
++      {
++      case -1:
++        regmask |= 1 << AVR32_REG_LR;
++        break;
++      case 0:
++        break;
++      case 1:
++        regmask |= 1 << AVR32_REG_R12;
++        break;
++      default:
++        break;
++      }
++
++      kbit = 1;
++    }
++
++  if (avr32_make_regmask8(regmask, &value))
++    as_bad(_("register list `%s' doesn't fit"), str);
++
++
++  slot = current_insn.next_slot++;
++  current_insn.field_value[slot].value = (value << 1) | kbit;
++}
++
++static void
++parse_reglist16(const struct avr32_operand *op ATTRIBUTE_UNUSED,
++              char *str, int opindex ATTRIBUTE_UNUSED)
++{
++  unsigned long regmask;
++  int slot;
++  char *tail;
++
++  regmask = avr32_parse_reglist(str, &tail);
++  if (*tail)
++    as_bad(_("invalid register list `%s'"), str);
++
++  slot = current_insn.next_slot++;
++  current_insn.field_value[slot].value = regmask;
++}
++
++static void
++parse_reglist_ldm(const struct avr32_operand *op ATTRIBUTE_UNUSED,
++                char *str, int opindex ATTRIBUTE_UNUSED)
++{
++  unsigned long regmask;
++  int slot, rp, w_bit = 0;
++  char *tail, *p, c;
++
++  for (p = str; *p && *p != ','; p++)
++    if (*p == '+')
++      break;
++
++  c = *p, *p = 0;
++  rp = avr32_parse_intreg(str);
++  *p = c;
++  if (rp < 0)
++    {
++      as_bad(_("invalid destination register in `%s'"), str);
++      return;
++    }
++
++  if (p[0] == '+' && p[1] == '+')
++    {
++      w_bit = 1;
++      p += 2;
++    }
++
++  if (*p != ',')
++    {
++      as_bad(_("expected `,' after destination register in `%s'"), str);
++      return;
++    }
++
++  str = p + 1;
++  regmask = avr32_parse_reglist(str, &tail);
++  if (*tail)
++    {
++      int retval;
++
++      if (rp != AVR32_REG_SP)
++      {
++        as_bad(_("junk at end of line: `%s'"), tail);
++        return;
++      }
++
++      rp = AVR32_REG_PC;
++
++      retval = parse_reglist_tail(tail, regmask);
++
++      switch (retval)
++      {
++      case -1:
++        regmask |= 1 << AVR32_REG_LR;
++        break;
++      case 0:
++        break;
++      case 1:
++        regmask |= 1 << AVR32_REG_R12;
++        break;
++      default:
++        return;
++      }
++    }
++
++  slot = current_insn.next_slot++;
++  current_insn.field_value[slot].value = rp;
++  slot = current_insn.next_slot++;
++  current_insn.field_value[slot].value = w_bit;
++  slot = current_insn.next_slot++;
++  current_insn.field_value[slot].value = regmask;
++}
++
++static void
++parse_reglist_cp8(const struct avr32_operand *op ATTRIBUTE_UNUSED,
++                char *str, int opindex ATTRIBUTE_UNUSED)
++{
++  unsigned long regmask;
++  int slot, h_bit = 0;
++  char *tail;
++
++  regmask = avr32_parse_cpreglist(str, &tail);
++  if (*tail)
++    as_bad(_("junk at end of line: `%s'"), tail);
++  else if (regmask & 0xffUL)
++    {
++      if (regmask & 0xff00UL)
++      as_bad(_("register list `%s' doesn't fit"), str);
++      regmask &= 0xff;
++    }
++  else if (regmask & 0xff00UL)
++    {
++      regmask >>= 8;
++      h_bit = 1;
++    }
++  else
++    as_warn(_("register list is empty"));
++
++  slot = current_insn.next_slot++;
++  current_insn.field_value[slot].value = regmask;
++  slot = current_insn.next_slot++;
++  current_insn.field_value[slot].value = h_bit;
++}
++
++static void
++parse_reglist_cpd8(const struct avr32_operand *op ATTRIBUTE_UNUSED,
++                 char *str, int opindex ATTRIBUTE_UNUSED)
++{
++  unsigned long regmask, regmask_d = 0;
++  int slot, i;
++  char *tail;
++
++  regmask = avr32_parse_cpreglist(str, &tail);
++  if (*tail)
++    as_bad(_("junk at end of line: `%s'"), tail);
++
++  for (i = 0; i < 8; i++)
++    {
++      if (regmask & 1)
++      {
++        if (!(regmask & 2))
++          {
++            as_bad(_("register list `%s' doesn't fit"), str);
++            break;
++          }
++        regmask_d |= 1 << i;
++      }
++      else if (regmask & 2)
++      {
++        as_bad(_("register list `%s' doesn't fit"), str);
++        break;
++      }
++
++      regmask >>= 2;
++    }
++
++  slot = current_insn.next_slot++;
++  current_insn.field_value[slot].value = regmask_d;
++}
++
++static void
++parse_retval(const struct avr32_operand *op ATTRIBUTE_UNUSED,
++           char *str, int opindex ATTRIBUTE_UNUSED)
++{
++  int regid, slot;
++
++  regid = avr32_parse_intreg(str);
++  if (regid < 0)
++    {
++      expressionS exp;
++      char *save;
++
++      regid = 0;
++
++      save = input_line_pointer;
++      input_line_pointer = str;
++      expression(&exp);
++      input_line_pointer = save;
++
++      if (exp.X_op != O_constant)
++      as_bad(_("invalid return value `%s'"), str);
++      else
++      switch (exp.X_add_number)
++        {
++        case -1:
++          regid = AVR32_REG_LR;
++          break;
++        case 0:
++          regid = AVR32_REG_SP;
++          break;
++        case 1:
++          regid = AVR32_REG_PC;
++          break;
++        default:
++          as_bad(_("invalid return value `%s'"), str);
++          break;
++        }
++    }
++
++  slot = current_insn.next_slot++;
++  current_insn.field_value[slot].value = regid;
++}
++
++#define parse_mcall parse_intreg_disp
++
++static void
++parse_jospinc(const struct avr32_operand *op ATTRIBUTE_UNUSED,
++            char *str, int opindex ATTRIBUTE_UNUSED)
++{
++  expressionS exp;
++  int slot;
++  char *save;
++
++  save = input_line_pointer;
++  input_line_pointer = str;
++  expression(&exp);
++  input_line_pointer = save;
++
++  slot = current_insn.next_slot++;
++
++  if (exp.X_op == O_constant)
++    {
++      if (exp.X_add_number > 0)
++      exp.X_add_number--;
++      current_insn.field_value[slot].value = exp.X_add_number;
++    }
++  else
++    as_bad(_("invalid numeric expression `%s'"), str);
++}
++
++#define parse_coh             parse_nothing
++#if 0
++static void
++parse_fpreg(const struct avr32_operand *op,
++          char *str, int opindex ATTRIBUTE_UNUSED)
++{
++  unsigned long regid;
++  int slot;
++
++  regid = strtoul(str + 2, NULL, 10);
++
++  if ((regid >= 16) || (regid & ((1 << op->align_order) - 1)))
++    as_bad(_("invalid floating-point register `%s'"), str);
++
++  slot = current_insn.next_slot++;
++  current_insn.field_value[slot].value = regid;
++  current_insn.field_value[slot].align_order = op->align_order;
++}
++#endif
++
++static void
++parse_picoreg(const struct avr32_operand *op,
++            char *str, int opindex ATTRIBUTE_UNUSED)
++{
++  unsigned long regid;
++  int slot;
++
++  regid = avr32_parse_picoreg(str);
++  if (regid & ((1 << op->align_order) - 1))
++    as_bad(_("invalid double-word PiCo register `%s'"), str);
++
++  slot = current_insn.next_slot++;
++  current_insn.field_value[slot].value = regid;
++  current_insn.field_value[slot].align_order = op->align_order;
++}
++
++static void
++parse_pico_reglist_w(const struct avr32_operand *op ATTRIBUTE_UNUSED,
++                   char *str, int opindex ATTRIBUTE_UNUSED)
++{
++  unsigned long regmask;
++  int slot, h_bit = 0;
++  char *tail;
++
++  regmask = avr32_parse_pico_reglist(str, &tail);
++  if (*tail)
++    as_bad(_("junk at end of line: `%s'"), tail);
++
++  if (regmask & 0x00ffUL)
++    {
++      if (regmask & 0xff00UL)
++      as_bad(_("register list `%s' doesn't fit"), str);
++      regmask &= 0x00ffUL;
++    }
++  else if (regmask & 0xff00UL)
++    {
++      regmask >>= 8;
++      h_bit = 1;
++    }
++  else
++    as_warn(_("register list is empty"));
++
++  slot = current_insn.next_slot++;
++  current_insn.field_value[slot].value = regmask;
++  slot = current_insn.next_slot++;
++  current_insn.field_value[slot].value = h_bit;
++}
++
++static void
++parse_pico_reglist_d(const struct avr32_operand *op ATTRIBUTE_UNUSED,
++                   char *str, int opindex ATTRIBUTE_UNUSED)
++{
++  unsigned long regmask, regmask_d = 0;
++  int slot, i;
++  char *tail;
++
++  regmask = avr32_parse_pico_reglist(str, &tail);
++  if (*tail)
++    as_bad(_("junk at end of line: `%s'"), tail);
++
++  for (i = 0; i < 8; i++)
++    {
++      if (regmask & 1)
++      {
++        if (!(regmask & 2))
++          {
++            as_bad(_("register list `%s' doesn't fit"), str);
++            break;
++          }
++        regmask_d |= 1 << i;
++      }
++      else if (regmask & 2)
++      {
++        as_bad(_("register list `%s' doesn't fit"), str);
++        break;
++      }
++
++      regmask >>= 2;
++    }
++
++  slot = current_insn.next_slot++;
++  current_insn.field_value[slot].value = regmask_d;
++}
++
++static void
++parse_pico_in(const struct avr32_operand *op ATTRIBUTE_UNUSED,
++            char *str, int opindex ATTRIBUTE_UNUSED)
++{
++  unsigned long regid;
++  int slot;
++
++  regid = strtoul(str + 2, NULL, 10);
++
++  if (regid >= 12)
++    as_bad(_("invalid PiCo IN register `%s'"), str);
++
++  slot = current_insn.next_slot++;
++  current_insn.field_value[slot].value = regid;
++  current_insn.field_value[slot].align_order = 0;
++}
++
++#define parse_pico_out0               parse_nothing
++#define parse_pico_out1               parse_nothing
++#define parse_pico_out2               parse_nothing
++#define parse_pico_out3               parse_nothing
++
++#define OP(name, sgn, pcrel, align, func) \
++  { AVR32_OPERAND_##name, sgn, pcrel, align, match_##func, parse_##func }
++
++struct avr32_operand avr32_operand_table[] = {
++  OP(INTREG, 0, 0, 0, intreg),
++  OP(INTREG_PREDEC, 0, 0, 0, intreg_predec),
++  OP(INTREG_POSTINC, 0, 0, 0, intreg_postinc),
++  OP(INTREG_LSL, 0, 0, 0, intreg_lsl),
++  OP(INTREG_LSR, 0, 0, 0, intreg_lsr),
++  OP(INTREG_BSEL, 0, 0, 0, intreg_part),
++  OP(INTREG_HSEL, 0, 0, 1, intreg_part),
++  OP(INTREG_SDISP, 1, 0, 0, intreg_disp),
++  OP(INTREG_SDISP_H, 1, 0, 1, intreg_disp),
++  OP(INTREG_SDISP_W, 1, 0, 2, intreg_disp),
++  OP(INTREG_UDISP, 0, 0, 0, intreg_disp),
++  OP(INTREG_UDISP_H, 0, 0, 1, intreg_disp),
++  OP(INTREG_UDISP_W, 0, 0, 2, intreg_disp),
++  OP(INTREG_INDEX, 0, 0, 0, intreg_index),
++  OP(INTREG_XINDEX, 0, 0, 0, intreg_xindex),
++  OP(DWREG, 0, 0, 1, intreg),
++  OP(PC_UDISP_W, 0, 1, 2, pc_disp),
++  OP(SP, 0, 0, 0, sp),
++  OP(SP_UDISP_W, 0, 0, 2, sp_disp),
++  OP(CPNO, 0, 0, 0, cpno),
++  OP(CPREG, 0, 0, 0, cpreg),
++  OP(CPREG_D, 0, 0, 1, cpreg),
++  OP(UNSIGNED_CONST, 0, 0, 0, const),
++  OP(UNSIGNED_CONST_W, 0, 0, 2, const),
++  OP(SIGNED_CONST, 1, 0, 0, const),
++  OP(SIGNED_CONST_W, 1, 0, 2, const),
++  OP(JMPLABEL, 1, 1, 1, jmplabel),
++  OP(UNSIGNED_NUMBER, 0, 0, 0, number),
++  OP(UNSIGNED_NUMBER_W, 0, 0, 2, number),
++  OP(REGLIST8, 0, 0, 0, reglist8),
++  OP(REGLIST9, 0, 0, 0, reglist9),
++  OP(REGLIST16, 0, 0, 0, reglist16),
++  OP(REGLIST_LDM, 0, 0, 0, reglist_ldm),
++  OP(REGLIST_CP8, 0, 0, 0, reglist_cp8),
++  OP(REGLIST_CPD8, 0, 0, 0, reglist_cpd8),
++  OP(RETVAL, 0, 0, 0, retval),
++  OP(MCALL, 1, 0, 2, mcall),
++  OP(JOSPINC, 0, 0, 0, jospinc),
++  OP(COH, 0, 0, 0, coh),
++  OP(PICO_REG_W, 0, 0, 0, picoreg),
++  OP(PICO_REG_D, 0, 0, 1, picoreg),
++  OP(PICO_REGLIST_W, 0, 0, 0, pico_reglist_w),
++  OP(PICO_REGLIST_D, 0, 0, 0, pico_reglist_d),
++  OP(PICO_IN, 0, 0, 0, pico_in),
++  OP(PICO_OUT0, 0, 0, 0, pico_out0),
++  OP(PICO_OUT1, 0, 0, 0, pico_out1),
++  OP(PICO_OUT2, 0, 0, 0, pico_out2),
++  OP(PICO_OUT3, 0, 0, 0, pico_out3),
++};
++
++symbolS *
++md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
++{
++  pr_debug("md_undefined_symbol: %s\n", name);
++  return 0;
++}
++
++struct avr32_relax_type
++{
++  long lower_bound;
++  long upper_bound;
++  unsigned char align;
++  unsigned char length;
++  signed short next;
++};
++
++#define EMPTY { 0, 0, 0, 0, -1 }
++#define C(lower, upper, align, next)                  \
++  { (lower), (upper), (align), 2, AVR32_OPC_##next }
++#define E(lower, upper, align)                                \
++  { (lower), (upper), (align), 4, -1 }
++
++static const struct avr32_relax_type avr32_relax_table[] =
++  {
++    /* 0 */
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    EMPTY, EMPTY, EMPTY,
++    E(0, 65535, 0), E(0, 65535, 0), E(0, 65535, 0), E(0, 65535, 0),
++    EMPTY,
++    /* 16 */
++    EMPTY, EMPTY, EMPTY, EMPTY,
++
++    C(-256, 254, 1, BREQ2), C(-256, 254, 1, BRNE2),
++    C(-256, 254, 1, BRCC2), C(-256, 254, 1, BRCS2),
++    C(-256, 254, 1, BRGE2), C(-256, 254, 1, BRLT2),
++    C(-256, 254, 1, BRMI2), C(-256, 254, 1, BRPL2),
++    E(-2097152, 2097150, 1), E(-2097152, 2097150, 1),
++    E(-2097152, 2097150, 1), E(-2097152, 2097150, 1),
++    /* 32 */
++    E(-2097152, 2097150, 1), E(-2097152, 2097150, 1),
++    E(-2097152, 2097150, 1), E(-2097152, 2097150, 1),
++    E(-2097152, 2097150, 1), E(-2097152, 2097150, 1),
++    E(-2097152, 2097150, 1), E(-2097152, 2097150, 1),
++    E(-2097152, 2097150, 1), E(-2097152, 2097150, 1),
++    E(-2097152, 2097150, 1), E(-2097152, 2097150, 1),
++
++    EMPTY, EMPTY, EMPTY, EMPTY,
++    /* 48 */
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    EMPTY, EMPTY, EMPTY,
++
++    C(-32, 31, 0, CP_W3), E(-1048576, 1048575, 0),
++
++    EMPTY, EMPTY, EMPTY,
++    /* 64: csrfcz */
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    E(0, 65535, 0), E(0, 65535, 0),
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    E(-32768, 32767, 0),
++    /* 80: LD_SB2 */
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++
++    C(0, 7, 0, LD_UB4), E(-32768, 32767, 0),
++
++    EMPTY,
++    EMPTY, EMPTY,
++
++    C(0, 14, 1, LD_SH4), E(-32768, 32767, 0),
++
++    EMPTY, EMPTY, EMPTY,
++
++    C(0, 14, 1, LD_UH4),
++
++    /* 96: LD_UH4 */
++    E(-32768, 32767, 0),
++
++    EMPTY, EMPTY, EMPTY, EMPTY,
++
++    C(0, 124, 2, LD_W4), E(-32768, 32767, 0),
++
++    E(0, 1020, 2),    /* LDC_D1 */
++    EMPTY, EMPTY,
++    E(0, 1020, 2),    /* LDC_W1 */
++    EMPTY, EMPTY,
++    E(0, 16380, 2),   /* LDC0_D */
++    E(0, 16380, 2),   /* LDC0_W */
++    EMPTY,
++
++    /* 112: LDCM_D_PU */
++    EMPTY, EMPTY, EMPTY,
++
++    C(0, 508, 2, LDDPC_EXT), E(-32768, 32767, 0),
++
++    EMPTY,EMPTY, EMPTY,
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    /* 134: MACHH_W */
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    E(-131072, 131068, 2),    /* MCALL */
++    E(0, 1020, 2),            /* MFDR */
++    E(0, 1020, 2),            /* MFSR */
++    EMPTY, EMPTY,
++
++    C(-128, 127, 0, MOV2), E(-1048576, 1048575, 0),
++
++    EMPTY, EMPTY, EMPTY,
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++
++    E(-128, 127, 0),          /* MOVEQ2 */
++    E(-128, 127, 0),          /* MOVNE2 */
++    E(-128, 127, 0),          /* MOVCC2 */
++    E(-128, 127, 0),          /* 166: MOVCS2 */
++    E(-128, 127, 0),          /* MOVGE2 */
++    E(-128, 127, 0),          /* MOVLT2 */
++    E(-128, 127, 0),          /* MOVMI2 */
++    E(-128, 127, 0),          /* MOVPL2 */
++    E(-128, 127, 0),          /* MOVLS2 */
++    E(-128, 127, 0),          /* MOVGT2 */
++    E(-128, 127, 0),          /* MOVLE2 */
++    E(-128, 127, 0),          /* MOVHI2 */
++    E(-128, 127, 0),          /* MOVVS2 */
++    E(-128, 127, 0),          /* MOVVC2 */
++    E(-128, 127, 0),          /* MOVQS2 */
++    E(-128, 127, 0),          /* MOVAL2 */
++
++    E(0, 1020, 2),            /* MTDR */
++    E(0, 1020, 2),            /* MTSR */
++    EMPTY,
++    EMPTY,
++    E(-128, 127, 0),          /* MUL3 */
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    /* 198: MVCR_W */
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    E(0, 65535, 0), E(0, 65535, 0),
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    /* 230: PASR_H */
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    /* 262: PUNPCKSB_H */
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++
++    C(-1024, 1022, 1, RCALL2), E(-2097152, 2097150, 1),
++
++    EMPTY,
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    EMPTY, EMPTY, EMPTY,
++
++    C(-1024, 1022, 1, BRAL),
++
++    EMPTY, EMPTY, EMPTY,
++    E(-128, 127, 0),          /* RSUB2 */
++    /* 294: SATADD_H */
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    E(0, 255, 0),             /* SLEEP */
++    EMPTY, EMPTY,
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    /* 326: ST_B2 */
++    EMPTY, EMPTY,
++    C(0, 7, 0, ST_B4), E(-32768, 32767, 0),
++    EMPTY, EMPTY, EMPTY, EMPTY,
++    E(-32768, 32767, 0),
++    EMPTY, EMPTY, EMPTY,
++    C(0, 14, 1, ST_H4), E(-32768, 32767, 0),
++    EMPTY, EMPTY,
++    EMPTY,
++    C(0, 60, 2, ST_W4), E(-32768, 32767, 0),
++    E(0, 1020, 2),    /* STC_D1 */
++    EMPTY, EMPTY,
++    E(0, 1020, 2),    /* STC_W1 */
++    EMPTY, EMPTY,
++    E(0, 16380, 2),   /* STC0_D */
++    E(0, 16380, 2),   /* STC0_W */
++
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    /* 358: STDSP */
++    EMPTY, EMPTY,
++    E(0, 1020, 2),    /* STHH_W1 */
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    EMPTY, EMPTY, EMPTY,
++    E(-32768, 32767, 0),
++    C(-512, 508, 2, SUB4),
++    C(-128, 127, 0, SUB4), E(-1048576, 1048576, 0),
++    /* SUB{cond} */
++    E(-128, 127, 0), E(-128, 127, 0), E(-128, 127, 0), E(-128, 127, 0),
++    E(-128, 127, 0), E(-128, 127, 0), E(-128, 127, 0), E(-128, 127, 0),
++    E(-128, 127, 0), E(-128, 127, 0), E(-128, 127, 0), E(-128, 127, 0),
++    E(-128, 127, 0), E(-128, 127, 0), E(-128, 127, 0), E(-128, 127, 0),
++    /* SUBF{cond} */
++    E(-128, 127, 0), E(-128, 127, 0), E(-128, 127, 0), E(-128, 127, 0),
++    E(-128, 127, 0), E(-128, 127, 0), E(-128, 127, 0), E(-128, 127, 0),
++    E(-128, 127, 0), E(-128, 127, 0), E(-128, 127, 0), E(-128, 127, 0),
++    E(-128, 127, 0), E(-128, 127, 0), E(-128, 127, 0), E(-128, 127, 0),
++    EMPTY,
++
++    /* 406: SWAP_B */
++    EMPTY, EMPTY, EMPTY,
++    E(0, 255, 0),     /* SYNC */
++    EMPTY, EMPTY, EMPTY, EMPTY,
++    /* 414: TST */
++    EMPTY, EMPTY, E(-65536, 65535, 2), E(-65536, 65535, 2), E(-65536, 65535, 2), EMPTY, EMPTY, EMPTY,
++    /* 422: RSUB{cond} */
++    E(-128, 127, 0), E(-128, 127, 0), E(-128, 127, 0), E(-128, 127, 0),
++    E(-128, 127, 0), E(-128, 127, 0), E(-128, 127, 0), E(-128, 127, 0),
++    E(-128, 127, 0), E(-128, 127, 0), E(-128, 127, 0), E(-128, 127, 0),
++    E(-128, 127, 0), E(-128, 127, 0), E(-128, 127, 0), E(-128, 127, 0),
++    /* 436: ADD{cond} */
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    /* 454: SUB{cond} */
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    /* 472: AND{cond} */
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    /* 486: OR{cond} */
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    /* 502: EOR{cond} */
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    /* 518: LD.w{cond} */
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    /* 534: LD.sh{cond} */
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    /* 550: LD.uh{cond} */
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    /* 566: LD.sb{cond} */
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    /* 582: LD.ub{cond} */
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    /* 596: ST.w{cond} */
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    /* 614: ST.h{cond} */
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    /* 630: ST.b{cond} */
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++    /* 646: movh */
++    E(0, 65535, 0), EMPTY, EMPTY,
++  /* 649: fmac.s */
++  EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++  EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
++  };
++
++#undef E
++#undef C
++#undef EMPTY
++
++#define AVR32_RS_NONE (-1)
++
++#define avr32_rs_size(state) (avr32_relax_table[(state)].length)
++#define avr32_rs_align(state) (avr32_relax_table[(state)].align)
++#define relax_more(state) (avr32_relax_table[(state)].next)
++
++#define opc_initial_substate(opc) ((opc)->id)
++
++static int need_relax(int subtype, offsetT distance)
++{
++  offsetT upper_bound, lower_bound;
++
++  upper_bound = avr32_relax_table[subtype].upper_bound;
++  lower_bound = avr32_relax_table[subtype].lower_bound;
++
++  if (distance & ((1 << avr32_rs_align(subtype)) - 1))
++    return 1;
++  if ((distance > upper_bound) || (distance < lower_bound))
++    return 1;
++
++  return 0;
++}
++
++enum {
++  LDA_SUBTYPE_MOV1,
++  LDA_SUBTYPE_MOV2,
++  LDA_SUBTYPE_SUB,
++  LDA_SUBTYPE_LDDPC,
++  LDA_SUBTYPE_LDW,
++  LDA_SUBTYPE_GOTLOAD,
++  LDA_SUBTYPE_GOTLOAD_LARGE,
++};
++
++enum {
++  CALL_SUBTYPE_RCALL1,
++  CALL_SUBTYPE_RCALL2,
++  CALL_SUBTYPE_MCALL_CP,
++  CALL_SUBTYPE_MCALL_GOT,
++  CALL_SUBTYPE_MCALL_LARGE,
++};
++
++#define LDA_INITIAL_SIZE      (avr32_pic ? 4 : 2)
++#define CALL_INITIAL_SIZE     2
++
++#define need_reloc(sym, seg, pcrel)                                   \
++  (!(S_IS_DEFINED(sym)                                                        \
++     && ((pcrel && S_GET_SEGMENT(sym) == seg)                         \
++       || (!pcrel && S_GET_SEGMENT(sym) == absolute_section)))        \
++   || S_FORCE_RELOC(sym, 1))
++
++/* Return an initial guess of the length by which a fragment must grow to
++   hold a branch to reach its destination.
++   Also updates fr_type/fr_subtype as necessary.
++
++   Called just before doing relaxation.
++   Any symbol that is now undefined will not become defined.
++   The guess for fr_var is ACTUALLY the growth beyond fr_fix.
++   Whatever we do to grow fr_fix or fr_var contributes to our returned value.
++   Although it may not be explicit in the frag, pretend fr_var starts with a
++   0 value.  */
++
++static int
++avr32_default_estimate_size_before_relax (fragS *fragP, segT segment)
++{
++  int growth = 0;
++
++  assert(fragP);
++  assert(fragP->fr_symbol);
++
++  if (fragP->tc_frag_data.force_extended
++      || need_reloc(fragP->fr_symbol, segment, fragP->tc_frag_data.pcrel))
++    {
++      int largest_state = fragP->fr_subtype;
++      while (relax_more(largest_state) != AVR32_RS_NONE)
++      largest_state = relax_more(largest_state);
++      growth = avr32_rs_size(largest_state) - fragP->fr_var;
++    }
++  else
++    {
++      growth = avr32_rs_size(fragP->fr_subtype) - fragP->fr_var;
++    }
++
++  pr_debug("%s:%d: md_estimate_size_before_relax: %d\n",
++         fragP->fr_file, fragP->fr_line, growth);
++
++  return growth;
++}
++
++static int
++avr32_lda_estimate_size_before_relax(fragS *fragP, segT segment ATTRIBUTE_UNUSED)
++{
++  return fragP->fr_var - LDA_INITIAL_SIZE;
++}
++
++static int
++avr32_call_estimate_size_before_relax(fragS *fragP, segT segment ATTRIBUTE_UNUSED)
++{
++  return fragP->fr_var - CALL_INITIAL_SIZE;
++}
++
++static int
++avr32_cpool_estimate_size_before_relax(fragS *fragP,
++                                     segT segment ATTRIBUTE_UNUSED)
++{
++  return fragP->fr_var;
++}
++
++/* This macro may be defined to relax a frag. GAS will call this with the
++ * segment, the frag, and the change in size of all previous frags;
++ * md_relax_frag should return the change in size of the frag. */
++static long
++avr32_default_relax_frag (segT segment, fragS *fragP, long stretch)
++{
++  int state, next_state;
++  symbolS *symbolP;   /* The target symbol */
++  long growth = 0;
++
++  state = next_state = fragP->fr_subtype;
++
++  symbolP = fragP->fr_symbol;
++
++  if (fragP->tc_frag_data.force_extended
++      || need_reloc(symbolP, segment, fragP->tc_frag_data.pcrel))
++    {
++      /* Symbol must be resolved by the linker. Emit the largest
++       possible opcode. */
++      while (relax_more(next_state) != AVR32_RS_NONE)
++      next_state = relax_more(next_state);
++    }
++  else
++    {
++      addressT address;       /* The address of fragP */
++      addressT target;        /* The address of the target symbol */
++      offsetT distance;       /* The distance between the insn and the symbol */
++      fragS *sym_frag;
++
++      address = fragP->fr_address;
++      target = fragP->fr_offset;
++      symbolP = fragP->fr_symbol;
++      sym_frag = symbol_get_frag(symbolP);
++
++      address += fragP->fr_fix - fragP->fr_var;
++      target += S_GET_VALUE(symbolP);
++
++      if (stretch != 0
++        && sym_frag->relax_marker != fragP->relax_marker
++        && S_GET_SEGMENT(symbolP) == segment)
++      /* if it was correctly aligned before, make sure it stays aligned */
++      target += stretch & (~0UL << avr32_rs_align(state));
++
++      if (fragP->tc_frag_data.pcrel)
++      distance = target - (address & (~0UL << avr32_rs_align(state)));
++      else
++      distance = target;
++
++      pr_debug("%s:%d: relax more? 0x%x - 0x%x = 0x%x (%d), align %d\n",
++             fragP->fr_file, fragP->fr_line, target, address,
++             distance, distance, avr32_rs_align(state));
++
++      if (need_relax(state, distance))
++      {
++        if (relax_more(state) != AVR32_RS_NONE)
++          next_state = relax_more(state);
++        pr_debug("%s:%d: relax more %d -> %d (%d - %d, align %d)\n",
++                 fragP->fr_file, fragP->fr_line, state, next_state,
++                 target, address, avr32_rs_align(state));
++      }
++    }
++
++  growth = avr32_rs_size(next_state) - avr32_rs_size(state);
++  fragP->fr_subtype = next_state;
++
++  pr_debug("%s:%d: md_relax_frag: growth=%d, subtype=%d, opc=0x%08lx\n",
++         fragP->fr_file, fragP->fr_line, growth, fragP->fr_subtype,
++         avr32_opc_table[next_state].value);
++
++  return growth;
++}
++
++static long
++avr32_lda_relax_frag(segT segment, fragS *fragP, long stretch)
++{
++  struct cpool *pool= NULL;
++  unsigned int entry = 0;
++  addressT address, target;
++  offsetT distance;
++  symbolS *symbolP;
++  fragS *sym_frag;
++  long old_size, new_size;
++
++  symbolP = fragP->fr_symbol;
++  old_size = fragP->fr_var;
++  if (!avr32_pic)
++    {
++      pool = fragP->tc_frag_data.pool;
++      entry = fragP->tc_frag_data.pool_entry;
++    }
++
++  address = fragP->fr_address;
++  address += fragP->fr_fix - LDA_INITIAL_SIZE;
++
++  if (!S_IS_DEFINED(symbolP) || S_FORCE_RELOC(symbolP, 1))
++    goto relax_max;
++
++  target = fragP->fr_offset;
++  sym_frag = symbol_get_frag(symbolP);
++  target += S_GET_VALUE(symbolP);
++
++  if (sym_frag->relax_marker != fragP->relax_marker
++      && S_GET_SEGMENT(symbolP) == segment)
++    target += stretch;
++
++  distance = target - address;
++
++  pr_debug("lda_relax_frag: target: %d, address: %d, var: %d\n",
++         target, address, fragP->fr_var);
++
++  if (!avr32_pic && S_GET_SEGMENT(symbolP) == absolute_section
++      && target <= 127 && (offsetT)target >= -128)
++    {
++      if (fragP->fr_subtype == LDA_SUBTYPE_LDDPC
++        || fragP->fr_subtype == LDA_SUBTYPE_LDW)
++      pool->literals[entry].refcount--;
++      new_size = 2;
++      fragP->fr_subtype = LDA_SUBTYPE_MOV1;
++    }
++  else if (!avr32_pic && S_GET_SEGMENT(symbolP) == absolute_section
++         && target <= 1048575 && (offsetT)target >= -1048576)
++    {
++      if (fragP->fr_subtype == LDA_SUBTYPE_LDDPC
++        || fragP->fr_subtype == LDA_SUBTYPE_LDW)
++      pool->literals[entry].refcount--;
++      new_size = 4;
++      fragP->fr_subtype = LDA_SUBTYPE_MOV2;
++    }
++  else if (!linkrelax && S_GET_SEGMENT(symbolP) == segment
++         /* the field will be negated, so this is really -(-32768)
++            and -(32767) */
++         && distance <= 32768 && distance >= -32767)
++    {
++      if (!avr32_pic
++        && (fragP->fr_subtype == LDA_SUBTYPE_LDDPC
++            || fragP->fr_subtype == LDA_SUBTYPE_LDW))
++      pool->literals[entry].refcount--;
++      new_size = 4;
++      fragP->fr_subtype = LDA_SUBTYPE_SUB;
++    }
++  else
++    {
++    relax_max:
++      if (avr32_pic)
++      {
++        if (linkrelax)
++          {
++            new_size = 8;
++            fragP->fr_subtype = LDA_SUBTYPE_GOTLOAD_LARGE;
++          }
++        else
++          {
++            new_size = 4;
++            fragP->fr_subtype = LDA_SUBTYPE_GOTLOAD;
++          }
++      }
++      else
++      {
++        if (fragP->fr_subtype != LDA_SUBTYPE_LDDPC
++            && fragP->fr_subtype != LDA_SUBTYPE_LDW)
++          pool->literals[entry].refcount++;
++
++        sym_frag = symbol_get_frag(pool->symbol);
++        target = (sym_frag->fr_address + sym_frag->fr_fix
++                  + pool->padding + pool->literals[entry].offset);
++
++        pr_debug("cpool sym address: 0x%lx\n",
++                 sym_frag->fr_address + sym_frag->fr_fix);
++
++        know(pool->section == segment);
++
++        if (sym_frag->relax_marker != fragP->relax_marker)
++          target += stretch;
++
++        distance = target - address;
++        if (distance <= 508 && distance >= 0)
++          {
++            new_size = 2;
++            fragP->fr_subtype = LDA_SUBTYPE_LDDPC;
++          }
++        else
++          {
++            new_size = 4;
++            fragP->fr_subtype = LDA_SUBTYPE_LDW;
++          }
++
++        pr_debug("lda_relax_frag (cpool): target=0x%lx, address=0x%lx, refcount=%d\n",
++                 target, address, pool->literals[entry].refcount);
++      }
++    }
++
++  fragP->fr_var = new_size;
++
++  pr_debug("%s:%d: lda: relax pass done. subtype: %d, growth: %ld\n",
++         fragP->fr_file, fragP->fr_line,
++         fragP->fr_subtype, new_size - old_size);
++
++  return new_size - old_size;
++}
++
++static long
++avr32_call_relax_frag(segT segment, fragS *fragP, long stretch)
++{
++  struct cpool *pool = NULL;
++  unsigned int entry = 0;
++  addressT address, target;
++  offsetT distance;
++  symbolS *symbolP;
++  fragS *sym_frag;
++  long old_size, new_size;
++
++  symbolP = fragP->fr_symbol;
++  old_size = fragP->fr_var;
++  if (!avr32_pic)
++    {
++      pool = fragP->tc_frag_data.pool;
++      entry = fragP->tc_frag_data.pool_entry;
++    }
++
++  address = fragP->fr_address;
++  address += fragP->fr_fix - CALL_INITIAL_SIZE;
++
++  if (need_reloc(symbolP, segment, 1))
++    {
++      pr_debug("call: must emit reloc\n");
++      goto relax_max;
++    }
++
++  target = fragP->fr_offset;
++  sym_frag = symbol_get_frag(symbolP);
++  target += S_GET_VALUE(symbolP);
++
++  if (sym_frag->relax_marker != fragP->relax_marker
++      && S_GET_SEGMENT(symbolP) == segment)
++    target += stretch;
++
++  distance = target - address;
++
++  if (distance <= 1022 && distance >= -1024)
++    {
++      pr_debug("call: distance is %d, emitting short rcall\n", distance);
++      if (!avr32_pic && fragP->fr_subtype == CALL_SUBTYPE_MCALL_CP)
++      pool->literals[entry].refcount--;
++      new_size = 2;
++      fragP->fr_subtype = CALL_SUBTYPE_RCALL1;
++    }
++  else if (distance <= 2097150 && distance >= -2097152)
++    {
++      pr_debug("call: distance is %d, emitting long rcall\n", distance);
++      if (!avr32_pic && fragP->fr_subtype == CALL_SUBTYPE_MCALL_CP)
++      pool->literals[entry].refcount--;
++      new_size = 4;
++      fragP->fr_subtype = CALL_SUBTYPE_RCALL2;
++    }
++  else
++    {
++      pr_debug("call: distance %d too far, emitting something big\n", distance);
++
++    relax_max:
++      if (avr32_pic)
++      {
++        if (linkrelax)
++          {
++            new_size = 10;
++            fragP->fr_subtype = CALL_SUBTYPE_MCALL_LARGE;
++          }
++        else
++          {
++            new_size = 4;
++            fragP->fr_subtype = CALL_SUBTYPE_MCALL_GOT;
++          }
++      }
++      else
++      {
++        if (fragP->fr_subtype != CALL_SUBTYPE_MCALL_CP)
++          pool->literals[entry].refcount++;
++
++        new_size = 4;
++        fragP->fr_subtype = CALL_SUBTYPE_MCALL_CP;
++      }
++    }
++
++  fragP->fr_var = new_size;
++
++  pr_debug("%s:%d: call: relax pass done, growth: %d, fr_var: %d\n",
++         fragP->fr_file, fragP->fr_line,
++         new_size - old_size, fragP->fr_var);
++
++  return new_size - old_size;
++}
++
++static long
++avr32_cpool_relax_frag(segT segment ATTRIBUTE_UNUSED,
++                     fragS *fragP,
++                     long stretch ATTRIBUTE_UNUSED)
++{
++  struct cpool *pool;
++  addressT address;
++  long old_size, new_size;
++  unsigned int entry;
++
++  pool = fragP->tc_frag_data.pool;
++  address = fragP->fr_address + fragP->fr_fix;
++  old_size = fragP->fr_var;
++  new_size = 0;
++
++  for (entry = 0; entry < pool->next_free_entry; entry++)
++    {
++      if (pool->literals[entry].refcount > 0)
++      {
++        pool->literals[entry].offset = new_size;
++        new_size += 4;
++      }
++    }
++
++  fragP->fr_var = new_size;
++
++  return new_size - old_size;
++}
++
++/* *fragP has been relaxed to its final size, and now needs to have
++   the bytes inside it modified to conform to the new size.
++
++   Called after relaxation is finished.
++   fragP->fr_type == rs_machine_dependent.
++   fragP->fr_subtype is the subtype of what the address relaxed to.  */
++
++static void
++avr32_default_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
++                          segT segment ATTRIBUTE_UNUSED,
++                          fragS *fragP)
++{
++  const struct avr32_opcode *opc;
++  const struct avr32_ifield *ifield;
++  bfd_reloc_code_real_type r_type;
++  symbolS *symbolP;
++  fixS *fixP;
++  bfd_vma value;
++  int subtype;
++
++  opc = &avr32_opc_table[fragP->fr_subtype];
++  ifield = opc->fields[opc->var_field];
++  symbolP = fragP->fr_symbol;
++  subtype = fragP->fr_subtype;
++  r_type = opc->reloc_type;
++
++  /* Clear the opcode bits and the bits belonging to the relaxed
++     field.  We assume all other fields stay the same.  */
++  value = bfd_getb32(fragP->fr_opcode);
++  value &= ~(opc->mask | ifield->mask);
++
++  /* Insert the new opcode */
++  value |= opc->value;
++  bfd_putb32(value, fragP->fr_opcode);
++
++  fragP->fr_fix += opc->size - fragP->fr_var;
++
++  if (fragP->tc_frag_data.reloc_info != AVR32_OPINFO_NONE)
++    {
++      switch (fragP->tc_frag_data.reloc_info)
++      {
++      case AVR32_OPINFO_HI:
++        r_type = BFD_RELOC_HI16;
++        break;
++      case AVR32_OPINFO_LO:
++        r_type = BFD_RELOC_LO16;
++        break;
++      case AVR32_OPINFO_GOT:
++        switch (r_type)
++          {
++          case BFD_RELOC_AVR32_18W_PCREL:
++            r_type = BFD_RELOC_AVR32_GOT18SW;
++            break;
++          case BFD_RELOC_AVR32_16S:
++            r_type = BFD_RELOC_AVR32_GOT16S;
++            break;
++          default:
++            BAD_CASE(r_type);
++            break;
++          }
++        break;
++      default:
++        BAD_CASE(fragP->tc_frag_data.reloc_info);
++        break;
++      }
++    }
++
++  pr_debug("%s:%d: convert_frag: new %s fixup\n",
++         fragP->fr_file, fragP->fr_line,
++         bfd_get_reloc_code_name(r_type));
++
++#if 1
++  fixP = fix_new_exp(fragP, fragP->fr_fix - opc->size, opc->size,
++                   &fragP->tc_frag_data.exp,
++                   fragP->tc_frag_data.pcrel, r_type);
++#else
++  fixP = fix_new(fragP, fragP->fr_fix - opc->size, opc->size, symbolP,
++               fragP->fr_offset, fragP->tc_frag_data.pcrel, r_type);
++#endif
++
++  /* Revert fix_new brain damage. "dot_value" is the value of PC at
++     the point of the fixup, relative to the frag address.  fix_new()
++     and friends think they are only being called during the assembly
++     pass, not during relaxation or similar, so fx_dot_value, fx_file
++     and fx_line are all initialized to the wrong value.  But we don't
++     know the size of the fixup until now, so we really can't live up
++     to the assumptions these functions make about the target.  What
++     do these functions think the "where" and "frag" argument mean
++     anyway?  */
++  fixP->fx_dot_value = fragP->fr_fix - opc->size;
++  fixP->fx_file = fragP->fr_file;
++  fixP->fx_line = fragP->fr_line;
++
++  fixP->tc_fix_data.ifield = ifield;
++  fixP->tc_fix_data.align = avr32_rs_align(subtype);
++  fixP->tc_fix_data.min = avr32_relax_table[subtype].lower_bound;
++  fixP->tc_fix_data.max = avr32_relax_table[subtype].upper_bound;
++}
++
++static void
++avr32_lda_convert_frag(bfd *abfd ATTRIBUTE_UNUSED,
++                     segT segment ATTRIBUTE_UNUSED,
++                     fragS *fragP)
++{
++  const struct avr32_opcode *opc;
++  const struct avr32_ifield *ifield;
++  bfd_reloc_code_real_type r_type;
++  expressionS exp;
++  struct cpool *pool;
++  fixS *fixP;
++  bfd_vma value;
++  int regid, pcrel = 0, align = 0;
++  char *p;
++
++  r_type = BFD_RELOC_NONE;
++  regid = fragP->tc_frag_data.reloc_info;
++  p = fragP->fr_opcode;
++  exp.X_add_symbol = fragP->fr_symbol;
++  exp.X_add_number = fragP->fr_offset;
++  exp.X_op = O_symbol;
++
++  pr_debug("%s:%d: lda_convert_frag, subtype: %d, fix: %d, var: %d, regid: %d\n",
++         fragP->fr_file, fragP->fr_line,
++         fragP->fr_subtype, fragP->fr_fix, fragP->fr_var, regid);
++
++  switch (fragP->fr_subtype)
++    {
++    case LDA_SUBTYPE_MOV1:
++      opc = &avr32_opc_table[AVR32_OPC_MOV1];
++      opc->fields[0]->insert(opc->fields[0], p, regid);
++      ifield = opc->fields[1];
++      r_type = opc->reloc_type;
++      break;
++    case LDA_SUBTYPE_MOV2:
++      opc = &avr32_opc_table[AVR32_OPC_MOV2];
++      opc->fields[0]->insert(opc->fields[0], p, regid);
++      ifield = opc->fields[1];
++      r_type = opc->reloc_type;
++      break;
++    case LDA_SUBTYPE_SUB:
++      opc = &avr32_opc_table[AVR32_OPC_SUB5];
++      opc->fields[0]->insert(opc->fields[0], p, regid);
++      opc->fields[1]->insert(opc->fields[1], p, AVR32_REG_PC);
++      ifield = opc->fields[2];
++      r_type = BFD_RELOC_AVR32_16N_PCREL;
++
++      /* Pretend that SUB5 isn't a "negated" pcrel expression for now.
++       We'll have to fix it up later when we know whether to
++       generate a reloc for it (in which case the linker will negate
++       it, so we shouldn't). */
++      pcrel = 1;
++      break;
++    case LDA_SUBTYPE_LDDPC:
++      opc = &avr32_opc_table[AVR32_OPC_LDDPC];
++      align = 2;
++      r_type = BFD_RELOC_AVR32_9W_CP;
++      goto cpool_common;
++    case LDA_SUBTYPE_LDW:
++      opc = &avr32_opc_table[AVR32_OPC_LDDPC_EXT];
++      r_type = BFD_RELOC_AVR32_16_CP;
++    cpool_common:
++      opc->fields[0]->insert(opc->fields[0], p, regid);
++      ifield = opc->fields[1];
++      pool = fragP->tc_frag_data.pool;
++      exp.X_add_symbol = pool->symbol;
++      exp.X_add_number = pool->literals[fragP->tc_frag_data.pool_entry].offset;
++      pcrel = 1;
++      break;
++    case LDA_SUBTYPE_GOTLOAD_LARGE:
++      /* ld.w Rd, r6[Rd << 2] (last) */
++      opc = &avr32_opc_table[AVR32_OPC_LD_W5];
++      bfd_putb32(opc->value, p + 4);
++      opc->fields[0]->insert(opc->fields[0], p + 4, regid);
++      opc->fields[1]->insert(opc->fields[1], p + 4, 6);
++      opc->fields[2]->insert(opc->fields[2], p + 4, regid);
++      opc->fields[3]->insert(opc->fields[3], p + 4, 2);
++
++      /* mov Rd, (got_offset / 4) */
++      opc = &avr32_opc_table[AVR32_OPC_MOV2];
++      opc->fields[0]->insert(opc->fields[0], p, regid);
++      ifield = opc->fields[1];
++      r_type = BFD_RELOC_AVR32_LDA_GOT;
++      break;
++    case LDA_SUBTYPE_GOTLOAD:
++      opc = &avr32_opc_table[AVR32_OPC_LD_W4];
++      opc->fields[0]->insert(opc->fields[0], p, regid);
++      opc->fields[1]->insert(opc->fields[1], p, 6);
++      ifield = opc->fields[2];
++      if (r_type == BFD_RELOC_NONE)
++      r_type = BFD_RELOC_AVR32_GOT16S;
++      break;
++    default:
++      BAD_CASE(fragP->fr_subtype);
++    }
++
++  value = bfd_getb32(p);
++  value &= ~(opc->mask | ifield->mask);
++  value |= opc->value;
++  bfd_putb32(value, p);
++
++  fragP->fr_fix += fragP->fr_var - LDA_INITIAL_SIZE;
++
++  if (fragP->fr_next
++      && ((offsetT)(fragP->fr_next->fr_address - fragP->fr_address)
++        != fragP->fr_fix))
++    {
++      fprintf(stderr, "LDA frag: fr_fix is wrong! fragP->fr_var = %ld, r_type = %s\n",
++            fragP->fr_var, bfd_get_reloc_code_name(r_type));
++      abort();
++    }
++
++  fixP = fix_new_exp(fragP, fragP->fr_fix - fragP->fr_var, fragP->fr_var,
++                   &exp, pcrel, r_type);
++
++  /* Revert fix_new brain damage. "dot_value" is the value of PC at
++     the point of the fixup, relative to the frag address.  fix_new()
++     and friends think they are only being called during the assembly
++     pass, not during relaxation or similar, so fx_dot_value, fx_file
++     and fx_line are all initialized to the wrong value.  But we don't
++     know the size of the fixup until now, so we really can't live up
++     to the assumptions these functions make about the target.  What
++     do these functions think the "where" and "frag" argument mean
++     anyway?  */
++  fixP->fx_dot_value = fragP->fr_fix - opc->size;
++  fixP->fx_file = fragP->fr_file;
++  fixP->fx_line = fragP->fr_line;
++
++  fixP->tc_fix_data.ifield = ifield;
++  fixP->tc_fix_data.align = align;
++  /* these are only used if the fixup can actually be resolved */
++  fixP->tc_fix_data.min = -32768;
++  fixP->tc_fix_data.max = 32767;
++}
++
++static void
++avr32_call_convert_frag(bfd *abfd ATTRIBUTE_UNUSED,
++                     segT segment ATTRIBUTE_UNUSED,
++                     fragS *fragP)
++{
++  const struct avr32_opcode *opc = NULL;
++  const struct avr32_ifield *ifield;
++  bfd_reloc_code_real_type r_type;
++  symbolS *symbol;
++  offsetT offset;
++  fixS *fixP;
++  bfd_vma value;
++  int pcrel = 0, align = 0;
++  char *p;
++
++  symbol = fragP->fr_symbol;
++  offset = fragP->fr_offset;
++  r_type = BFD_RELOC_NONE;
++  p = fragP->fr_opcode;
++
++  pr_debug("%s:%d: call_convert_frag, subtype: %d, fix: %d, var: %d\n",
++         fragP->fr_file, fragP->fr_line,
++         fragP->fr_subtype, fragP->fr_fix, fragP->fr_var);
++
++  switch (fragP->fr_subtype)
++    {
++    case CALL_SUBTYPE_RCALL1:
++      opc = &avr32_opc_table[AVR32_OPC_RCALL1];
++      /* fall through */
++    case CALL_SUBTYPE_RCALL2:
++      if (!opc)
++      opc = &avr32_opc_table[AVR32_OPC_RCALL2];
++      ifield = opc->fields[0];
++      r_type = opc->reloc_type;
++      pcrel = 1;
++      align = 1;
++      break;
++    case CALL_SUBTYPE_MCALL_CP:
++      opc = &avr32_opc_table[AVR32_OPC_MCALL];
++      opc->fields[0]->insert(opc->fields[0], p, AVR32_REG_PC);
++      ifield = opc->fields[1];
++      r_type = BFD_RELOC_AVR32_CPCALL;
++      symbol = fragP->tc_frag_data.pool->symbol;
++      offset = fragP->tc_frag_data.pool->literals[fragP->tc_frag_data.pool_entry].offset;
++      assert(fragP->tc_frag_data.pool->literals[fragP->tc_frag_data.pool_entry].refcount > 0);
++      pcrel = 1;
++      align = 2;
++      break;
++    case CALL_SUBTYPE_MCALL_GOT:
++      opc = &avr32_opc_table[AVR32_OPC_MCALL];
++      opc->fields[0]->insert(opc->fields[0], p, 6);
++      ifield = opc->fields[1];
++      r_type = BFD_RELOC_AVR32_GOT18SW;
++      break;
++    case CALL_SUBTYPE_MCALL_LARGE:
++      assert(fragP->fr_var == 10);
++      /* ld.w lr, r6[lr << 2] */
++      opc = &avr32_opc_table[AVR32_OPC_LD_W5];
++      bfd_putb32(opc->value, p + 4);
++      opc->fields[0]->insert(opc->fields[0], p + 4, AVR32_REG_LR);
++      opc->fields[1]->insert(opc->fields[1], p + 4, 6);
++      opc->fields[2]->insert(opc->fields[2], p + 4, AVR32_REG_LR);
++      opc->fields[3]->insert(opc->fields[3], p + 4, 2);
++
++      /* icall lr */
++      opc = &avr32_opc_table[AVR32_OPC_ICALL];
++      bfd_putb16(opc->value >> 16, p + 8);
++      opc->fields[0]->insert(opc->fields[0], p + 8, AVR32_REG_LR);
++
++      /* mov lr, (got_offset / 4) */
++      opc = &avr32_opc_table[AVR32_OPC_MOV2];
++      opc->fields[0]->insert(opc->fields[0], p, AVR32_REG_LR);
++      ifield = opc->fields[1];
++      r_type = BFD_RELOC_AVR32_GOTCALL;
++      break;
++    default:
++      BAD_CASE(fragP->fr_subtype);
++    }
++
++  /* Insert the opcode and clear the variable ifield */
++  value = bfd_getb32(p);
++  value &= ~(opc->mask | ifield->mask);
++  value |= opc->value;
++  bfd_putb32(value, p);
++
++  fragP->fr_fix += fragP->fr_var - CALL_INITIAL_SIZE;
++
++  if (fragP->fr_next
++      && ((offsetT)(fragP->fr_next->fr_address - fragP->fr_address)
++        != fragP->fr_fix))
++    {
++      fprintf(stderr, "%s:%d: fr_fix %lu is wrong! fr_var=%lu, r_type=%s\n",
++            fragP->fr_file, fragP->fr_line,
++            fragP->fr_fix, fragP->fr_var, bfd_get_reloc_code_name(r_type));
++      fprintf(stderr, "fr_fix should be %ld. next frag is %s:%d\n",
++            (offsetT)(fragP->fr_next->fr_address - fragP->fr_address),
++            fragP->fr_next->fr_file, fragP->fr_next->fr_line);
++    }
++
++  fixP = fix_new(fragP, fragP->fr_fix - fragP->fr_var, fragP->fr_var,
++               symbol, offset, pcrel, r_type);
++
++  /* Revert fix_new brain damage. "dot_value" is the value of PC at
++     the point of the fixup, relative to the frag address.  fix_new()
++     and friends think they are only being called during the assembly
++     pass, not during relaxation or similar, so fx_dot_value, fx_file
++     and fx_line are all initialized to the wrong value.  But we don't
++     know the size of the fixup until now, so we really can't live up
++     to the assumptions these functions make about the target.  What
++     do these functions think the "where" and "frag" argument mean
++     anyway?  */
++  fixP->fx_dot_value = fragP->fr_fix - opc->size;
++  fixP->fx_file = fragP->fr_file;
++  fixP->fx_line = fragP->fr_line;
++
++  fixP->tc_fix_data.ifield = ifield;
++  fixP->tc_fix_data.align = align;
++  /* these are only used if the fixup can actually be resolved */
++  fixP->tc_fix_data.min = -2097152;
++  fixP->tc_fix_data.max = 2097150;
++}
++
++static void
++avr32_cpool_convert_frag(bfd *abfd ATTRIBUTE_UNUSED,
++                       segT segment ATTRIBUTE_UNUSED,
++                       fragS *fragP)
++{
++  struct cpool *pool;
++  addressT address;
++  unsigned int entry;
++  char *p;
++  char sym_name[20];
++
++  /* Did we get rid of the frag altogether? */
++  if (!fragP->fr_var)
++    return;
++
++  pool = fragP->tc_frag_data.pool;
++  address = fragP->fr_address + fragP->fr_fix;
++  p = fragP->fr_literal + fragP->fr_fix;
++
++  sprintf(sym_name, "$$cp_\002%x", pool->id);
++  symbol_locate(pool->symbol, sym_name, pool->section, fragP->fr_fix, fragP);
++  symbol_table_insert(pool->symbol);
++
++  for (entry = 0; entry < pool->next_free_entry; entry++)
++    {
++      if (pool->literals[entry].refcount > 0)
++      {
++        fix_new_exp(fragP, fragP->fr_fix, 4, &pool->literals[entry].exp,
++                    FALSE, BFD_RELOC_AVR32_32_CPENT);
++        fragP->fr_fix += 4;
++      }
++    }
++}
++
++static struct avr32_relaxer avr32_default_relaxer = {
++  .estimate_size      = avr32_default_estimate_size_before_relax,
++  .relax_frag         = avr32_default_relax_frag,
++  .convert_frag               = avr32_default_convert_frag,
++};
++static struct avr32_relaxer avr32_lda_relaxer = {
++  .estimate_size      = avr32_lda_estimate_size_before_relax,
++  .relax_frag         = avr32_lda_relax_frag,
++  .convert_frag               = avr32_lda_convert_frag,
++};
++static struct avr32_relaxer avr32_call_relaxer = {
++  .estimate_size      = avr32_call_estimate_size_before_relax,
++  .relax_frag         = avr32_call_relax_frag,
++  .convert_frag               = avr32_call_convert_frag,
++};
++static struct avr32_relaxer avr32_cpool_relaxer = {
++  .estimate_size      = avr32_cpool_estimate_size_before_relax,
++  .relax_frag         = avr32_cpool_relax_frag,
++  .convert_frag               = avr32_cpool_convert_frag,
++};
++
++static void s_cpool(int arg ATTRIBUTE_UNUSED)
++{
++  struct cpool *pool;
++  unsigned int max_size;
++  char *buf;
++
++  pool = find_cpool(now_seg, now_subseg);
++  if (!pool || !pool->symbol || pool->next_free_entry == 0)
++    return;
++
++  /* Make sure the constant pool is properly aligned */
++  frag_align_code(2, 0);
++  if (bfd_get_section_alignment(stdoutput, pool->section) < 2)
++    bfd_set_section_alignment(stdoutput, pool->section, 2);
++
++  /* Assume none of the entries are discarded, and that we need the
++     maximum amount of alignment.  But we're not going to allocate
++     anything up front. */
++  max_size = pool->next_free_entry * 4 + 2;
++  frag_grow(max_size);
++  buf = frag_more(0);
++
++  frag_now->tc_frag_data.relaxer = &avr32_cpool_relaxer;
++  frag_now->tc_frag_data.pool = pool;
++
++  symbol_set_frag(pool->symbol, frag_now);
++
++  /* Assume zero initial size, allowing other relaxers to be
++     optimistic about things.  */
++  frag_var(rs_machine_dependent, max_size, 0,
++         0, pool->symbol, 0, NULL);
++
++  /* Mark the pool as empty.  */
++  pool->used = 1;
++}
++
++/* The location from which a PC relative jump should be calculated,
++   given a PC relative reloc.  */
++
++long
++md_pcrel_from_section (fixS *fixP, segT sec)
++{
++  pr_debug("pcrel_from_section, fx_offset = %d\n", fixP->fx_offset);
++
++  if (fixP->fx_addsy != NULL
++      && (! S_IS_DEFINED (fixP->fx_addsy)
++          || S_GET_SEGMENT (fixP->fx_addsy) != sec
++        || S_FORCE_RELOC(fixP->fx_addsy, 1)))
++    {
++      pr_debug("Unknown pcrel symbol: %s\n", S_GET_NAME(fixP->fx_addsy));
++
++      /* The symbol is undefined (or is defined but not in this section).
++       Let the linker figure it out.  */
++      return 0;
++    }
++
++  pr_debug("pcrel from %x + %x, symbol: %s (%x)\n",
++         fixP->fx_frag->fr_address, fixP->fx_where,
++         fixP->fx_addsy?S_GET_NAME(fixP->fx_addsy):"(null)",
++         fixP->fx_addsy?S_GET_VALUE(fixP->fx_addsy):0);
++
++  return ((fixP->fx_frag->fr_address + fixP->fx_where)
++        & (~0UL << fixP->tc_fix_data.align));
++}
++
++valueT
++md_section_align (segT segment, valueT size)
++{
++  int align = bfd_get_section_alignment (stdoutput, segment);
++  return ((size + (1 << align) - 1) & (-1 << align));
++}
++
++static int syntax_matches(const struct avr32_syntax *syntax,
++                        char *str)
++{
++  int i;
++
++  pr_debug("syntax %d matches `%s'?\n", syntax->id, str);
++
++  if (syntax->nr_operands < 0)
++    {
++      struct avr32_operand *op;
++      int optype;
++
++      for (i = 0; i < (-syntax->nr_operands - 1); i++)
++      {
++        char *p;
++        char c;
++
++        optype = syntax->operand[i];
++        assert(optype < AVR32_NR_OPERANDS);
++        op = &avr32_operand_table[optype];
++
++        for (p = str; *p; p++)
++          if (*p == ',')
++            break;
++
++        if (p == str)
++          return 0;
++
++        c = *p;
++        *p = 0;
++
++        if (!op->match(str))
++          {
++            *p = c;
++            return 0;
++          }
++
++        str = p;
++        *p = c;
++        if (c)
++          str++;
++      }
++
++      optype = syntax->operand[i];
++      assert(optype < AVR32_NR_OPERANDS);
++      op = &avr32_operand_table[optype];
++
++      if (!op->match(str))
++      return 0;
++      return 1;
++    }
++
++  for (i = 0; i < syntax->nr_operands; i++)
++    {
++      struct avr32_operand *op;
++      int optype = syntax->operand[i];
++      char *p;
++      char c;
++
++      assert(optype < AVR32_NR_OPERANDS);
++      op = &avr32_operand_table[optype];
++
++      for (p = str; *p; p++)
++      if (*p == ',')
++        break;
++
++      if (p == str)
++      return 0;
++
++      c = *p;
++      *p = 0;
++
++      if (!op->match(str))
++      {
++        *p = c;
++        return 0;
++      }
++
++      str = p;
++      *p = c;
++      if (c)
++      str++;
++    }
++
++  if (*str == '\0')
++    return 1;
++
++  if ((*str == 'e' || *str == 'E') && !str[1])
++    return 1;
++
++  return 0;
++}
++
++static int parse_operands(char *str)
++{
++  int i;
++
++  if (current_insn.syntax->nr_operands < 0)
++    {
++      int optype;
++      struct avr32_operand *op;
++
++      for (i = 0; i < (-current_insn.syntax->nr_operands - 1); i++)
++      {
++        char *p;
++        char c;
++
++        optype = current_insn.syntax->operand[i];
++        op = &avr32_operand_table[optype];
++
++        for (p = str; *p; p++)
++          if (*p == ',')
++            break;
++
++        assert(p != str);
++
++        c = *p, *p = 0;
++        op->parse(op, str, i);
++        *p = c;
++
++        str = p;
++        if (c) str++;
++      }
++
++      /* give the rest of the line to the last operand */
++      optype = current_insn.syntax->operand[i];
++      op = &avr32_operand_table[optype];
++      op->parse(op, str, i);
++    }
++  else
++    {
++      for (i = 0; i < current_insn.syntax->nr_operands; i++)
++      {
++        int optype = current_insn.syntax->operand[i];
++        struct avr32_operand *op = &avr32_operand_table[optype];
++        char *p;
++        char c;
++
++        skip_whitespace(str);
++
++        for (p = str; *p; p++)
++          if (*p == ',')
++            break;
++
++        assert(p != str);
++
++        c = *p, *p = 0;
++        op->parse(op, str, i);
++        *p = c;
++
++        str = p;
++        if (c) str++;
++      }
++
++      if (*str == 'E' || *str == 'e')
++      current_insn.force_extended = 1;
++    }
++
++  return 0;
++}
++
++static const char *
++finish_insn(const struct avr32_opcode *opc)
++{
++  expressionS *exp = &current_insn.immediate;
++  unsigned int i;
++  int will_relax = 0;
++  char *buf;
++
++  assert(current_insn.next_slot == opc->nr_fields);
++
++  pr_debug("%s:%d: finish_insn: trying opcode %d\n",
++         frag_now->fr_file, frag_now->fr_line, opc->id);
++
++  /* Go through the relaxation stage for all instructions that can
++     possibly take a symbolic immediate.  The relax code will take
++     care of range checking and alignment.  */
++  if (opc->var_field != -1)
++    {
++      int substate, largest_substate;
++      symbolS *sym;
++      offsetT off;
++
++      will_relax = 1;
++      substate = largest_substate = opc_initial_substate(opc);
++
++      while (relax_more(largest_substate) != AVR32_RS_NONE)
++      largest_substate = relax_more(largest_substate);
++
++      pr_debug("will relax. initial substate: %d (size %d), largest substate: %d (size %d)\n",
++             substate, avr32_rs_size(substate),
++             largest_substate, avr32_rs_size(largest_substate));
++
++      /* make sure we have enough room for the largest possible opcode */
++      frag_grow(avr32_rs_size(largest_substate));
++      buf = frag_more(opc->size);
++
++      dwarf2_emit_insn(opc->size);
++
++      frag_now->tc_frag_data.reloc_info = AVR32_OPINFO_NONE;
++      frag_now->tc_frag_data.pcrel = current_insn.pcrel;
++      frag_now->tc_frag_data.force_extended = current_insn.force_extended;
++      frag_now->tc_frag_data.relaxer = &avr32_default_relaxer;
++
++      if (exp->X_op == O_hi)
++      {
++        frag_now->tc_frag_data.reloc_info = AVR32_OPINFO_HI;
++        exp->X_op = exp->X_md;
++      }
++      else if (exp->X_op == O_lo)
++      {
++        frag_now->tc_frag_data.reloc_info = AVR32_OPINFO_LO;
++        exp->X_op = exp->X_md;
++      }
++      else if (exp->X_op == O_got)
++      {
++        frag_now->tc_frag_data.reloc_info = AVR32_OPINFO_GOT;
++        exp->X_op = O_symbol;
++      }
++
++#if 0
++      if ((opc->reloc_type == BFD_RELOC_AVR32_SUB5)
++        && exp->X_op == O_subtract)
++      {
++        symbolS *tmp;
++        tmp = exp->X_add_symbol;
++        exp->X_add_symbol = exp->X_op_symbol;
++        exp->X_op_symbol = tmp;
++      }
++#endif
++
++      frag_now->tc_frag_data.exp = current_insn.immediate;
++
++      sym = exp->X_add_symbol;
++      off = exp->X_add_number;
++      if (exp->X_op != O_symbol)
++      {
++        sym = make_expr_symbol(exp);
++        off = 0;
++      }
++
++      frag_var(rs_machine_dependent,
++             avr32_rs_size(largest_substate) - opc->size,
++             opc->size,
++             substate, sym, off, buf);
++    }
++  else
++    {
++      assert(avr32_rs_size(opc_initial_substate(opc)) == 0);
++
++      /* Make sure we always have room for another whole word, as the ifield
++       inserters can only write words. */
++      frag_grow(4);
++      buf = frag_more(opc->size);
++      dwarf2_emit_insn(opc->size);
++    }
++
++  assert(!(opc->value & ~opc->mask));
++
++  pr_debug("inserting opcode: 0x%lx\n", opc->value);
++  bfd_putb32(opc->value, buf);
++
++  for (i = 0; i < opc->nr_fields; i++)
++    {
++      const struct avr32_ifield *f = opc->fields[i];
++      const struct avr32_ifield_data *fd = &current_insn.field_value[i];
++
++      pr_debug("inserting field: 0x%lx & 0x%lx\n",
++             fd->value >> fd->align_order, f->mask);
++
++      f->insert(f, buf, fd->value >> fd->align_order);
++    }
++
++  assert(will_relax || !current_insn.immediate.X_add_symbol);
++  return NULL;
++}
++
++static const char *
++finish_alias(const struct avr32_alias *alias)
++{
++  const struct avr32_opcode *opc;
++  struct {
++    unsigned long value;
++    unsigned long align;
++  } mapped_operand[AVR32_MAX_OPERANDS];
++  unsigned int i;
++
++  opc = alias->opc;
++
++  /* Remap the operands from the alias to the real opcode */
++  for (i = 0; i < opc->nr_fields; i++)
++    {
++      if (alias->operand_map[i].is_opindex)
++      {
++        struct avr32_ifield_data *fd;
++        fd = &current_insn.field_value[alias->operand_map[i].value];
++        mapped_operand[i].value = fd->value;
++        mapped_operand[i].align = fd->align_order;
++      }
++      else
++      {
++        mapped_operand[i].value = alias->operand_map[i].value;
++        mapped_operand[i].align = 0;
++      }
++    }
++
++  for (i = 0; i < opc->nr_fields; i++)
++    {
++      current_insn.field_value[i].value = mapped_operand[i].value;
++      if (opc->id == AVR32_OPC_COP)
++      current_insn.field_value[i].align_order = 0;
++      else
++      current_insn.field_value[i].align_order
++        = mapped_operand[i].align;
++    }
++
++  current_insn.next_slot = opc->nr_fields;
++
++  return finish_insn(opc);
++}
++
++static const char *
++finish_lda(const struct avr32_syntax *syntax ATTRIBUTE_UNUSED)
++{
++  expressionS *exp = &current_insn.immediate;
++  relax_substateT initial_subtype;
++  symbolS *sym;
++  offsetT off;
++  int initial_size, max_size;
++  char *buf;
++
++  initial_size = LDA_INITIAL_SIZE;
++
++  if (avr32_pic)
++    {
++      initial_subtype = LDA_SUBTYPE_SUB;
++      if (linkrelax)
++      max_size = 8;
++      else
++      max_size = 4;
++    }
++  else
++    {
++      initial_subtype = LDA_SUBTYPE_MOV1;
++      max_size = 4;
++    }
++
++  frag_grow(max_size);
++  buf = frag_more(initial_size);
++  dwarf2_emit_insn(initial_size);
++
++  if (exp->X_op == O_symbol)
++    {
++      sym = exp->X_add_symbol;
++      off = exp->X_add_number;
++    }
++  else
++    {
++      sym = make_expr_symbol(exp);
++      off = 0;
++    }
++
++  frag_now->tc_frag_data.reloc_info = current_insn.field_value[0].value;
++  frag_now->tc_frag_data.relaxer = &avr32_lda_relaxer;
++
++  if (!avr32_pic)
++    {
++      /* The relaxer will bump the refcount if necessary */
++      frag_now->tc_frag_data.pool
++      = add_to_cpool(exp, &frag_now->tc_frag_data.pool_entry, 0);
++    }
++
++  frag_var(rs_machine_dependent, max_size - initial_size,
++         initial_size, initial_subtype, sym, off, buf);
++
++  return NULL;
++}
++
++static const char *
++finish_call(const struct avr32_syntax *syntax ATTRIBUTE_UNUSED)
++{
++  expressionS *exp = &current_insn.immediate;
++  symbolS *sym;
++  offsetT off;
++  int initial_size, max_size;
++  char *buf;
++
++  initial_size = CALL_INITIAL_SIZE;
++
++  if (avr32_pic)
++    {
++      if (linkrelax)
++      max_size = 10;
++      else
++      max_size = 4;
++    }
++  else
++    max_size = 4;
++
++  frag_grow(max_size);
++  buf = frag_more(initial_size);
++  dwarf2_emit_insn(initial_size);
++
++  frag_now->tc_frag_data.relaxer = &avr32_call_relaxer;
++
++  if (exp->X_op == O_symbol)
++    {
++      sym = exp->X_add_symbol;
++      off = exp->X_add_number;
++    }
++  else
++    {
++      sym = make_expr_symbol(exp);
++      off = 0;
++    }
++
++  if (!avr32_pic)
++    {
++      /* The relaxer will bump the refcount if necessary */
++      frag_now->tc_frag_data.pool
++      = add_to_cpool(exp, &frag_now->tc_frag_data.pool_entry, 0);
++    }
++
++  frag_var(rs_machine_dependent, max_size - initial_size,
++         initial_size, CALL_SUBTYPE_RCALL1, sym, off, buf);
++
++  return NULL;
++}
++
++void
++md_begin (void)
++{
++  unsigned long flags = 0;
++  int i;
++
++  avr32_mnemonic_htab = hash_new();
++
++  if (!avr32_mnemonic_htab)
++    as_fatal(_("virtual memory exhausted"));
++
++  for (i = 0; i < AVR32_NR_MNEMONICS; i++)
++    {
++      hash_insert(avr32_mnemonic_htab, avr32_mnemonic_table[i].name,
++                (void *)&avr32_mnemonic_table[i]);
++    }
++
++  if (linkrelax)
++    flags |= EF_AVR32_LINKRELAX;
++  if (avr32_pic)
++    flags |= EF_AVR32_PIC;
++
++  bfd_set_private_flags(stdoutput, flags);
++
++#ifdef OPC_CONSISTENCY_CHECK
++  if (sizeof(avr32_operand_table)/sizeof(avr32_operand_table[0])
++      < AVR32_NR_OPERANDS)
++    as_fatal(_("operand table is incomplete"));
++
++  for (i = 0; i < AVR32_NR_OPERANDS; i++)
++    if (avr32_operand_table[i].id != i)
++      as_fatal(_("operand table inconsistency found at index %d\n"), i);
++  pr_debug("%d operands verified\n", AVR32_NR_OPERANDS);
++
++  for (i = 0; i < AVR32_NR_IFIELDS; i++)
++    if (avr32_ifield_table[i].id != i)
++      as_fatal(_("ifield table inconsistency found at index %d\n"), i);
++  pr_debug("%d instruction fields verified\n", AVR32_NR_IFIELDS);
++
++  for (i = 0; i < AVR32_NR_OPCODES; i++)
++    {
++      if (avr32_opc_table[i].id != i)
++      as_fatal(_("opcode table inconsistency found at index %d\n"), i);
++      if ((avr32_opc_table[i].var_field == -1
++         && avr32_relax_table[i].length != 0)
++        || (avr32_opc_table[i].var_field != -1
++            && avr32_relax_table[i].length == 0))
++      as_fatal(_("relax table inconsistency found at index %d\n"), i);
++    }
++  pr_debug("%d opcodes verified\n", AVR32_NR_OPCODES);
++
++  for (i = 0; i < AVR32_NR_SYNTAX; i++)
++    if (avr32_syntax_table[i].id != i)
++      as_fatal(_("syntax table inconsistency found at index %d\n"), i);
++  pr_debug("%d syntax variants verified\n", AVR32_NR_SYNTAX);
++
++  for (i = 0; i < AVR32_NR_ALIAS; i++)
++    if (avr32_alias_table[i].id != i)
++      as_fatal(_("alias table inconsistency found at index %d\n"), i);
++  pr_debug("%d aliases verified\n", AVR32_NR_ALIAS);
++
++  for (i = 0; i < AVR32_NR_MNEMONICS; i++)
++    if (avr32_mnemonic_table[i].id != i)
++      as_fatal(_("mnemonic table inconsistency found at index %d\n"), i);
++  pr_debug("%d mnemonics verified\n", AVR32_NR_MNEMONICS);
++#endif
++}
++
++void
++md_assemble (char *str)
++{
++  struct avr32_mnemonic *mnemonic;
++  char *p, c;
++
++  memset(&current_insn, 0, sizeof(current_insn));
++  current_insn.immediate.X_op = O_constant;
++
++  skip_whitespace(str);
++  for (p = str; *p; p++)
++    if (*p == ' ')
++      break;
++  c = *p;
++  *p = 0;
++
++  mnemonic = hash_find(avr32_mnemonic_htab, str);
++  *p = c;
++  if (c) p++;
++
++  if (mnemonic)
++    {
++      const struct avr32_syntax *syntax;
++
++      for (syntax = mnemonic->syntax; syntax; syntax = syntax->next)
++      {
++        const char *errmsg = NULL;
++
++        if (syntax_matches(syntax, p))
++          {
++            if (!(syntax->isa_flags & avr32_arch->isa_flags))
++              {
++                as_bad(_("Selected architecture `%s'  does not support `%s'"),
++                       avr32_arch->name, str);
++                return;
++              }
++
++            current_insn.syntax = syntax;
++            parse_operands(p);
++
++            switch (syntax->type)
++              {
++              case AVR32_PARSER_NORMAL:
++                errmsg = finish_insn(syntax->u.opc);
++                break;
++              case AVR32_PARSER_ALIAS:
++                errmsg = finish_alias(syntax->u.alias);
++                break;
++              case AVR32_PARSER_LDA:
++                errmsg = finish_lda(syntax);
++                break;
++              case AVR32_PARSER_CALL:
++                errmsg = finish_call(syntax);
++                break;
++              default:
++                BAD_CASE(syntax->type);
++                break;
++              }
++
++            if (errmsg)
++              as_bad("%s in `%s'", errmsg, str);
++
++            return;
++          }
++      }
++
++      as_bad(_("unrecognized form of instruction: `%s'"), str);
++    }
++  else
++    as_bad(_("unrecognized instruction `%s'"), str);
++}
++
++void avr32_cleanup(void)
++{
++  struct cpool *pool;
++
++  /* Emit any constant pools that haven't been explicitly flushed with
++     a .cpool directive. */
++  for (pool = cpool_list; pool; pool = pool->next)
++    {
++      subseg_set(pool->section, pool->sub_section);
++      s_cpool(0);
++    }
++}
++
++/* Handle any PIC-related operands in data allocation pseudo-ops */
++void
++avr32_cons_fix_new (fragS *frag, int off, int size, expressionS *exp)
++{
++  bfd_reloc_code_real_type r_type = BFD_RELOC_UNUSED;
++  int pcrel = 0;
++
++  pr_debug("%s:%u: cons_fix_new, add_sym: %s, op_sym: %s, op: %d, add_num: %d\n",
++         frag->fr_file, frag->fr_line,
++         exp->X_add_symbol?S_GET_NAME(exp->X_add_symbol):"(none)",
++         exp->X_op_symbol?S_GET_NAME(exp->X_op_symbol):"(none)",
++         exp->X_op, exp->X_add_number);
++
++  if (exp->X_op == O_subtract && exp->X_op_symbol)
++    {
++      if (exp->X_op_symbol == GOT_symbol)
++      {
++        if (size != 4)
++          goto bad_size;
++        r_type = BFD_RELOC_AVR32_GOTPC;
++        exp->X_op = O_symbol;
++        exp->X_op_symbol = NULL;
++      }
++    }
++  else if (exp->X_op == O_got)
++    {
++      switch (size)
++      {
++      case 1:
++        r_type = BFD_RELOC_AVR32_GOT8;
++        break;
++      case 2:
++        r_type = BFD_RELOC_AVR32_GOT16;
++        break;
++      case 4:
++        r_type = BFD_RELOC_AVR32_GOT32;
++        break;
++      default:
++        goto bad_size;
++      }
++
++      exp->X_op = O_symbol;
++    }
++
++  if (r_type == BFD_RELOC_UNUSED)
++    switch (size)
++      {
++      case 1:
++      r_type = BFD_RELOC_8;
++      break;
++      case 2:
++      r_type = BFD_RELOC_16;
++      break;
++      case 4:
++      r_type = BFD_RELOC_32;
++      break;
++      default:
++      goto bad_size;
++      }
++  else if (size != 4)
++    {
++    bad_size:
++      as_bad(_("unsupported BFD relocation size %u"), size);
++      r_type = BFD_RELOC_UNUSED;
++    }
++
++  fix_new_exp (frag, off, size, exp, pcrel, r_type);
++}
++
++static void
++avr32_frob_section(bfd *abfd ATTRIBUTE_UNUSED, segT sec,
++                 void *ignore ATTRIBUTE_UNUSED)
++{
++  segment_info_type *seginfo;
++  fixS *fix;
++
++  seginfo = seg_info(sec);
++  if (!seginfo)
++    return;
++
++  for (fix = seginfo->fix_root; fix; fix = fix->fx_next)
++    {
++      if (fix->fx_done)
++      continue;
++
++      if (fix->fx_r_type == BFD_RELOC_AVR32_SUB5
++        && fix->fx_addsy && fix->fx_subsy)
++      {
++        if (S_GET_SEGMENT(fix->fx_addsy) != S_GET_SEGMENT(fix->fx_subsy)
++            || linkrelax)
++          {
++            symbolS *tmp;
++#ifdef DEBUG
++            fprintf(stderr, "Swapping symbols in fixup:\n");
++            print_fixup(fix);
++#endif
++            tmp = fix->fx_addsy;
++            fix->fx_addsy = fix->fx_subsy;
++            fix->fx_subsy = tmp;
++            fix->fx_offset = -fix->fx_offset;
++          }
++      }
++    }
++}
++
++/* We need to look for SUB5 instructions with expressions that will be
++   made PC-relative and switch fx_addsy with fx_subsy.  This has to be
++   done before adjustment or the wrong symbol might be adjusted.
++
++   This applies to fixups that are a result of expressions like -(sym
++   - .) and that will make it all the way to md_apply_fix3().  LDA
++   does the right thing in convert_frag, so we must not convert
++   those. */
++void
++avr32_frob_file(void)
++{
++  /* if (1 || !linkrelax)
++     return; */
++
++  bfd_map_over_sections(stdoutput, avr32_frob_section, NULL);
++}
++
++static bfd_boolean
++convert_to_diff_reloc(fixS *fixP)
++{
++  switch (fixP->fx_r_type)
++    {
++    case BFD_RELOC_32:
++      fixP->fx_r_type = BFD_RELOC_AVR32_DIFF32;
++      break;
++    case BFD_RELOC_16:
++      fixP->fx_r_type = BFD_RELOC_AVR32_DIFF16;
++      break;
++    case BFD_RELOC_8:
++      fixP->fx_r_type = BFD_RELOC_AVR32_DIFF8;
++      break;
++    default:
++      return FALSE;
++    }
++
++  return TRUE;
++}
++
++/* Simplify a fixup.  If possible, the fixup is reduced to a single
++   constant which is written to the output file.  Otherwise, a
++   relocation is generated so that the linker can take care of the
++   rest.
++
++   ELF relocations have certain constraints: They can only take a
++   single symbol and a single addend.  This means that for difference
++   expressions, we _must_ get rid of the fx_subsy symbol somehow.
++
++   The difference between two labels in the same section can be
++   calculated directly unless 'linkrelax' is set, or a relocation is
++   forced.  If so, we must emit a R_AVR32_DIFFxx relocation.  If there
++   are addends involved at this point, we must be especially careful
++   as the relocation must point exactly to the symbol being
++   subtracted.
++
++   When subtracting a symbol defined in the same section as the fixup,
++   we might be able to convert it to a PC-relative expression, unless
++   linkrelax is set. If this is the case, there's no way we can make
++   sure that the difference between the fixup and fx_subsy stays
++   constant.  So for now, we're just going to disallow that.
++   */
++void
++avr32_process_fixup(fixS *fixP, segT this_segment)
++{
++  segT add_symbol_segment = absolute_section;
++  segT sub_symbol_segment = absolute_section;
++  symbolS *fx_addsy, *fx_subsy;
++  offsetT value = 0, fx_offset;
++  bfd_boolean apply = FALSE;
++
++  assert(this_segment != absolute_section);
++
++  if (fixP->fx_r_type >= BFD_RELOC_UNUSED)
++    {
++      as_bad_where(fixP->fx_file, fixP->fx_line,
++                 _("Bad relocation type %d\n"), fixP->fx_r_type);
++      return;
++    }
++
++  /* BFD_RELOC_AVR32_SUB5 fixups have been swapped by avr32_frob_section() */
++  fx_addsy = fixP->fx_addsy;
++  fx_subsy = fixP->fx_subsy;
++  fx_offset = fixP->fx_offset;
++
++  if (fx_addsy)
++    add_symbol_segment = S_GET_SEGMENT(fx_addsy);
++
++  if (fx_subsy)
++    {
++      resolve_symbol_value(fx_subsy);
++      sub_symbol_segment = S_GET_SEGMENT(fx_subsy);
++
++      if (sub_symbol_segment == this_segment
++        && (!linkrelax
++            || S_GET_VALUE(fx_subsy) == (fixP->fx_frag->fr_address
++                                         + fixP->fx_where)))
++      {
++        fixP->fx_pcrel = TRUE;
++        fx_offset += (fixP->fx_frag->fr_address + fixP->fx_where
++                      - S_GET_VALUE(fx_subsy));
++        fx_subsy = NULL;
++      }
++      else if (sub_symbol_segment == absolute_section)
++      {
++        /* The symbol is really a constant.  */
++        fx_offset -= S_GET_VALUE(fx_subsy);
++        fx_subsy = NULL;
++      }
++      else if (SEG_NORMAL(add_symbol_segment)
++             && sub_symbol_segment == add_symbol_segment
++             && (!linkrelax || convert_to_diff_reloc(fixP)))
++      {
++        /* Difference between two labels in the same section.  */
++        if (linkrelax)
++          {
++            /* convert_to_diff() has ensured that the reloc type is
++               either DIFF32, DIFF16 or DIFF8.  */
++            value = (S_GET_VALUE(fx_addsy) + fixP->fx_offset
++                     - S_GET_VALUE(fx_subsy));
++
++            /* Try to convert it to a section symbol if possible  */
++            if (!S_FORCE_RELOC(fx_addsy, 1)
++                && !(sub_symbol_segment->flags & SEC_THREAD_LOCAL))
++              {
++                fx_offset = S_GET_VALUE(fx_subsy);
++                fx_addsy = section_symbol(sub_symbol_segment);
++              }
++            else
++              {
++                fx_addsy = fx_subsy;
++                fx_offset = 0;
++              }
++
++            fx_subsy = NULL;
++            apply = TRUE;
++          }
++        else
++          {
++            fx_offset += S_GET_VALUE(fx_addsy);
++            fx_offset -= S_GET_VALUE(fx_subsy);
++            fx_addsy = NULL;
++            fx_subsy = NULL;
++          }
++      }
++      else
++      {
++        as_bad_where(fixP->fx_file, fixP->fx_line,
++                     _("can't resolve `%s' {%s section} - `%s' {%s section}"),
++                     fx_addsy ? S_GET_NAME (fx_addsy) : "0",
++                     segment_name (add_symbol_segment),
++                     S_GET_NAME (fx_subsy),
++                     segment_name (sub_symbol_segment));
++        return;
++      }
++    }
++
++  if (fx_addsy && !TC_FORCE_RELOCATION(fixP))
++    {
++      if (add_symbol_segment == this_segment
++        && fixP->fx_pcrel)
++      {
++        value += S_GET_VALUE(fx_addsy);
++        value -= md_pcrel_from_section(fixP, this_segment);
++        fx_addsy = NULL;
++        fixP->fx_pcrel = FALSE;
++      }
++      else if (add_symbol_segment == absolute_section)
++      {
++        fx_offset += S_GET_VALUE(fixP->fx_addsy);
++        fx_addsy = NULL;
++      }
++    }
++
++  if (!fx_addsy)
++    fixP->fx_done = TRUE;
++
++  if (fixP->fx_pcrel)
++    {
++      if (fx_addsy != NULL
++        && S_IS_DEFINED(fx_addsy)
++        && S_GET_SEGMENT(fx_addsy) != this_segment)
++      value += md_pcrel_from_section(fixP, this_segment);
++
++      switch (fixP->fx_r_type)
++      {
++      case BFD_RELOC_32:
++        fixP->fx_r_type = BFD_RELOC_32_PCREL;
++        break;
++      case BFD_RELOC_16:
++        fixP->fx_r_type = BFD_RELOC_16_PCREL;
++        break;
++      case BFD_RELOC_8:
++        fixP->fx_r_type = BFD_RELOC_8_PCREL;
++        break;
++      case BFD_RELOC_AVR32_SUB5:
++        fixP->fx_r_type = BFD_RELOC_AVR32_16N_PCREL;
++        break;
++      case BFD_RELOC_AVR32_16S:
++        fixP->fx_r_type = BFD_RELOC_AVR32_16B_PCREL;
++        break;
++      case BFD_RELOC_AVR32_14UW:
++        fixP->fx_r_type = BFD_RELOC_AVR32_14UW_PCREL;
++        break;
++      case BFD_RELOC_AVR32_10UW:
++        fixP->fx_r_type = BFD_RELOC_AVR32_10UW_PCREL;
++        break;
++      default:
++        /* Should have been taken care of already */
++        break;
++      }
++    }
++
++  if (fixP->fx_done || apply)
++    {
++      const struct avr32_ifield *ifield;
++      char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
++
++      if (fixP->fx_done)
++      value += fx_offset;
++
++      /* For hosts with longs bigger than 32-bits make sure that the top
++         bits of a 32-bit negative value read in by the parser are set,
++         so that the correct comparisons are made.  */
++      if (value & 0x80000000)
++        value |= (-1L << 31);
++
++      switch (fixP->fx_r_type)
++      {
++      case BFD_RELOC_32:
++      case BFD_RELOC_16:
++      case BFD_RELOC_8:
++      case BFD_RELOC_AVR32_DIFF32:
++      case BFD_RELOC_AVR32_DIFF16:
++      case BFD_RELOC_AVR32_DIFF8:
++        md_number_to_chars(buf, value, fixP->fx_size);
++        break;
++      case BFD_RELOC_HI16:
++        value >>= 16;
++      case BFD_RELOC_LO16:
++        value &= 0xffff;
++        md_number_to_chars(buf + 2, value, 2);
++        break;
++      case BFD_RELOC_AVR32_16N_PCREL:
++        value = -value;
++        /* fall through */
++      case BFD_RELOC_AVR32_22H_PCREL:
++      case BFD_RELOC_AVR32_18W_PCREL:
++      case BFD_RELOC_AVR32_16B_PCREL:
++      case BFD_RELOC_AVR32_11H_PCREL:
++      case BFD_RELOC_AVR32_9H_PCREL:
++      case BFD_RELOC_AVR32_9UW_PCREL:
++      case BFD_RELOC_AVR32_3U:
++      case BFD_RELOC_AVR32_4UH:
++      case BFD_RELOC_AVR32_6UW:
++      case BFD_RELOC_AVR32_6S:
++      case BFD_RELOC_AVR32_7UW:
++      case BFD_RELOC_AVR32_8S_EXT:
++      case BFD_RELOC_AVR32_8S:
++      case BFD_RELOC_AVR32_10UW:
++      case BFD_RELOC_AVR32_10SW:
++      case BFD_RELOC_AVR32_STHH_W:
++      case BFD_RELOC_AVR32_14UW:
++      case BFD_RELOC_AVR32_16S:
++      case BFD_RELOC_AVR32_16U:
++      case BFD_RELOC_AVR32_21S:
++      case BFD_RELOC_AVR32_SUB5:
++      case BFD_RELOC_AVR32_CPCALL:
++      case BFD_RELOC_AVR32_16_CP:
++      case BFD_RELOC_AVR32_9W_CP:
++      case BFD_RELOC_AVR32_15S:
++        ifield = fixP->tc_fix_data.ifield;
++        pr_debug("insert field: %ld <= %ld <= %ld (align %u)\n",
++                 fixP->tc_fix_data.min, value, fixP->tc_fix_data.max,
++                 fixP->tc_fix_data.align);
++        if (value < fixP->tc_fix_data.min || value > fixP->tc_fix_data.max)
++          as_bad_where(fixP->fx_file, fixP->fx_line,
++                       _("operand out of range (%ld not between %ld and %ld)"),
++                       value, fixP->tc_fix_data.min, fixP->tc_fix_data.max);
++        if (value & ((1 << fixP->tc_fix_data.align) - 1))
++          as_bad_where(fixP->fx_file, fixP->fx_line,
++                       _("misaligned operand (required alignment: %d)"),
++                       1 << fixP->tc_fix_data.align);
++        ifield->insert(ifield, buf, value >> fixP->tc_fix_data.align);
++        break;
++      case BFD_RELOC_AVR32_ALIGN:
++        /* Nothing to do */
++        fixP->fx_done = FALSE;
++        break;
++      default:
++        as_fatal("reloc type %s not handled\n",
++                 bfd_get_reloc_code_name(fixP->fx_r_type));
++      }
++    }
++
++  fixP->fx_addsy = fx_addsy;
++  fixP->fx_subsy = fx_subsy;
++  fixP->fx_offset = fx_offset;
++
++  if (!fixP->fx_done)
++    {
++      if (!fixP->fx_addsy)
++      fixP->fx_addsy = abs_section_sym;
++
++      symbol_mark_used_in_reloc(fixP->fx_addsy);
++      if (fixP->fx_subsy)
++      abort();
++    }
++}
++
++#if 0
++void
++md_apply_fix3 (fixS *fixP, valueT *valP, segT seg)
++{
++  const struct avr32_ifield *ifield;
++  offsetT     value = *valP;
++  char                *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
++  bfd_boolean apply;
++
++  pr_debug("%s:%u: apply_fix3: r_type=%d value=%lx offset=%lx\n",
++         fixP->fx_file, fixP->fx_line, fixP->fx_r_type, *valP,
++         fixP->fx_offset);
++
++  if (fixP->fx_r_type >= BFD_RELOC_UNUSED)
++    {
++      as_bad_where(fixP->fx_file, fixP->fx_line,
++                 _("Bad relocation type %d\n"), fixP->fx_r_type);
++      return;
++    }
++
++  if (!fixP->fx_addsy && !fixP->fx_subsy)
++    fixP->fx_done = 1;
++
++  if (fixP->fx_pcrel)
++    {
++      if (fixP->fx_addsy != NULL
++        && S_IS_DEFINED(fixP->fx_addsy)
++        && S_GET_SEGMENT(fixP->fx_addsy) != seg)
++      value += md_pcrel_from_section(fixP, seg);
++
++      switch (fixP->fx_r_type)
++      {
++      case BFD_RELOC_32:
++        fixP->fx_r_type = BFD_RELOC_32_PCREL;
++        break;
++      case BFD_RELOC_16:
++      case BFD_RELOC_8:
++        as_bad_where (fixP->fx_file, fixP->fx_line,
++                      _("8- and 16-bit PC-relative relocations not supported"));
++        break;
++      case BFD_RELOC_AVR32_SUB5:
++        fixP->fx_r_type = BFD_RELOC_AVR32_PCREL_SUB5;
++        break;
++      case BFD_RELOC_AVR32_16S:
++        fixP->fx_r_type = BFD_RELOC_AVR32_16_PCREL;
++        break;
++      default:
++        /* Should have been taken care of already */
++        break;
++      }
++    }
++
++  if (fixP->fx_r_type == BFD_RELOC_32
++      && fixP->fx_subsy)
++    {
++      fixP->fx_r_type = BFD_RELOC_AVR32_DIFF32;
++
++      /* Offsets are only allowed if it's a result of adjusting a
++       local symbol into a section-relative offset.
++       tc_fix_adjustable() should prevent any adjustment if there
++       was an offset involved before.  */
++      if (fixP->fx_offset && !symbol_section_p(fixP->fx_addsy))
++      as_bad_where(fixP->fx_file, fixP->fx_line,
++                   _("cannot represent symbol difference with an offset"));
++
++      value = (S_GET_VALUE(fixP->fx_addsy) + fixP->fx_offset
++             - S_GET_VALUE(fixP->fx_subsy));
++
++      /* The difference before any relaxing takes place is written
++       out, and the DIFF32 reloc identifies the address of the first
++       symbol (i.e. the on that's subtracted.)  */
++      *valP = value;
++      fixP->fx_offset -= value;
++      fixP->fx_subsy = NULL;
++
++      md_number_to_chars(buf, value, fixP->fx_size);
++    }
++
++  if (fixP->fx_done)
++    {
++      switch (fixP->fx_r_type)
++      {
++      case BFD_RELOC_8:
++      case BFD_RELOC_16:
++      case BFD_RELOC_32:
++        md_number_to_chars(buf, value, fixP->fx_size);
++        break;
++      case BFD_RELOC_HI16:
++        value >>= 16;
++      case BFD_RELOC_LO16:
++        value &= 0xffff;
++        *valP = value;
++        md_number_to_chars(buf + 2, value, 2);
++        break;
++      case BFD_RELOC_AVR32_PCREL_SUB5:
++        value = -value;
++        /* fall through */
++      case BFD_RELOC_AVR32_9_PCREL:
++      case BFD_RELOC_AVR32_11_PCREL:
++      case BFD_RELOC_AVR32_16_PCREL:
++      case BFD_RELOC_AVR32_18_PCREL:
++      case BFD_RELOC_AVR32_22_PCREL:
++      case BFD_RELOC_AVR32_3U:
++      case BFD_RELOC_AVR32_4UH:
++      case BFD_RELOC_AVR32_6UW:
++      case BFD_RELOC_AVR32_6S:
++      case BFD_RELOC_AVR32_7UW:
++      case BFD_RELOC_AVR32_8S:
++      case BFD_RELOC_AVR32_10UW:
++      case BFD_RELOC_AVR32_10SW:
++      case BFD_RELOC_AVR32_14UW:
++      case BFD_RELOC_AVR32_16S:
++      case BFD_RELOC_AVR32_16U:
++      case BFD_RELOC_AVR32_21S:
++      case BFD_RELOC_AVR32_BRC1:
++      case BFD_RELOC_AVR32_SUB5:
++      case BFD_RELOC_AVR32_CPCALL:
++      case BFD_RELOC_AVR32_16_CP:
++      case BFD_RELOC_AVR32_9_CP:
++      case BFD_RELOC_AVR32_15S:
++        ifield = fixP->tc_fix_data.ifield;
++        pr_debug("insert field: %ld <= %ld <= %ld (align %u)\n",
++                 fixP->tc_fix_data.min, value, fixP->tc_fix_data.max,
++                 fixP->tc_fix_data.align);
++        if (value < fixP->tc_fix_data.min || value > fixP->tc_fix_data.max)
++          as_bad_where(fixP->fx_file, fixP->fx_line,
++                       _("operand out of range (%ld not between %ld and %ld)"),
++                       value, fixP->tc_fix_data.min, fixP->tc_fix_data.max);
++        if (value & ((1 << fixP->tc_fix_data.align) - 1))
++          as_bad_where(fixP->fx_file, fixP->fx_line,
++                       _("misaligned operand (required alignment: %d)"),
++                       1 << fixP->tc_fix_data.align);
++        ifield->insert(ifield, buf, value >> fixP->tc_fix_data.align);
++        break;
++      case BFD_RELOC_AVR32_ALIGN:
++        /* Nothing to do */
++        fixP->fx_done = FALSE;
++        break;
++      default:
++        as_fatal("reloc type %s not handled\n",
++                 bfd_get_reloc_code_name(fixP->fx_r_type));
++      }
++    }
++}
++#endif
++
++arelent *
++tc_gen_reloc (asection *section ATTRIBUTE_UNUSED,
++            fixS *fixp)
++{
++  arelent *reloc;
++  bfd_reloc_code_real_type code;
++
++  reloc = xmalloc (sizeof (arelent));
++
++  reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
++  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
++  reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
++  reloc->addend = fixp->fx_offset;
++  code = fixp->fx_r_type;
++
++  reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
++
++  if (reloc->howto == NULL)
++    {
++      as_bad_where (fixp->fx_file, fixp->fx_line,
++                  _("cannot represent relocation %s in this object file format"),
++                  bfd_get_reloc_code_name (code));
++      return NULL;
++    }
++
++  return reloc;
++}
++
++bfd_boolean
++avr32_force_reloc(fixS *fixP)
++{
++  if (linkrelax && fixP->fx_addsy
++      && !(S_GET_SEGMENT(fixP->fx_addsy)->flags & SEC_DEBUGGING)
++      && S_GET_SEGMENT(fixP->fx_addsy) != absolute_section)
++    {
++      pr_debug(stderr, "force reloc: addsy=%p, r_type=%d, sec=%s\n",
++             fixP->fx_addsy, fixP->fx_r_type, S_GET_SEGMENT(fixP->fx_addsy)->name);
++      return 1;
++    }
++
++  return generic_force_reloc(fixP);
++}
++
++bfd_boolean
++avr32_fix_adjustable(fixS *fixP)
++{
++  switch (fixP->fx_r_type)
++    {
++      /* GOT relocations can't have addends since BFD treats all
++       references to a given symbol the same. This means that we
++       must avoid section-relative references to local symbols when
++       dealing with these kinds of relocs */
++    case BFD_RELOC_AVR32_GOT32:
++    case BFD_RELOC_AVR32_GOT16:
++    case BFD_RELOC_AVR32_GOT8:
++    case BFD_RELOC_AVR32_GOT21S:
++    case BFD_RELOC_AVR32_GOT18SW:
++    case BFD_RELOC_AVR32_GOT16S:
++    case BFD_RELOC_AVR32_LDA_GOT:
++    case BFD_RELOC_AVR32_GOTCALL:
++      pr_debug("fix not adjustable\n");
++      return 0;
++
++    default:
++      break;
++    }
++
++  return 1;
++}
++
++/* When we want the linker to be able to relax the code, we need to
++   output a reloc for every .align directive requesting an alignment
++   to a four byte boundary or larger.  If we don't do this, the linker
++   can't guarantee that the alignment is actually maintained in the
++   linker output.
++
++   TODO: Might as well insert proper NOPs while we're at it... */
++void
++avr32_handle_align(fragS *frag)
++{
++  if (linkrelax
++      && frag->fr_type == rs_align_code
++      && frag->fr_address + frag->fr_fix > 0
++      && frag->fr_offset > 0)
++    {
++      /* The alignment order (fr_offset) is stored in the addend. */
++      fix_new(frag, frag->fr_fix, 2, &abs_symbol, frag->fr_offset,
++            FALSE, BFD_RELOC_AVR32_ALIGN);
++    }
++}
++
++/* Relax_align. Advance location counter to next address that has 'alignment'
++   lowest order bits all 0s, return size of adjustment made.  */
++relax_addressT
++avr32_relax_align(segT segment ATTRIBUTE_UNUSED,
++                fragS *fragP,
++                relax_addressT address)
++{
++  relax_addressT mask;
++  relax_addressT new_address;
++  int alignment;
++
++  alignment = fragP->fr_offset;
++  mask = ~((~0) << alignment);
++  new_address = (address + mask) & (~mask);
++
++  return new_address - address;
++}
++
++/* Turn a string in input_line_pointer into a floating point constant
++   of type type, and store the appropriate bytes in *litP.  The number
++   of LITTLENUMS emitted is stored in *sizeP .  An error message is
++   returned, or NULL on OK. */
++
++/* Equal to MAX_PRECISION in atof-ieee.c */
++#define MAX_LITTLENUMS 6
++
++char *
++md_atof (type, litP, sizeP)
++char   type;
++char * litP;
++int *  sizeP;
++{
++  int              i;
++  int              prec;
++  LITTLENUM_TYPE   words [MAX_LITTLENUMS];
++  char *           t;
++
++  switch (type)
++  {
++    case 'f':
++    case 'F':
++    case 's':
++    case 'S':
++      prec = 2;
++      break;
++
++    case 'd':
++    case 'D':
++    case 'r':
++    case 'R':
++      prec = 4;
++      break;
++
++      /* FIXME: Some targets allow other format chars for bigger sizes here.  */
++
++    default:
++      * sizeP = 0;
++      return _("Bad call to md_atof()");
++  }
++
++  t = atof_ieee (input_line_pointer, type, words);
++  if (t)
++    input_line_pointer = t;
++  * sizeP = prec * sizeof (LITTLENUM_TYPE);
++
++  for (i = 0; i < prec; i++)
++  {
++    md_number_to_chars (litP, (valueT) words[i],
++                        sizeof (LITTLENUM_TYPE));
++    litP += sizeof (LITTLENUM_TYPE);
++  }
++
++  return 0;
++}
++
++static char *avr32_end_of_match(char *cont, char *what)
++{
++  int len = strlen (what);
++
++  if (! is_part_of_name (cont[len])
++      && strncasecmp (cont, what, len) == 0)
++    return cont + len;
++
++  return NULL;
++}
++
++int
++avr32_parse_name (char const *name, expressionS *exp, char *nextchar)
++{
++  char *next = input_line_pointer;
++  char *next_end;
++
++  pr_debug("parse_name: %s, nextchar=%c (%02x)\n", name, *nextchar, *nextchar);
++
++  if (*nextchar == '(')
++    {
++      if (strcasecmp(name, "hi") == 0)
++      {
++        *next = *nextchar;
++
++        expression(exp);
++
++        if (exp->X_op == O_constant)
++          {
++            pr_debug("  -> constant hi(0x%08lx) -> 0x%04lx\n",
++                     exp->X_add_number, exp->X_add_number >> 16);
++            exp->X_add_number = (exp->X_add_number >> 16) & 0xffff;
++          }
++        else
++          {
++            exp->X_md = exp->X_op;
++            exp->X_op = O_hi;
++          }
++
++        return 1;
++      }
++      else if (strcasecmp(name, "lo") == 0)
++      {
++        *next = *nextchar;
++
++        expression(exp);
++
++        if (exp->X_op == O_constant)
++          exp->X_add_number &= 0xffff;
++        else
++          {
++            exp->X_md = exp->X_op;
++            exp->X_op = O_lo;
++          }
++
++        return 1;
++      }
++    }
++  else if (*nextchar == '@')
++    {
++      exp->X_md = exp->X_op;
++
++      if ((next_end = avr32_end_of_match (next + 1, "got")))
++      exp->X_op = O_got;
++      else if ((next_end = avr32_end_of_match (next + 1, "tlsgd")))
++      exp->X_op = O_tlsgd;
++      /* Add more as needed */
++      else
++      {
++        char c;
++        input_line_pointer++;
++        c = get_symbol_end();
++        as_bad (_("unknown relocation override `%s'"), next + 1);
++        *input_line_pointer = c;
++        input_line_pointer = next;
++        return 0;
++      }
++
++      exp->X_op_symbol = NULL;
++      exp->X_add_symbol = symbol_find_or_make (name);
++      exp->X_add_number = 0;
++
++      *input_line_pointer = *nextchar;
++      input_line_pointer = next_end;
++      *nextchar = *input_line_pointer;
++      *input_line_pointer = '\0';
++      return 1;
++    }
++  else if (strcmp (name, "_GLOBAL_OFFSET_TABLE_") == 0)
++    {
++      if (!GOT_symbol)
++      GOT_symbol = symbol_find_or_make(name);
++
++      exp->X_add_symbol = GOT_symbol;
++      exp->X_op = O_symbol;
++      exp->X_add_number = 0;
++      return 1;
++    }
++
++  return 0;
++}
++
++static void
++s_rseg (int value ATTRIBUTE_UNUSED)
++{
++  /* Syntax: RSEG segment_name [:type] [NOROOT|ROOT] [(align)]
++   * Defaults:
++   *  - type: undocumented ("typically CODE or DATA")
++   *  - ROOT
++   *  - align: 1 for code, 0 for others
++   *
++   * TODO: NOROOT is ignored. If gas supports discardable segments, it should
++   * be implemented.
++   */
++  char *name, *end;
++  int length, type, attr;
++  int align = 0;
++
++  SKIP_WHITESPACE();
++
++  end = input_line_pointer;
++  while (0 == strchr ("\n\t;:( ", *end))
++    end++;
++  if (end == input_line_pointer)
++    {
++      as_warn (_("missing name"));
++      ignore_rest_of_line();
++      return;
++    }
++
++  name = xmalloc (end - input_line_pointer + 1);
++  memcpy (name, input_line_pointer, end - input_line_pointer);
++  name[end - input_line_pointer] = '\0';
++  input_line_pointer = end;
++
++  SKIP_WHITESPACE();
++
++  type = SHT_NULL;
++  attr = 0;
++
++  if (*input_line_pointer == ':')
++    {
++      /* Skip the colon */
++      ++input_line_pointer;
++      SKIP_WHITESPACE();
++
++      /* Possible options at this point:
++       *   - flag (ROOT or NOROOT)
++       *   - a segment type
++       */
++      end = input_line_pointer;
++      while (0 == strchr ("\n\t;:( ", *end))
++      end++;
++      length = end - input_line_pointer;
++      if (((length == 4) && (0 == strncasecmp( input_line_pointer, "ROOT", 4))) ||
++        ((length == 6) && (0 == strncasecmp( input_line_pointer, "NOROOT", 6))))
++      {
++        /* Ignore ROOT/NOROOT */
++        input_line_pointer = end;
++      }
++      else
++      {
++        /* Must be a segment type */
++        switch (*input_line_pointer)
++          {
++          case 'C':
++          case 'c':
++            if ((length == 4) &&
++                (0 == strncasecmp (input_line_pointer, "CODE", 4)))
++              {
++                attr |= SHF_ALLOC | SHF_EXECINSTR;
++                type = SHT_PROGBITS;
++                align = 1;
++                break;
++              }
++            if ((length == 5) &&
++                (0 == strncasecmp (input_line_pointer, "CONST", 5)))
++              {
++                attr |= SHF_ALLOC;
++                type = SHT_PROGBITS;
++                break;
++              }
++            goto de_fault;
++
++          case 'D':
++          case 'd':
++            if ((length == 4) &&
++                (0 == strncasecmp (input_line_pointer, "DATA", 4)))
++              {
++                attr |= SHF_ALLOC | SHF_WRITE;
++                type = SHT_PROGBITS;
++                break;
++              }
++            goto de_fault;
++
++            /* TODO: Add FAR*, HUGE*, IDATA and NEAR* if necessary */
++
++          case 'U':
++          case 'u':
++            if ((length == 7) &&
++                (0 == strncasecmp (input_line_pointer, "UNTYPED", 7)))
++              break;
++            goto de_fault;
++
++            /* TODO: Add XDATA and ZPAGE if necessary */
++
++          de_fault:
++          default:
++            as_warn (_("unrecognized segment type"));
++          }
++
++        input_line_pointer = end;
++        SKIP_WHITESPACE();
++
++        if (*input_line_pointer == ':')
++          {
++            /*  ROOT/NOROOT */
++            ++input_line_pointer;
++            SKIP_WHITESPACE();
++
++            end = input_line_pointer;
++            while (0 == strchr ("\n\t;:( ", *end))
++              end++;
++            length = end - input_line_pointer;
++            if (! ((length == 4) &&
++                   (0 == strncasecmp( input_line_pointer, "ROOT", 4))) &&
++                ! ((length == 6) &&
++                   (0 == strncasecmp( input_line_pointer, "NOROOT", 6))))
++              {
++                as_warn (_("unrecognized segment flag"));
++              }
++
++            input_line_pointer = end;
++            SKIP_WHITESPACE();
++          }
++      }
++    }
++
++  if (*input_line_pointer == '(')
++    {
++      align = get_absolute_expression ();
++    }
++
++  demand_empty_rest_of_line();
++
++  obj_elf_change_section (name, type, attr, 0, NULL, 0, 0);
++#ifdef AVR32_DEBUG
++  fprintf( stderr, "RSEG: Changed section to %s, type: 0x%x, attr: 0x%x\n",
++      name, type, attr );
++  fprintf( stderr, "RSEG: Aligning to 2**%d\n", align );
++#endif
++
++  if (align > 15)
++    {
++      align = 15;
++      as_warn (_("alignment too large: %u assumed"), align);
++    }
++
++  /* Hope not, that is */
++  assert (now_seg != absolute_section);
++
++  /* Only make a frag if we HAVE to... */
++  if (align != 0 && !need_pass_2)
++    {
++      if (subseg_text_p (now_seg))
++      frag_align_code (align, 0);
++      else
++      frag_align (align, 0, 0);
++    }
++
++  record_alignment (now_seg, align - OCTETS_PER_BYTE_POWER);
++}
++
++/* vim: syntax=c sw=2
++ */
+--- /dev/null
++++ b/gas/config/tc-avr32.h
+@@ -0,0 +1,325 @@
++/* Assembler definitions for AVR32.
++   Copyright 2003,2004,2005,2006,2007,2008,2009 Atmel Corporation.
++
++   Written by Haavard Skinnemoen, Atmel Norway, <hskinnemoen@atmel.com>
++
++   This file is part of GAS, the GNU Assembler.
++
++   GAS 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, or (at your option)
++   any later version.
++
++   GAS 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 GAS; see the file COPYING.  If not, write to the Free
++   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
++   02111-1307, USA.  */
++
++#if 0
++#define DEBUG
++#define DEBUG1
++#define DEBUG2
++#define DEBUG3
++#define DEBUG4
++#define DEBUG5
++#endif
++
++/* Are we trying to be compatible with the IAR assembler? (--iar) */
++extern int avr32_iarcompat;
++
++/* By convention, you should define this macro in the `.h' file.  For
++   example, `tc-m68k.h' defines `TC_M68K'.  You might have to use this
++   if it is necessary to add CPU specific code to the object format
++   file.  */
++#define TC_AVR32
++
++/* This macro is the BFD target name to use when creating the output
++   file.  This will normally depend upon the `OBJ_FMT' macro.  */
++#define TARGET_FORMAT "elf32-avr32"
++
++/* This macro is the BFD architecture to pass to `bfd_set_arch_mach'.  */
++#define TARGET_ARCH bfd_arch_avr32
++
++/* This macro is the BFD machine number to pass to
++   `bfd_set_arch_mach'.  If it is not defined, GAS will use 0.  */
++#define TARGET_MACH 0
++
++/* UNDOCUMENTED: Allow //-style comments */
++#define DOUBLESLASH_LINE_COMMENTS
++
++/* You should define this macro to be non-zero if the target is big
++   endian, and zero if the target is little endian.  */
++#define TARGET_BYTES_BIG_ENDIAN 1
++
++/* FIXME: It seems that GAS only expects a one-byte opcode...
++   #define NOP_OPCODE 0xd703 */
++
++/* If you define this macro, GAS will warn about the use of
++   nonstandard escape sequences in a string.  */
++#undef ONLY_STANDARD_ESCAPES
++
++#define DWARF2_FORMAT(SEC) dwarf2_format_32bit
++
++/* Instructions are either 2 or 4 bytes long */
++/* #define DWARF2_LINE_MIN_INSN_LENGTH 2 */
++
++/* GAS will call this function for any expression that can not be
++   recognized.  When the function is called, `input_line_pointer'
++   will point to the start of the expression.  */
++#define md_operand(x)
++
++#define md_parse_name(name, expr, mode, c) avr32_parse_name(name, expr, c)
++extern int avr32_parse_name(const char *, struct expressionS *, char *);
++
++/* You may define this macro to generate a fixup for a data
++   allocation pseudo-op.  */
++#define TC_CONS_FIX_NEW(FRAG, OFF, LEN, EXP)  \
++  avr32_cons_fix_new(FRAG, OFF, LEN, EXP)
++void avr32_cons_fix_new (fragS *, int, int, expressionS *);
++
++/* `extsym - .' expressions can be emitted using PC-relative relocs */
++#define DIFF_EXPR_OK
++
++/* This is used to construct expressions out of @gotoff, etc. The
++   relocation type is stored in X_md */
++#define O_got         O_md1
++#define O_hi          O_md2
++#define O_lo          O_md3
++#define O_tlsgd               O_md4
++
++/* You may define this macro to parse an expression used in a data
++   allocation pseudo-op such as `.word'.  You can use this to
++   recognize relocation directives that may appear in such directives.  */
++/* #define TC_PARSE_CONS_EXPRESSION(EXPR,N) avr_parse_cons_expression (EXPR,N)
++   void avr_parse_cons_expression (expressionS *exp, int nbytes); */
++
++/* This should just call either `number_to_chars_bigendian' or
++   `number_to_chars_littleendian', whichever is appropriate.  On
++   targets like the MIPS which support options to change the
++   endianness, which function to call is a runtime decision.  On
++   other targets, `md_number_to_chars' can be a simple macro.  */
++#define md_number_to_chars number_to_chars_bigendian
++
++/* `md_short_jump_size'
++   `md_long_jump_size'
++   `md_create_short_jump'
++   `md_create_long_jump'
++   If `WORKING_DOT_WORD' is defined, GAS will not do broken word
++   processing (*note Broken words::.).  Otherwise, you should set
++   `md_short_jump_size' to the size of a short jump (a jump that is
++   just long enough to jump around a long jmp) and
++   `md_long_jump_size' to the size of a long jump (a jump that can go
++   anywhere in the function), You should define
++   `md_create_short_jump' to create a short jump around a long jump,
++   and define `md_create_long_jump' to create a long jump.  */
++#define WORKING_DOT_WORD
++
++/* If you define this macro, it means that `tc_gen_reloc' may return
++   multiple relocation entries for a single fixup.  In this case, the
++   return value of `tc_gen_reloc' is a pointer to a null terminated
++   array.  */
++#undef RELOC_EXPANSION_POSSIBLE
++
++/* If you define this macro, GAS will not require pseudo-ops to start with a .
++   character. */
++#define NO_PSEUDO_DOT (avr32_iarcompat)
++
++/* The IAR assembler uses $ as the location counter. Unfortunately, we
++   can't make this dependent on avr32_iarcompat... */
++#define DOLLAR_DOT
++
++/* Values passed to md_apply_fix3 don't include the symbol value.  */
++#define MD_APPLY_SYM_VALUE(FIX) 0
++
++/* The number of bytes to put into a word in a listing.  This affects
++   the way the bytes are clumped together in the listing.  For
++   example, a value of 2 might print `1234 5678' where a value of 1
++   would print `12 34 56 78'.  The default value is 4.  */
++#define LISTING_WORD_SIZE 4
++
++/* extern const struct relax_type md_relax_table[];
++#define TC_GENERIC_RELAX_TABLE md_relax_table */
++
++/*
++  An `.lcomm' directive with no explicit alignment parameter will use
++  this macro to set P2VAR to the alignment that a request for SIZE
++  bytes will have.  The alignment is expressed as a power of two.  If
++  no alignment should take place, the macro definition should do
++  nothing.  Some targets define a `.bss' directive that is also
++  affected by this macro.  The default definition will set P2VAR to
++  the truncated power of two of sizes up to eight bytes.
++
++  We want doublewords to be word-aligned, so we're going to modify the
++  default definition a tiny bit.
++*/
++#define TC_IMPLICIT_LCOMM_ALIGNMENT(SIZE, P2VAR)      \
++  do                                                  \
++    {                                                 \
++      if ((SIZE) >= 4)                                        \
++      (P2VAR) = 2;                                    \
++      else if ((SIZE) >= 2)                           \
++      (P2VAR) = 1;                                    \
++      else                                            \
++      (P2VAR) = 0;                                    \
++    }                                                 \
++  while (0)
++
++/* When relaxing, we need to generate relocations for alignment
++   directives.  */
++#define HANDLE_ALIGN(frag) avr32_handle_align(frag)
++extern void avr32_handle_align(fragS *);
++
++/* See internals doc for explanation. Oh wait...
++   Now, can you guess where "alignment" comes from? ;-) */
++#define MAX_MEM_FOR_RS_ALIGN_CODE ((1 << alignment) - 1)
++
++/* We need to stop gas from reducing certain expressions (e.g. GOT
++   references) */
++#define tc_fix_adjustable(fix) avr32_fix_adjustable(fix)
++extern bfd_boolean avr32_fix_adjustable(struct fix *);
++
++/* The linker needs to be passed a little more information when relaxing. */
++#define TC_FORCE_RELOCATION(fix) avr32_force_reloc(fix)
++extern bfd_boolean avr32_force_reloc(struct fix *);
++
++/* I'm tired of working around all the madness in fixup_segment().
++   This hook will do basically the same things as the generic code,
++   and then it will "goto" right past it.  */
++#define TC_VALIDATE_FIX(FIX, SEG, SKIP)               \
++  do                                          \
++    {                                         \
++      avr32_process_fixup(FIX, SEG);          \
++      if (!(FIX)->fx_done)                    \
++      ++seg_reloc_count;                      \
++      goto SKIP;                              \
++    }                                         \
++  while (0)
++extern void avr32_process_fixup(struct fix *fixP, segT this_segment);
++
++/* Positive values of TC_FX_SIZE_SLACK allow a target to define
++   fixups that far past the end of a frag.  Having such fixups
++   is of course most most likely a bug in setting fx_size correctly.
++   A negative value disables the fixup check entirely, which is
++   appropriate for something like the Renesas / SuperH SH_COUNT
++   reloc.  */
++/* This target is buggy, and sets fix size too large.  */
++#define TC_FX_SIZE_SLACK(FIX) -1
++
++/* We don't want the gas core to make any assumptions about our way of
++   doing linkrelaxing.  */
++#define TC_LINKRELAX_FIXUP(SEG)                       0
++
++/* ... but we do want it to insert lots of padding. */
++#define LINKER_RELAXING_SHRINKS_ONLY
++
++/* Better do it ourselves, really... */
++#define TC_RELAX_ALIGN(SEG, FRAG, ADDR)       avr32_relax_align(SEG, FRAG, ADDR)
++extern relax_addressT
++avr32_relax_align(segT segment, fragS *fragP, relax_addressT address);
++
++/* Use line number format that is amenable to linker relaxation.  */
++#define DWARF2_USE_FIXED_ADVANCE_PC (linkrelax != 0)
++
++/* This is called by write_object_file() just before symbols are
++   attempted converted into section symbols.  */
++#define tc_frob_file_before_adjust()  avr32_frob_file()
++extern void avr32_frob_file(void);
++
++/* If you define this macro, GAS will call it at the end of each input
++   file.  */
++#define md_cleanup() avr32_cleanup()
++extern void avr32_cleanup(void);
++
++/* There's an AVR32-specific hack in operand() which creates O_md
++   expressions when encountering HWRD or LWRD. We need to generate
++   proper relocs for them */
++/* #define md_cgen_record_fixup_exp avr32_cgen_record_fixup_exp */
++
++/* I needed to add an extra hook in gas_cgen_finish_insn() for
++   conversion of O_md* operands because md_cgen_record_fixup_exp()
++   isn't called for relaxable insns */
++/* #define md_cgen_convert_expr(exp, opinfo) avr32_cgen_convert_expr(exp, opinfo)
++   int avr32_cgen_convert_expr(expressionS *, int); */
++
++/* #define tc_gen_reloc gas_cgen_tc_gen_reloc */
++
++/* If you define this macro, it should return the position from which
++   the PC relative adjustment for a PC relative fixup should be
++   made. On many processors, the base of a PC relative instruction is
++   the next instruction, so this macro would return the length of an
++   instruction, plus the address of the PC relative fixup. The latter
++   can be calculated as fixp->fx_where + fixp->fx_frag->fr_address. */
++extern long md_pcrel_from_section (struct fix *, segT);
++#define MD_PCREL_FROM_SECTION(FIX, SEC) md_pcrel_from_section (FIX, SEC)
++
++#define LOCAL_LABEL(name) (name[0] == '.' && (name[1] == 'L'))
++#define LOCAL_LABELS_FB               1
++
++struct avr32_relaxer
++{
++  int (*estimate_size)(fragS *, segT);
++  long (*relax_frag)(segT, fragS *, long);
++  void (*convert_frag)(bfd *, segT, fragS *);
++};
++
++/* AVR32 has quite complex instruction coding, which means we need
++ * lots of information in order to do the right thing during relaxing
++ * (basically, we need to be able to reconstruct a whole new opcode if
++ * necessary) */
++#define TC_FRAG_TYPE struct avr32_frag_data
++
++struct cpool;
++
++struct avr32_frag_data
++{
++  /* TODO: Maybe add an expression object here so that we can use
++     fix_new_exp() in md_convert_frag?  We may have to decide
++     pcrel-ness in md_estimate_size_before_relax() as well...or we
++     might do it when parsing.  Doing it while parsing may fail
++     because the sub_symbol is undefined then... */
++  int pcrel;
++  int force_extended;
++  int reloc_info;
++  struct avr32_relaxer *relaxer;
++  expressionS exp;
++
++  /* Points to associated constant pool, for use by LDA and CALL in
++     non-pic mode, and when relaxing the .cpool directive */
++  struct cpool *pool;
++  unsigned int pool_entry;
++};
++
++/* We will have to initialize the fields explicitly when needed */
++#define TC_FRAG_INIT(fragP)
++
++#define md_estimate_size_before_relax(fragP, segT)                    \
++  ((fragP)->tc_frag_data.relaxer->estimate_size(fragP, segT))
++#define md_relax_frag(segment, fragP, stretch)                                \
++  ((fragP)->tc_frag_data.relaxer->relax_frag(segment, fragP, stretch))
++#define md_convert_frag(abfd, segment, fragP)                         \
++  ((fragP)->tc_frag_data.relaxer->convert_frag(abfd, segment, fragP))
++
++#define TC_FIX_TYPE struct avr32_fix_data
++
++struct avr32_fix_data
++{
++  const struct avr32_ifield *ifield;
++  unsigned int align;
++  long min;
++  long max;
++};
++
++#define TC_INIT_FIX_DATA(fixP)                        \
++  do                                          \
++    {                                         \
++      (fixP)->tc_fix_data.ifield = NULL;      \
++      (fixP)->tc_fix_data.align = 0;          \
++      (fixP)->tc_fix_data.min = 0;            \
++      (fixP)->tc_fix_data.max = 0;            \
++    }                                         \
++  while (0)
+--- a/gas/configure.tgt
++++ b/gas/configure.tgt
+@@ -33,6 +33,7 @@ case ${cpu} in
+   am33_2.0)           cpu_type=mn10300 endian=little ;;
+   arm*be|arm*b)               cpu_type=arm endian=big ;;
+   arm*)                       cpu_type=arm endian=little ;;
++  avr32*)             cpu_type=avr32 endian=big ;;
+   bfin*)              cpu_type=bfin endian=little ;;
+   c4x*)                       cpu_type=tic4x ;;
+   cr16*)              cpu_type=cr16 endian=little ;;
+@@ -136,6 +137,9 @@ case ${generic_target} in
+   cr16-*-elf*)                                fmt=elf ;;
++  avr32-*-linux*)                     fmt=elf  em=linux bfd_gas=yes ;;
++  avr32*)                             fmt=elf  bfd_gas=yes ;;
++
+   cris-*-linux-* | crisv32-*-linux-*)
+                                       fmt=multi em=linux ;;
+   cris-*-* | crisv32-*-*)             fmt=multi ;;
+--- a/gas/doc/all.texi
++++ b/gas/doc/all.texi
+@@ -30,6 +30,7 @@
+ @set ARC
+ @set ARM
+ @set AVR
++@set AVR32
+ @set Blackfin
+ @set CR16
+ @set CRIS
+--- a/gas/doc/asconfig.texi
++++ b/gas/doc/asconfig.texi
+@@ -30,6 +30,7 @@
+ @set ARC
+ @set ARM
+ @set AVR
++@set AVR32
+ @set Blackfin
+ @set CR16
+ @set CRIS
+--- a/gas/doc/as.texinfo
++++ b/gas/doc/as.texinfo
+@@ -6865,6 +6865,9 @@ subject, see the hardware manufacturer's
+ @ifset AVR
+ * AVR-Dependent::               AVR Dependent Features
+ @end ifset
++@ifset AVR32
++* AVR32-Dependent::               AVR32 Dependent Features
++@end ifset
+ @ifset Blackfin
+ * Blackfin-Dependent::                Blackfin Dependent Features
+ @end ifset
+@@ -7006,6 +7009,10 @@ subject, see the hardware manufacturer's
+ @include c-avr.texi
+ @end ifset
++@ifset AVR32
++@include c-avr32.texi
++@end ifset
++
+ @ifset Blackfin
+ @include c-bfin.texi
+ @end ifset
+--- /dev/null
++++ b/gas/doc/c-avr32.texi
+@@ -0,0 +1,244 @@
++@c Copyright 2005, 2006, 2007, 2008, 2009
++@c Atmel Corporation
++@c This is part of the GAS manual.
++@c For copying conditions, see the file as.texinfo.
++
++@ifset GENERIC
++@page
++@node AVR32-Dependent
++@chapter AVR32 Dependent Features
++@end ifset
++
++@ifclear GENERIC
++@node Machine Dependencies
++@chapter AVR32 Dependent Features
++@end ifclear
++
++@cindex AVR32 support
++@menu
++* AVR32 Options::               Options
++* AVR32 Syntax::                Syntax
++* AVR32 Directives::            Directives
++* AVR32 Opcodes::               Opcodes
++@end menu
++
++@node AVR32 Options
++@section Options
++@cindex AVR32 options
++@cindex options for AVR32
++
++@table @code
++
++@cindex @code{--pic} command line option, AVR32
++@cindex PIC code generation for AVR32
++@item --pic
++This option specifies that the output of the assembler should be marked
++as position-independent code (PIC).  It will also ensure that
++pseudo-instructions that deal with address calculation are output as
++PIC, and that all absolute address references in the code are marked as
++such.
++
++@cindex @code{--linkrelax} command line option, AVR32
++@item --linkrelax
++This option specifies that the output of the assembler should be marked
++as linker-relaxable.  It will also ensure that all PC-relative operands
++that may change during linker relaxation get appropriate relocations.
++
++@end table
++
++
++@node AVR32 Syntax
++@section Syntax
++@menu
++* AVR32-Chars::              Special Characters
++* AVR32-Symrefs::            Symbol references
++@end menu
++
++@node AVR32-Chars
++@subsection Special Characters
++
++@cindex line comment character, AVR32
++@cindex AVR32 line comment character
++The presence of a @samp{//} on a line indicates the start of a comment
++that extends to the end of the current line.  If a @samp{#} appears as
++the first character of a line, the whole line is treated as a comment.
++
++@cindex line separator, AVR32
++@cindex statement separator, AVR32
++@cindex AVR32 line separator
++The @samp{;} character can be used instead of a newline to separate
++statements.
++
++@node AVR32-Symrefs
++@subsection Symbol references
++
++The absolute value of a symbol can be obtained by simply naming the
++symbol.  However, as AVR32 symbols have 32-bit values, most symbols have
++values that are outside the range of any instructions.
++
++Instructions that take a PC-relative offset, e.g. @code{lddpc} or
++@code{rcall}, can also reference a symbol by simply naming the symbol
++(no explicit calculations necessary).  In this case, the assembler or
++linker subtracts the address of the instruction from the symbol's value
++and inserts the result into the instruction.  Note that even though an
++overflow is less likely to happen for a relative reference than for an
++absolute reference, the assembler or linker will generate an error if
++the referenced symbol is too far away from the current location.
++
++Relative references can be used for data as well.  For example:
++
++@smallexample
++        lddpc   r0, 2f
++1:      add     r0, pc
++        ...
++        .align  2
++2:      .int    @var{some_symbol} - 1b
++@end smallexample
++
++Here, r0 will end up with the run-time address of @var{some_symbol} even
++if the program was loaded at a different address than it was linked
++(position-independent code).
++
++@subsubsection Symbol modifiers
++
++@table @code
++
++@item @code{hi(@var{symbol})}
++Evaluates to the value of the symbol shifted right 16 bits.  This will
++work even if @var{symbol} is defined in a different module.
++
++@item @code{lo(@var{symbol})}
++Evaluates to the low 16 bits of the symbol's value.  This will work even
++if @var{symbol} is defined in a different module.
++
++@item @code{@var{symbol}@@got}
++Create a GOT entry for @var{symbol} and return the offset of that entry
++relative to the GOT base.
++
++@end table
++
++
++@node AVR32 Directives
++@section Directives
++@cindex machine directives, AVR32
++@cindex AVR32 directives
++
++@table @code
++
++@cindex @code{.cpool} directive, AVR32
++@item .cpool
++This directive causes the current contents of the constant pool to be
++dumped into the current section at the current location (aligned to a
++word boundary).  @code{GAS} maintains a separate constant pool for each
++section and each sub-section.  The @code{.cpool} directive will only
++affect the constant pool of the current section and sub-section.  At the
++end of assembly, all remaining, non-empty constant pools will
++automatically be dumped.
++
++@end table
++
++
++@node AVR32 Opcodes
++@section Opcodes
++@cindex AVR32 opcodes
++@cindex opcodes for AVR32
++
++@code{@value{AS}} implements all the standard AVR32 opcodes.  It also
++implements several pseudo-opcodes, which are recommended to use wherever
++possible because they give the tool chain better freedom to generate
++optimal code.
++
++@table @code
++
++@cindex @code{LDA.W reg, symbol} pseudo op, AVR32
++@item LDA.W
++@smallexample
++        lda.w   @var{reg}, @var{symbol}
++@end smallexample
++
++This instruction will load the address of @var{symbol} into
++@var{reg}. The instruction will evaluate to one of the following,
++depending on the relative distance to the symbol, the relative distance
++to the constant pool and whether the @code{--pic} option has been
++specified. If the @code{--pic} option has not been specified, the
++alternatives are as follows:
++@smallexample
++        /* @var{symbol} evaluates to a small enough value */
++        mov     @var{reg}, @var{symbol}
++
++        /* (. - @var{symbol}) evaluates to a small enough value */
++        sub     @var{reg}, pc, . - @var{symbol}
++
++        /* Constant pool is close enough */
++        lddpc   @var{reg}, @var{cpent}
++        ...
++@var{cpent}:
++        .long   @var{symbol}
++
++        /* Otherwise (not implemented yet, probably not necessary) */
++        mov     @var{reg}, lo(@var{symbol})
++        orh     @var{reg}, hi(@var{symbol})
++@end smallexample
++
++If the @code{--pic} option has been specified, the alternatives are as
++follows:
++@smallexample
++        /* (. - @var{symbol}) evaluates to a small enough value */
++        sub     @var{reg}, pc, . - @var{symbol}
++
++        /* If @code{--linkrelax} not specified */
++        ld.w    @var{reg}, r6[@var{symbol}@@got]
++
++        /* Otherwise */
++        mov     @var{reg}, @var{symbol}@@got / 4
++        ld.w    @var{reg}, r6[@var{reg} << 2]
++@end smallexample
++
++If @var{symbol} is not defined in the same file and section as the
++@code{LDA.W} instruction, the most pessimistic alternative of the
++above is selected. The linker may convert it back into the most
++optimal alternative when the final value of all symbols is known.
++
++@cindex @code{CALL symbol} pseudo op, AVR32
++@item CALL
++@smallexample
++        call    @var{symbol}
++@end smallexample
++
++This instruction will insert code to call the subroutine identified by
++@var{symbol}. It will evaluate to one of the following, depending on
++the relative distance to the symbol as well as the @code{--linkrelax}
++and @code{--pic} command-line options.
++
++If @var{symbol} is defined in the same section and input file, and the
++distance is small enough, an @code{rcall} instruction is inserted:
++@smallexample
++        rcall   @var{symbol}
++@end smallexample
++
++Otherwise, if the @code{--pic} option has not been specified:
++@smallexample
++        mcall   @var{cpent}
++        ...
++@var{cpent}:
++        .long   @var{symbol}
++@end smallexample
++
++Finally, if nothing else fits and the @code{--pic} option has been
++specified, the assembler will indirect the call through the Global
++Offset Table:
++@smallexample
++        /* If @code{--linkrelax} not specified */
++        mcall   r6[@var{symbol}@@got]
++
++        /* If @code{--linkrelax} specified */
++        mov     lr, @var{symbol}@@got / 4
++        ld.w    lr, r6[lr << 2]
++        icall   lr
++@end smallexample
++
++The linker, after determining the final value of @var{symbol}, may
++convert any of these into more optimal alternatives. This includes
++deleting any superfluous constant pool- and GOT-entries.
++
++@end table
+--- a/gas/doc/Makefile.am
++++ b/gas/doc/Makefile.am
+@@ -33,6 +33,7 @@ CPU_DOCS = \
+       c-arc.texi \
+       c-arm.texi \
+       c-avr.texi \
++      c-avr32.texi \
+       c-bfin.texi \
+       c-cr16.texi \
+       c-d10v.texi \
+--- a/gas/Makefile.am
++++ b/gas/Makefile.am
+@@ -111,6 +111,7 @@ TARGET_CPU_CFILES = \
+       config/tc-arc.c \
+       config/tc-arm.c \
+       config/tc-avr.c \
++      config/tc-avr32.c \
+       config/tc-bfin.c \
+       config/tc-cr16.c \
+       config/tc-cris.c \
+@@ -175,6 +176,7 @@ TARGET_CPU_HFILES = \
+       config/tc-arc.h \
+       config/tc-arm.h \
+       config/tc-avr.h \
++      config/tc-avr32.h \
+       config/tc-bfin.h \
+       config/tc-cr16.h \
+       config/tc-cris.h \
+--- a/gas/Makefile.in
++++ b/gas/Makefile.in
+@@ -378,6 +378,7 @@ TARGET_CPU_CFILES = \
+       config/tc-arc.c \
+       config/tc-arm.c \
+       config/tc-avr.c \
++      config/tc-avr32.c \
+       config/tc-bfin.c \
+       config/tc-cr16.c \
+       config/tc-cris.c \
+@@ -442,6 +443,7 @@ TARGET_CPU_HFILES = \
+       config/tc-arc.h \
+       config/tc-arm.h \
+       config/tc-avr.h \
++      config/tc-avr32.h \
+       config/tc-bfin.h \
+       config/tc-cr16.h \
+       config/tc-cris.h \
+@@ -785,6 +787,7 @@ distclean-compile:
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-arc.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-arm.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-avr.Po@am__quote@
++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-avr32.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-bfin.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-cr16.Po@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-cris.Po@am__quote@
+@@ -923,6 +926,20 @@ tc-avr.obj: config/tc-avr.c
+ @AMDEP_TRUE@@am__fastdepCC_FALSE@     DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tc-avr.obj `if test -f 'config/tc-avr.c'; then $(CYGPATH_W) 'config/tc-avr.c'; else $(CYGPATH_W) '$(srcdir)/config/tc-avr.c'; fi`
++tc-avr32.o: config/tc-avr32.c
++@am__fastdepCC_TRUE@  $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tc-avr32.o -MD -MP -MF $(DEPDIR)/tc-avr32.Tpo -c -o tc-avr32.o `test -f 'config/tc-avr32.c' || echo '$(srcdir)/'`config/tc-avr32.c
++@am__fastdepCC_TRUE@  $(am__mv) $(DEPDIR)/tc-avr32.Tpo $(DEPDIR)/tc-avr32.Po
++@AMDEP_TRUE@@am__fastdepCC_FALSE@     source='config/tc-avr32.c' object='tc-avr32.o' libtool=no @AMDEPBACKSLASH@
++@AMDEP_TRUE@@am__fastdepCC_FALSE@     DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
++@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tc-avr32.o `test -f 'config/tc-avr32.c' || echo '$(srcdir)/'`config/tc-avr32.c
++
++tc-avr32.obj: config/tc-avr32.c
++@am__fastdepCC_TRUE@  $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tc-avr32.obj -MD -MP -MF $(DEPDIR)/tc-avr32.Tpo -c -o tc-avr32.obj `if test -f 'config/tc-avr32.c'; then $(CYGPATH_W) 'config/tc-avr32.c'; else $(CYGPATH_W) '$(srcdir)/config/tc-avr32.c'; fi`
++@am__fastdepCC_TRUE@  $(am__mv) $(DEPDIR)/tc-avr32.Tpo $(DEPDIR)/tc-avr32.Po
++@AMDEP_TRUE@@am__fastdepCC_FALSE@     source='config/tc-avr32.c' obj