Blob Blame History Raw
diff -Nur ../binutils-2.18.orig/binutils/doc/objcopy.1 ./binutils/doc/objcopy.1
--- ../binutils-2.18.orig/binutils/doc/objcopy.1	Tue Oct 23 21:44:42 2007
+++ ./binutils/doc/objcopy.1	Tue Oct 23 22:18:44 2007
@@ -193,6 +193,8 @@
         [\fB\-\-readonly\-text\fR]
         [\fB\-\-pure\fR]
         [\fB\-\-impure\fR]
+        [\fB\-\-change\-pathname\fR \fIold\fR=\fInew\fR]
+        [\fB\-\-basename\fR]
         [\fB\-v\fR|\fB\-\-verbose\fR]
         [\fB\-V\fR|\fB\-\-version\fR]  
         [\fB\-\-help\fR] [\fB\-\-info\fR]
@@ -807,6 +809,23 @@
 It can also be a useful way of reducing the size of a \fB\-\-just\-symbols\fR
 linker input file.
 .RE
+.IP "\fB\-\-change\-pathname\fR \fIold\fR=\fInew\fR" 4
+.IX Item "--change-pathname old=new"
+When converting debugging information using \fB\-\-debugging\fR, for
+every pathname that starts with \fIold\fR, replace the matching part
+by \fInew\fR.  This is intented to map pathnames between different
+debugging tools, or when parts of the object file(s) had their
+pathnames recorded in a different build environment.  Note that only
+leading directory name components might be changed that way, since the
+trailing filename could be recorded elsewhere as well (depending on the
+debugging format of the input file).
+.IP "\fB\-\-basename\fR"
+.IX Item "--basename"
+When converting debugging information using \fB\-\-debugging\fR, for
+every pathname, strip all leading directory information.  This option
+takes precedence over any \fB\-\-change\-pathname\fR option.  For some
+debugging formats that cannot handle long filenames, this options is
+implied (notably, some COFF debugging formats).
 .IP "\fB\-V\fR" 4
 .IX Item "-V"
 .PD 0
diff -Nur ../binutils-2.18.orig/binutils/Makefile.am ./binutils/Makefile.am
--- ../binutils-2.18.orig/binutils/Makefile.am	Tue Oct 23 21:44:42 2007
+++ ./binutils/Makefile.am	Tue Oct 23 22:22:40 2007
@@ -98,7 +98,7 @@
 	resbin.c rescoff.c resrc.c resres.c \
 	size.c srconv.c stabs.c strings.c sysdump.c \
 	unwind-ia64.c version.c \
-	windres.c winduni.c wrstabs.c \
+	windres.c winduni.c wrcoff.c wrstabs.c \
 	windmc.c mclex.c
 
 GENERATED_CFILES = \
@@ -106,7 +106,7 @@
 	defparse.c deflex.c nlmheader.c rcparse.c mcparse.c
 
 DEBUG_SRCS = rddbg.c debug.c stabs.c ieee.c rdcoff.c
-WRITE_DEBUG_SRCS = $(DEBUG_SRCS) wrstabs.c
+WRITE_DEBUG_SRCS = $(DEBUG_SRCS) wrstabs.c wrcoff.c
 
 # Code shared by all the binutils.
 BULIBS = bucomm.c version.c filemode.c
diff -Nur ../binutils-2.18.orig/binutils/Makefile.in ./binutils/Makefile.in
--- ../binutils-2.18.orig/binutils/Makefile.in	Tue Oct 23 21:44:42 2007
+++ ./binutils/Makefile.in	Tue Oct 23 22:26:52 2007
@@ -129,7 +129,7 @@
 nm_new_OBJECTS = $(am_nm_new_OBJECTS)
 nm_new_LDADD = $(LDADD)
 am__objects_2 = rddbg.$(OBJEXT) debug.$(OBJEXT) stabs.$(OBJEXT) \
-	ieee.$(OBJEXT) rdcoff.$(OBJEXT)
+	ieee.$(OBJEXT) rdcoff.$(OBJEXT) wrcoff.$(OBJEXT)
 am__objects_3 = $(am__objects_2) wrstabs.$(OBJEXT)
 am_objcopy_OBJECTS = objcopy.$(OBJEXT) not-strip.$(OBJEXT) \
 	rename.$(OBJEXT) $(am__objects_3) $(am__objects_1)
@@ -418,7 +418,7 @@
 	resbin.c rescoff.c resrc.c resres.c \
 	size.c srconv.c stabs.c strings.c sysdump.c \
 	unwind-ia64.c version.c \
-	windres.c winduni.c wrstabs.c \
+	windres.c winduni.c wrcoff.c wrstabs.c \
 	windmc.c mclex.c
 
 GENERATED_CFILES = \
@@ -426,7 +426,7 @@
 	defparse.c deflex.c nlmheader.c rcparse.c mcparse.c
 
 DEBUG_SRCS = rddbg.c debug.c stabs.c ieee.c rdcoff.c
-WRITE_DEBUG_SRCS = $(DEBUG_SRCS) wrstabs.c
+WRITE_DEBUG_SRCS = $(DEBUG_SRCS) wrstabs.c wrcoff.c
 
 # Code shared by all the binutils.
 BULIBS = bucomm.c version.c filemode.c
diff -Nur ../binutils-2.18.orig/binutils/bucomm.c ./binutils/bucomm.c
--- ../binutils-2.18.orig/binutils/bucomm.c	Tue Oct 23 21:44:42 2007
+++ ./binutils/bucomm.c	Tue Oct 23 22:18:44 2007
@@ -501,6 +501,32 @@
   return ret;
 }
 
+/* Return the basename of "file", i. e. everything minus whatever
+   directory part has been provided.  Stolen from bfd/archive.c.
+   Should we also handle the VMS case (as in bfd/archive.c)?  */
+const char *
+bu_basename (file)
+     const char *file;
+{
+  const char *filename = strrchr (file, '/');
+
+#ifdef HAVE_DOS_BASED_FILE_SYSTEM
+  {
+    /* We could have foo/bar\\baz, or foo\\bar, or d:bar.  */
+    char *bslash = strrchr (file, '\\');
+    if (filename == NULL || (bslash != NULL && bslash > filename))
+      filename = bslash;
+    if (filename == NULL && file[0] != '\0' && file[1] == ':')
+      filename = file + 1;
+  }
+#endif
+  if (filename != (char *) NULL)
+    filename++;
+  else
+    filename = file;
+  return filename;
+}
+
 /* Returns the size of the named file.  If the file does not
    exist, or if it is not a real file, then a suitable non-fatal
    error message is printed and zero is returned.  */
diff -Nur ../binutils-2.18.orig/binutils/bucomm.h ./binutils/bucomm.h
--- ../binutils-2.18.orig/binutils/bucomm.h	Tue Oct 23 21:44:42 2007
+++ ./binutils/bucomm.h	Tue Oct 23 22:18:44 2007
@@ -54,6 +54,8 @@
 
 off_t get_file_size (const char *);
 
+const char *bu_basename PARAMS ((const char *));
+
 extern char *program_name;
 
 /* filemode.c */
diff -Nur ../binutils-2.18.orig/binutils/budbg.h ./binutils/budbg.h
--- ../binutils-2.18.orig/binutils/budbg.h	Tue Oct 23 21:44:42 2007
+++ ./binutils/budbg.h	Tue Oct 23 22:18:44 2007
@@ -51,8 +51,11 @@
 
 extern bfd_boolean write_ieee_debugging_info (bfd *, void *);
 
-/* Routine used to read COFF debugging information.  */
+/* Routine used to read and write COFF debugging information.  */
 
 extern bfd_boolean parse_coff (bfd *, asymbol **, long, void *);
+
+extern bfd_boolean write_coff_debugging_info
+  (bfd *abfd, void *, long *symcountp, asymbol ***);
 
 #endif
--- binutils/debug.c.orig	Mon Aug  6 21:55:10 2007
+++ binutils/debug.c	Tue Oct 23 23:43:19 2007
@@ -31,6 +31,7 @@
 #include <assert.h>
 #include "bfd.h"
 #include "libiberty.h"
+#include "bucomm.h"
 #include "debug.h"
 
 /* Global information we keep for debugging.  A pointer to this
@@ -552,6 +553,19 @@
   struct debug_type *t;
 };
 
+/* Simple list, used for pathname translations. */
+struct xlat_list
+{
+  /* Next string on list. */
+  struct xlat_list *next;
+  /* Old part to match against. */
+  const char *old;
+  size_t olen;
+  /* New part to replace. */
+  const char *newstr;
+  size_t nlen;
+};
+
 /* Local functions.  */
 
 static void debug_error (const char *);
@@ -588,6 +602,11 @@
   (struct debug_handle *, struct debug_type *, struct debug_type *);
 static bfd_boolean debug_class_type_samep
   (struct debug_handle *, struct debug_type *, struct debug_type *);
+static const char *debug_xlat_pathname (const char *);
+
+/* List of pathname translations. */
+static struct xlat_list *xlat, *xltail;
+static bfd_boolean xlat_basename;
 
 /* Issue an error message.  */
 
@@ -680,6 +699,8 @@
 
   if (name == NULL)
     name = "";
+  else
+    name = debug_xlat_pathname (name);
 
   nfile = (struct debug_file *) xmalloc (sizeof *nfile);
   memset (nfile, 0, sizeof *nfile);
@@ -720,6 +741,8 @@
 
   if (name == NULL)
     name = "";
+  else
+    name = debug_xlat_pathname (name);
 
   if (info->current_unit == NULL)
     {
@@ -3369,4 +3392,70 @@
     }
 
   return TRUE;
+}
+
+/* Register a pathname translation. */
+void
+debug_register_pathname_xlat (oname, nname)
+     const char *oname;
+     const char *nname;
+{
+  struct xlat_list *xlp;
+
+  /* Special case: if oname is given as NULL, this means the
+     --basename option has been given to objcopy. */
+  if (oname == NULL)
+    {
+      xlat_basename = TRUE;
+      return;
+    }
+
+  xlp = (struct xlat_list *) xmalloc (sizeof (struct xlat_list));
+  xlp->next = NULL;
+  if (xlat == NULL)
+    xlat = xltail = xlp;
+  else
+    {
+      xltail->next = xlp;
+      xltail = xlp;
+    }
+  xlp->old = oname;
+  xlp->newstr = nname;
+  xlp->olen = strlen (oname);
+  xlp->nlen = strlen (nname);
+}
+
+/* Try to translate a pathname. */
+static const char *
+debug_xlat_pathname (oname)
+     const char *oname;
+{
+  struct xlat_list *xlp;
+  char *cp;
+  size_t olen;
+
+  if (xlat_basename)
+    return bu_basename (oname);  
+
+  olen = strlen (oname);
+  for (xlp = xlat; xlp; xlp = xlp->next)
+    {
+      if (xlp->olen > olen)
+	/* This cannot be our turn. */
+	continue;
+      /* Since we have pre-computed all our length values to avoid
+	 repetitively computing them, just use memcmp() since it's
+	 faster than strcmp(). */
+      if (memcmp (xlp->old, oname, xlp->olen) == 0)
+	{
+	  cp = (char *) xmalloc (olen + xlp->nlen - xlp->olen + 1);
+	  memcpy (cp, xlp->newstr, xlp->nlen);
+	  memcpy (cp + xlp->nlen, oname + xlp->olen,
+		  olen - xlp->olen + 1);
+	  return cp;
+	}
+    }
+
+  /* Not found, pass the original name on. */
+  return oname;
 }
diff -Nur ../binutils-2.18.orig/binutils/debug.h ./binutils/debug.h
--- ../binutils-2.18.orig/binutils/debug.h	Tue Oct 23 21:44:43 2007
+++ ./binutils/debug.h	Tue Oct 23 22:18:44 2007
@@ -440,6 +440,12 @@
 
 extern bfd_boolean debug_start_source (void *, const char *);
 
+/* Register a pathname translation for source (and include) filenames.
+   This is used by the --change-pathname option of objcopy. */
+
+extern void debug_register_pathname_xlat
+  PARAMS ((const char *, const char *));
+
 /* Record a function definition.  This implicitly starts a function
    block.  The debug_type argument is the type of the return value.
    The bfd_boolean indicates whether the function is globally visible.
diff -Nur ../binutils-2.18.orig/binutils/objcopy.c ./binutils/objcopy.c
--- ../binutils-2.18.orig/binutils/objcopy.c	Tue Oct 23 21:44:43 2007
+++ ./binutils/objcopy.c	Tue Oct 23 22:38:29 2007
@@ -32,6 +32,7 @@
 #include "elf-bfd.h"
 #include <sys/stat.h>
 #include "libbfd.h"
+#include "debug.h"
 
 /* A list of symbols to explicitly strip out, or to keep.  A linked
    list is good enough for a small number from the command line, but
@@ -272,7 +273,9 @@
     OPTION_PURE,
     OPTION_IMPURE,
     OPTION_EXTRACT_SYMBOL,
-    OPTION_REVERSE_BYTES
+    OPTION_REVERSE_BYTES,
+    OPTION_CHANGE_PATHNAME,
+    OPTION_BASENAME
   };
 
 /* Options to handle if running as "strip".  */
@@ -316,10 +319,12 @@
   {"adjust-section-vma", required_argument, 0, OPTION_CHANGE_SECTION_ADDRESS},
   {"adjust-warnings", no_argument, 0, OPTION_CHANGE_WARNINGS},
   {"alt-machine-code", required_argument, 0, OPTION_ALT_MACH_CODE},
+  {"basename", no_argument, 0, OPTION_BASENAME},
   {"binary-architecture", required_argument, 0, 'B'},
   {"byte", required_argument, 0, 'b'},
   {"change-addresses", required_argument, 0, OPTION_CHANGE_ADDRESSES},
   {"change-leading-char", no_argument, 0, OPTION_CHANGE_LEADING_CHAR},
+  {"change-pathname", required_argument, 0, OPTION_CHANGE_PATHNAME},
   {"change-section-address", required_argument, 0, OPTION_CHANGE_SECTION_ADDRESS},
   {"change-section-lma", required_argument, 0, OPTION_CHANGE_SECTION_LMA},
   {"change-section-vma", required_argument, 0, OPTION_CHANGE_SECTION_VMA},
@@ -504,6 +509,8 @@
      --prefix-alloc-sections <prefix>\n\
                                    Add <prefix> to start of every allocatable\n\
                                      section name\n\
+     --change-pathname <old>=<new> Change debug pathnames from <old> to <new>\n\
+     --basename                    Strip directory part from debug pathnames\n\
   -v --verbose                     List all object files modified\n\
   @<file>                          Read options from <file>\n\
   -V --version                     Display this program's version number\n\
@@ -911,6 +918,8 @@
   asymbol **from = isyms, **to = osyms;
   long src_count = 0, dst_count = 0;
   int relocatable = (abfd->flags & (EXEC_P | DYNAMIC)) == 0;
+  bfd_boolean need_for_debugging = convert_debugging
+    && bfd_get_arch (abfd) == bfd_arch_avr;
 
   for (; src_count < symcount; src_count++)
     {
@@ -1010,9 +1019,10 @@
 	       || bfd_is_com_section (bfd_get_section (sym)))
 	keep = strip_symbols != STRIP_UNNEEDED;
       else if ((flags & BSF_DEBUGGING) != 0)	/* Debugging symbol.  */
-	keep = (strip_symbols != STRIP_DEBUG
-		&& strip_symbols != STRIP_UNNEEDED
-		&& ! convert_debugging);
+	keep = need_for_debugging
+		|| (strip_symbols != STRIP_DEBUG
+		    && strip_symbols != STRIP_UNNEEDED
+		    && ! convert_debugging);
       else if (bfd_coff_get_comdat_section (abfd, bfd_get_section (sym)))
 	/* COMDAT sections store special information in local
 	   symbols, so we cannot risk stripping any of them.  */
@@ -2588,6 +2598,10 @@
     return write_ieee_debugging_info (obfd, dhandle);
 
   if (bfd_get_flavour (obfd) == bfd_target_coff_flavour
+      && bfd_get_arch (obfd) == bfd_arch_avr)
+    return write_coff_debugging_info (obfd, dhandle, symcountp, symppp);
+
+  if (bfd_get_flavour (obfd) == bfd_target_coff_flavour
       || bfd_get_flavour (obfd) == bfd_target_elf_flavour)
     {
       bfd_byte *syms, *strings;
@@ -3287,6 +3301,30 @@
 
 	case OPTION_PREFIX_ALLOC_SECTIONS:
 	  prefix_alloc_sections_string = optarg;
+	  break;
+
+	case OPTION_CHANGE_PATHNAME:
+	  {
+	    const char *s;
+	    int len;
+	    char *name;
+
+	    s = strchr (optarg, '=');
+	    if (s == NULL)
+	      fatal (_("bad format for %s"), "--change-pathname");
+
+	    len = s - optarg;
+	    name = (char *) xmalloc (len + 1);
+	    strncpy (name, optarg, len);
+	    name[len] = '\0';
+
+	    debug_register_pathname_xlat (name, s + 1);
+	  }
+	  break;
+
+	case OPTION_BASENAME:
+	  /* very special case of pathname translation */
+	  debug_register_pathname_xlat (NULL, NULL);
 	  break;
 
 	case OPTION_READONLY_TEXT:
diff -Nur ../binutils-2.18.orig/binutils/rdcoff.c ./binutils/rdcoff.c
--- ../binutils-2.18.orig/binutils/rdcoff.c	Tue Oct 23 21:44:43 2007
+++ ./binutils/rdcoff.c	Tue Oct 23 22:18:44 2007
@@ -82,6 +82,9 @@
   struct coff_slots *slots;
   /* Basic types.  */
   debug_type basic[T_MAX + 1];
+  /* Some general information, kept here for convenience. */
+  size_t intsize;		/* sizeof (int) */
+  size_t doublesize;		/* sizeof (double) */
 };
 
 static debug_type *coff_get_slot (struct coff_types *, int);
@@ -101,6 +104,7 @@
   (bfd *, struct coff_types *, asymbol *, long, struct internal_syment *,
    void *, debug_type, bfd_boolean);
 static bfd_boolean external_coff_symbol_p (int sym_class);
+static bfd_vma coff_convert_register (bfd *, bfd_vma);
 
 /* Return the slot for a type.  */
 
@@ -271,8 +275,7 @@
       break;
 
     case T_INT:
-      /* FIXME: Perhaps the size should depend upon the architecture.  */
-      ret = debug_make_int_type (dhandle, 4, FALSE);
+      ret = debug_make_int_type (dhandle, types->intsize, FALSE);
       name = "int";
       break;
 
@@ -287,7 +290,7 @@
       break;
 
     case T_DOUBLE:
-      ret = debug_make_float_type (dhandle, 8);
+      ret = debug_make_float_type (dhandle, types->doublesize);
       name = "double";
       break;
 
@@ -307,7 +310,7 @@
       break;
 
     case T_UINT:
-      ret = debug_make_int_type (dhandle, 4, TRUE);
+      ret = debug_make_int_type (dhandle, types->intsize, TRUE);
       name = "unsigned int";
       break;
 
@@ -565,6 +568,8 @@
 
     case C_WEAKEXT:
     case C_EXT:
+      /* AVR COFF abuses C_EXTDEF */
+    case C_EXTDEF:
       if (! debug_record_variable (dhandle, bfd_asymbol_name (sym), type,
 				   DEBUG_GLOBAL, bfd_asymbol_value (sym)))
 	return FALSE;
@@ -580,9 +585,9 @@
       break;
 
     case C_REG:
-      /* FIXME: We may need to convert the register number.  */
       if (! debug_record_variable (dhandle, bfd_asymbol_name (sym), type,
-				   DEBUG_REGISTER, bfd_asymbol_value (sym)))
+				   DEBUG_REGISTER,
+				   coff_convert_register (abfd, bfd_asymbol_value (sym))))
 	return FALSE;
       break;
 
@@ -596,9 +601,9 @@
       break;
 
     case C_REGPARM:
-      /* FIXME: We may need to convert the register number.  */
       if (! debug_record_parameter (dhandle, bfd_asymbol_name (sym), type,
-				    DEBUG_PARM_REG, bfd_asymbol_value (sym)))
+				    DEBUG_PARM_REG,
+				    coff_convert_register (abfd, bfd_asymbol_value (sym))))
 	return FALSE;
       break;
 
@@ -648,6 +653,28 @@
   return FALSE;
 }
 
+static bfd_vma
+coff_convert_register (abfd, val)
+     bfd *abfd;
+     bfd_vma val;
+{
+
+  switch (bfd_get_arch (abfd))
+    {
+    case bfd_arch_avr:
+      /* AVR COFF wants to describe up to four registers by the four
+	 bytes of the 32-bit value.  Unused bytes are filled with
+	 0xff.  In theory, this would allow for non-contiguous
+	 register usage to hold a single value, but hopefully, no
+	 compiler is going to use that feature.  We could not handle
+	 it anyway. */
+      return val & 0xff;
+
+    default:
+      return val;
+    }
+}
+
 /* This is the main routine.  It looks through all the symbols and
    handles them.  */
 
@@ -674,6 +701,17 @@
   types.slots = NULL;
   for (i = 0; i <= T_MAX; i++)
     types.basic[i] = DEBUG_TYPE_NULL;
+  switch (bfd_get_arch (abfd))
+    {
+    case bfd_arch_avr:
+      types.intsize = 2;
+      types.doublesize = 4;
+      break;
+
+    default:
+      types.intsize = 4;
+      types.doublesize = 8;
+    }
 
   next_c_file = -1;
   fnname = NULL;
@@ -734,7 +772,6 @@
       switch (syment.n_sclass)
 	{
 	case C_EFCN:
-	case C_EXTDEF:
 	case C_ULABEL:
 	case C_USTATIC:
 	case C_LINE:
@@ -757,6 +794,8 @@
 	  /* Fall through.  */
 	case C_WEAKEXT:
 	case C_EXT:
+	  /* AVR COFF abuses C_EXTDEF for C_EXT */
+	case C_EXTDEF:
 	  if (ISFCN (syment.n_type))
 	    {
 	      fnname = name;
diff -Nur ../binutils-2.18.orig/binutils/wrcoff.c ./binutils/wrcoff.c
--- ../binutils-2.18.orig/binutils/wrcoff.c	Thu Jan  1 01:00:00 1970
+++ ./binutils/wrcoff.c	Tue Oct 23 22:18:44 2007
@@ -0,0 +1,3410 @@
+/* wrcoff.c -- Generate (AVR) COFF debugging information
+   Copyright 2003 Free Software Foundation, Inc.
+
+   Written by Joerg Wunsch.
+
+   This file is part of GNU Binutils.
+
+   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.  */
+
+/* This file contains code which writes out COFF debugging
+   information.  By now, this has only been tested on the AVR
+   platform, though any attempt has been made to keep the conversion
+   applicable to possible other COFF debugging consumers as well. */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "sysdep.h"
+#include "bfd.h"
+#include "coff/internal.h"
+#include "bucomm.h"
+#include "libiberty.h"
+#include "safe-ctype.h"
+#include "debug.h"
+#include "budbg.h"
+
+/* Enabling COFF_DEBUG will trace the internal callback functions and
+   their parameters as debug_write() calls them. */
+//#define COFF_DEBUG 1
+
+#include "libcoff.h"
+
+#define N_TMASK (coff_data (info->abfd)->local_n_tmask)
+#define N_BTSHFT (coff_data (info->abfd)->local_n_btshft)
+#define N_BTMASK (coff_data (info->abfd)->local_n_btmask)
+#define N_TSHIFT (coff_data (info->abfd)->local_n_tshift)
+
+/* Structure of local symbols per compilation unit. */
+struct coff_compilation_unit
+{
+  const char *fname;
+  asymbol **syms;
+  long nsyms, totsyms;
+};
+
+enum ts_kind
+{
+  TS_EMPTY,
+  TS_VOID,
+  TS_INT,
+  TS_FLOAT,
+  TS_COMPLEX,
+  TS_ENUM,
+  TS_POINTER,
+  TS_FUNC,
+  TS_ARRAY,
+  TS_STRUCT,
+  TS_NONE = -1
+};
+
+/* Structure defining the pre-defined types. */
+struct coff_predef_type
+{
+  enum ts_kind kind;
+  unsigned int size;		/* in bytes */
+  bfd_boolean isunsigned;
+  int slot;
+};
+
+struct coff_type_stack;
+struct coff_hash_entry;
+
+struct coff_struct_fields
+{
+  const char *name;
+  bfd_vma bitpos;
+  bfd_vma bitsize;
+  enum debug_visibility visibility;
+  struct coff_type_stack *types;
+};
+
+/* Our type stack. */
+struct coff_type_stack
+{
+  struct coff_type_stack *next;
+  enum ts_kind tsk;
+  union
+  {
+    /* TS_INT */
+    struct
+    {
+      unsigned int size;
+      bfd_boolean isunsigned;
+    }
+    ts_int;
+
+    /* TS_FLOAT */
+    struct
+    {
+      unsigned int size;
+    }
+    ts_float;
+
+    /* TS_ENUM */
+    struct
+    {
+      union
+      {
+	const char *fixtag;
+	char *malloctag;
+      }
+      tag;
+      bfd_boolean tagismalloced;
+      const char **names;
+      bfd_signed_vma *vals;
+      struct coff_enum_hash_entry *ehash;
+    }
+    ts_enum;
+
+    /* TS_FUNC */
+    struct
+    {
+      struct coff_type_stack *savedts;
+    }
+    ts_func;
+
+    /* TS_ARRAY */
+    struct
+    {
+      bfd_signed_vma low;
+      bfd_signed_vma high;
+    }
+    ts_array;
+
+    /* TS_STRUCT */
+    struct
+    {
+      union
+      {
+	const char *fixtag;
+	char *malloctag;
+      }
+      tag;
+      bfd_boolean tagismalloced;
+      unsigned int id;
+      bfd_boolean isstruct;
+      unsigned int size;
+      long nfields;
+      struct coff_struct_fields *fields;
+      struct coff_type_stack *savedts;
+      struct coff_struct_hash_entry *shash;
+    }
+    ts_struct;
+  }
+  u;
+};
+
+struct coff_name_type_hash_table
+{
+  struct bfd_hash_table root;
+};
+
+struct coff_name_type_hash_entry
+{
+  struct bfd_hash_entry root;
+  /* Information for this name.  */
+  struct coff_type_stack *types;
+  bfd_boolean emitted;
+};
+
+struct coff_struct_hash_table
+{
+  struct bfd_hash_table root;
+};
+
+struct coff_struct_hash_entry
+{
+  struct bfd_hash_entry root;
+  /* Information for this name.  */
+  struct coff_type_stack *types;
+  bfd_boolean emitted;
+  combined_entry_type *native;
+  /* list of symbol indices that need fixing */
+  long *fixidxs;
+  unsigned nfixidxs;
+};
+
+struct coff_enum_hash_table
+{
+  struct bfd_hash_table root;
+};
+
+struct coff_enum_hash_entry
+{
+  struct bfd_hash_entry root;
+  /* Information for this name.  */
+  struct coff_type_stack *types;
+  bfd_boolean emitted;
+  combined_entry_type *native;
+  /* list of symbol indices that need fixing */
+  long *fixidxs;
+  unsigned nfixidxs;
+};
+
+/* COFF private symbol data.  Used as a cookie to pass data around
+   between various processing stages.  The generic COFF handling code
+   doesn't use any private data. */
+struct coff_private_symdata
+{
+  unsigned int size;		/* size of symbol, used in AVR register
+				   translation */
+  struct coff_struct_hash_entry *shash; /* TS_STRUCT hash for fixups */
+  struct coff_enum_hash_entry *ehash; /* TS_ENUM hash for fixups */
+};
+
+/* Stack of tags that need endndx fixing. */
+struct coff_fix_stack
+{
+  struct coff_fix_stack *next;
+  combined_entry_type *native;
+};
+
+/* This is the handle passed through debug_write.  */
+
+struct coff_write_handle
+{
+  /* The BFD.  */
+  bfd *abfd;
+  /* Pointers to .text and .data sections, can be used as defaults if
+     no other information is available. */
+  asection *textsect;
+  asection *datasect;
+  /* Some special flags. */
+  unsigned long flags;
+  /* Flags describing architecture options. */
+#define COFF_FL_AVR	0x0001	/* COFF is for AVR platform. */
+#define COFF_FL_EXT_AVR	0x0002	/* AVR "extended" COFF */
+  /* Flags describing internal status information. */
+#define COFF_FL_FIX_ENDNDX	0x10000	/* apply endndx fix at next symbol */
+#define COFF_FL_START_FCN	0x20000	/* begin of function pending */
+#define COFF_FL_FIX_BB		0x40000	/* fix last ".bb" symbol */
+  /* List of our compilation units, from input symbol table. */
+  struct coff_compilation_unit *units;
+  long nunits;
+  struct coff_compilation_unit *currentfile;
+  /* Global symbols from input symbol table. */
+  asymbol **globals;
+  long nglobals;
+  /* Section syms for named sections. */
+  coff_symbol_type **secsyms;
+  long nsecsyms;
+  /* Our COFF symbols. */
+  asymbol **syms;
+  long nsyms;
+  /* Total line number count. */
+  unsigned long totlnos;
+  /* Size of standard objects on this arch. */
+  unsigned int pointersize;
+  unsigned int enumsize;
+  /* Pending information when starting a function.  We have to defer
+     almost everything, some actions can be taken when seeing the
+     starting block of that function, some will even have to wait
+     until we see the end of the function. */
+  const char *funname;		/* name of function */
+  bfd_boolean funglobal;		/* global/local function? */
+  unsigned int lastlno;		/* last line number seen so far */
+  long funcindex;		/* index of ".func" symbol in syms */
+  unsigned int nlnos;		/* line numbers recorded for this function*/
+  bfd_vma endaddr;		/* last .eb address we have seen so far */
+  unsigned int funlno;		/* first line number in function */
+  coff_symbol_type **fargs;	/* function arguments */
+  unsigned int nfargs;
+  asection *funcsection;	/* section the current function is using */
+  /* Type information */
+  struct coff_type_stack *tstack;
+  struct coff_name_type_hash_table types;
+  struct coff_struct_hash_table structs;
+  struct coff_enum_hash_table enums;
+  unsigned nenums;		/* counter for anonymous enum tags */
+  /* Stack of pending endndx fixes, see coff_record_symbol(). */
+  struct coff_fix_stack *fixes;
+};
+
+/* Predefined types, default to usual 32-bit architectures.
+   Arch-dependant different byte sizes will be tuned upon entering
+   write_coff_debugging_info().  The table is looked up from front to
+   end, so we put `more popular' types that might have the same size
+   as other types first (e. g. "int" precedes "long" and "short"). */
+static struct coff_predef_type coff_predef_types[] =
+{
+  { TS_INT, 4, FALSE, 4 },	/* signed int */
+  { TS_INT, 1, FALSE, 2 },	/* signed char */
+  { TS_INT, 2, FALSE, 3 },	/* signed short */
+  { TS_INT, 4, FALSE, 5 },	/* long int */
+  { TS_FLOAT, 8, FALSE, 7 },	/* double */
+  { TS_FLOAT, 4, FALSE, 6 },	/* float */
+  { TS_INT, 4, TRUE, 14 },	/* unsigned int */
+  { TS_INT, 1, TRUE, 12 },	/* unsigned char */
+  { TS_INT, 2, TRUE, 13 },	/* unsigned short */
+  { TS_INT, 4, TRUE, 15 },	/* unsigned long */
+};
+
+static bfd_boolean coff_copy_symbols
+  PARAMS ((struct coff_write_handle *, long, asymbol **));
+static asymbol *coff_find_symbol
+  PARAMS ((struct coff_write_handle *, const char *, bfd_boolean, bfd_boolean));
+static void coff_record_symbol
+  PARAMS ((struct coff_write_handle *, coff_symbol_type *));
+static symvalue coff_fixup_avr_register PARAMS ((symvalue, int));
+static struct bfd_hash_entry *coff_name_type_newfunc
+  PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
+static bfd_boolean coff_free_type_info
+  PARAMS ((struct coff_name_type_hash_entry *, PTR));
+static struct bfd_hash_entry *coff_struct_newfunc
+  PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
+static bfd_boolean coff_free_struct_info
+  PARAMS ((struct coff_struct_hash_entry *, PTR));
+static struct bfd_hash_entry *coff_enum_newfunc
+  PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
+static bfd_boolean coff_free_enum_info
+  PARAMS ((struct coff_enum_hash_entry *, PTR));
+static unsigned int coff_get_fundamental_type
+  PARAMS ((struct coff_write_handle *, struct coff_type_stack *));
+static bfd_boolean coff_make_typed_symbol
+  PARAMS ((struct coff_write_handle *, coff_symbol_type **, enum ts_kind));
+static bfd_boolean coff_emit_struct
+  PARAMS ((struct coff_write_handle *, struct coff_type_stack *,
+	   struct coff_struct_hash_entry *));
+static bfd_boolean coff_emit_enum
+  PARAMS ((struct coff_write_handle *, struct coff_type_stack *,
+	   struct coff_enum_hash_entry *));
+static bfd_boolean coff_emit_ndebug_sym
+  PARAMS ((struct coff_write_handle *, asymbol *, bfd_boolean));
+
+static bfd_boolean coff_start_compilation_unit PARAMS ((PTR, const char *));
+static bfd_boolean coff_start_source PARAMS ((PTR, const char *));
+static bfd_boolean coff_empty_type PARAMS ((PTR));
+static bfd_boolean coff_void_type PARAMS ((PTR));
+static bfd_boolean coff_int_type PARAMS ((PTR, unsigned int, bfd_boolean));
+static bfd_boolean coff_float_type PARAMS ((PTR, unsigned int));
+static bfd_boolean coff_complex_type PARAMS ((PTR, unsigned int));
+static bfd_boolean coff_bool_type PARAMS ((PTR, unsigned int));
+static bfd_boolean coff_enum_type
+  PARAMS ((PTR, const char *, const char **, bfd_signed_vma *));
+static bfd_boolean coff_pointer_type PARAMS ((PTR));
+static bfd_boolean coff_function_type PARAMS ((PTR, int, bfd_boolean));
+static bfd_boolean coff_reference_type PARAMS ((PTR));
+static bfd_boolean coff_range_type PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma));
+static bfd_boolean coff_array_type
+  PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma, bfd_boolean));
+static bfd_boolean coff_set_type PARAMS ((PTR, bfd_boolean));
+static bfd_boolean coff_offset_type PARAMS ((PTR));
+static bfd_boolean coff_method_type PARAMS ((PTR, bfd_boolean, int, bfd_boolean));
+static bfd_boolean coff_const_type PARAMS ((PTR));
+static bfd_boolean coff_volatile_type PARAMS ((PTR));
+static bfd_boolean coff_start_struct_type
+  PARAMS ((PTR, const char *, unsigned int, bfd_boolean, unsigned int));
+static bfd_boolean coff_struct_field
+  PARAMS ((PTR, const char *, bfd_vma, bfd_vma, enum debug_visibility));
+static bfd_boolean coff_end_struct_type PARAMS ((PTR));
+static bfd_boolean coff_start_class_type
+  PARAMS ((PTR, const char *, unsigned int, bfd_boolean, unsigned int, bfd_boolean,
+	   bfd_boolean));
+static bfd_boolean coff_class_static_member
+  PARAMS ((PTR, const char *, const char *, enum debug_visibility));
+static bfd_boolean coff_class_baseclass
+  PARAMS ((PTR, bfd_vma, bfd_boolean, enum debug_visibility));
+static bfd_boolean coff_class_start_method PARAMS ((PTR, const char *));
+static bfd_boolean coff_class_method_variant
+  PARAMS ((PTR, const char *, enum debug_visibility, bfd_boolean, bfd_boolean,
+	   bfd_vma, bfd_boolean));
+static bfd_boolean coff_class_static_method_variant
+  PARAMS ((PTR, const char *, enum debug_visibility, bfd_boolean, bfd_boolean));
+static bfd_boolean coff_class_end_method PARAMS ((PTR));
+static bfd_boolean coff_end_class_type PARAMS ((PTR));
+static bfd_boolean coff_typedef_type PARAMS ((PTR, const char *));
+static bfd_boolean coff_tag_type
+  PARAMS ((PTR, const char *, unsigned int, enum debug_type_kind));
+static bfd_boolean coff_typdef PARAMS ((PTR, const char *));
+static bfd_boolean coff_tag PARAMS ((PTR, const char *));
+static bfd_boolean coff_int_constant PARAMS ((PTR, const char *, bfd_vma));
+static bfd_boolean coff_float_constant PARAMS ((PTR, const char *, double));
+static bfd_boolean coff_typed_constant PARAMS ((PTR, const char *, bfd_vma));
+static bfd_boolean coff_variable
+  PARAMS ((PTR, const char *, enum debug_var_kind, bfd_vma));
+static bfd_boolean coff_start_function PARAMS ((PTR, const char *, bfd_boolean));
+static bfd_boolean coff_function_parameter
+  PARAMS ((PTR, const char *, enum debug_parm_kind, bfd_vma));
+static bfd_boolean coff_start_block PARAMS ((PTR, bfd_vma));
+static bfd_boolean coff_end_block PARAMS ((PTR, bfd_vma));
+static bfd_boolean coff_end_function PARAMS ((PTR));
+static bfd_boolean coff_lineno
+  PARAMS ((PTR, const char *, unsigned long, bfd_vma));
+
+static const struct debug_write_fns coff_fns =
+{
+  coff_start_compilation_unit,
+  coff_start_source,
+  coff_empty_type,
+  coff_void_type,
+  coff_int_type,
+  coff_float_type,
+  coff_complex_type,
+  coff_bool_type,
+  coff_enum_type,
+  coff_pointer_type,
+  coff_function_type,
+  coff_reference_type,
+  coff_range_type,
+  coff_array_type,
+  coff_set_type,
+  coff_offset_type,
+  coff_method_type,
+  coff_const_type,
+  coff_volatile_type,
+  coff_start_struct_type,
+  coff_struct_field,
+  coff_end_struct_type,
+  coff_start_class_type,
+  coff_class_static_member,
+  coff_class_baseclass,
+  coff_class_start_method,
+  coff_class_method_variant,
+  coff_class_static_method_variant,
+  coff_class_end_method,
+  coff_end_class_type,
+  coff_typedef_type,
+  coff_tag_type,
+  coff_typdef,
+  coff_tag,
+  coff_int_constant,
+  coff_float_constant,
+  coff_typed_constant,
+  coff_variable,
+  coff_start_function,
+  coff_function_parameter,
+  coff_start_block,
+  coff_end_block,
+  coff_end_function,
+  coff_lineno
+};
+
+/*
+ * Copy our input (non-debugging) symbols.  Local symbols will be
+ * maintained in one bucket per each compilation unit, global (and
+ * weak) symbols will be kept in a simple array.
+ */
+static bfd_boolean
+coff_copy_symbols (info, count, sympp)
+     struct coff_write_handle *info;
+     long count;
+     asymbol **sympp;
+{
+  asymbol *osym;
+  long i;
+  struct coff_compilation_unit *up;
+
+  up = NULL;
+
+  for (i = 0; i < count; i++)
+    {
+      osym = sympp[i];
+
+      /* Try to figure out the .text and .data sections from our input
+	 symbols as we walk them.  Unfortunately, this ought to be the
+	 /input/ section pointers, so their ->output_section is
+	 non-NULL.  That's why we can't simply walk through all the
+	 sections of our abfd since this is describing the output
+	 only. */
+      if (info->textsect == NULL && osym->section->flags & SEC_CODE)
+	/* Assume this to be our .text section. */
+	info->textsect = osym->section;
+      else if (info->datasect == NULL && osym->section->flags & SEC_DATA)
+	/* Assume this to be our .data section. */
+	info->datasect = osym->section;
+
+      if (osym->flags & BSF_FILE)
+	{
+	  /* New file name. */
+	  long l;
+
+	  up = NULL;
+
+	  /* Well, maybe an old one actually?  If so, append it there.
+	     This can happen for files that contribute to multiple
+	     (input) sections that were concatenated by the linker
+	     (like crt1.S). */
+	  for (l = 0; l < info->nunits; l++)
+	    {
+	      if (strcmp (info->units[l].fname, osym->name) == 0)
+		{
+		  up = info->units + l;
+		  break;
+		}
+	    }
+
+	  if (up == NULL)
+	    {
+	      info->units = (struct coff_compilation_unit *)
+		xrealloc (info->units,
+			  ++info->nunits * sizeof(struct coff_compilation_unit));
+	      up = info->units + (info->nunits - 1);
+	      up->fname = osym->name;
+	      up->syms = NULL;
+	      up->nsyms = up->totsyms = 0;
+	    }
+	}
+      else if (osym->flags & (BSF_GLOBAL | BSF_WEAK))
+	{
+	  /* Global (or weak) symbols are recorded outside compilation
+	     units. */
+	  info->globals = (asymbol **)
+	    xrealloc (info->globals, ++info->nglobals * sizeof(asymbol *));
+	  info->globals[info->nglobals - 1] = osym;
+	  continue;
+	}
+      else if (!bfd_is_const_section(osym->section))
+	{
+	  if (osym->flags & BSF_SECTION_SYM)
+	    {
+	      coff_symbol_type *csymp;
+	      /* Just record them by now, they'll be fixed up later. */
+
+	      if (info->nsyms == 0 && (info->flags & COFF_FL_AVR) == 0)
+		{
+		  /* Very first symbol, fake a compilation unit name
+		     for it.  Historical precedence seems to dictate
+		     this, but AVR COFF does not use that. */
+		  csymp = (coff_symbol_type *)
+		    coff_bfd_make_debug_symbol (info->abfd, 0, 0);
+		  if (csymp == NULL)
+		    return FALSE;
+
+		  csymp->symbol.name = xstrdup ("<fake>");
+		  csymp->symbol.value = 0;
+		  csymp->symbol.udata.p = NULL;
+		  csymp->native->u.syment.n_sclass = C_FILE;
+		  /* force filename into aux entry */
+		  csymp->native->u.syment.n_numaux = 1;
+		  coff_record_symbol (info, csymp);
+		}
+
+	      /* convert to COFF native section symbol */
+	      csymp = (coff_symbol_type *)
+		coff_bfd_make_debug_symbol (info->abfd, 0, 0);
+	      if (csymp == NULL)
+		return FALSE;
+
+	      csymp->symbol.name = xstrdup (osym->section->name);
+	      csymp->symbol.value = osym->section->output_section->vma;
+	      csymp->symbol.flags = BSF_DEBUGGING | BSF_SECTION_SYM;
+	      csymp->symbol.section = osym->section;
+	      csymp->symbol.udata.p = NULL;
+	      csymp->native->fix_scnlen = 1;
+	      csymp->native->u.syment.n_sclass = C_STAT;
+	      csymp->native->u.syment.n_type = T_NULL;
+	      csymp->native->u.syment.n_numaux = 1;
+
+	      coff_record_symbol (info, csymp);
+
+	      info->secsyms = (coff_symbol_type **)
+		xrealloc (info->secsyms,
+			  ++info->nsecsyms * sizeof(coff_symbol_type *));
+	      info->secsyms[info->nsecsyms - 1] = csymp;
+	    }
+	  else
+	    {
+	      /* Local symbol in a named section, will be recorded
+		 within the respective compilation unit. */
+	      if (up == NULL)
+		{
+		  fprintf (stderr,
+			   _("Discarding local symbol outside any compilation unit"));
+		  if (osym->name)
+		    fprintf (stderr, ": %s", osym->name);
+		  putc ('\n', stderr);
+		}
+	      else
+		{
+		  up->syms = (asymbol **)
+		    xrealloc (up->syms, ++up->nsyms * sizeof(asymbol *));
+		  up->syms[up->nsyms - 1] = osym;
+		  up->totsyms = up->nsyms;
+		  continue;
+		}
+	    }
+	}
+    }
+
+  return TRUE;
+}
+
+/* Find a name in the symbol table.  If found, the respective entry in
+   the symbol vector is zeroed, so after processing all debugging
+   symbols, only non-debugging symbols will remain. */
+static asymbol *
+coff_find_symbol (info, name, isfunction, global)
+     struct coff_write_handle *info;
+     const char *name;
+     bfd_boolean isfunction;
+     bfd_boolean global;
+{
+  asymbol *symp;
+  long i;
+  size_t namelen;
+
+  if (global)
+    {
+      for (i = 0; i < info->nglobals; i++)
+	{
+	  symp = info->globals[i];
+	  if (symp == NULL)
+	    continue;
+	  if (strcmp (name, symp->name) == 0
+	      && ((symp->flags & BSF_FUNCTION) != 0) == (isfunction == TRUE))
+	    {
+	      info->globals[i] = NULL;
+	      return symp;
+	    }
+	}
+      return NULL;
+    }
+
+  if (info->currentfile == NULL)
+    return NULL;
+
+  /* For local symbols, the match optionally stops at a dot in the
+     symtab symbol's name; this is used by gcc to indicate
+     function-scope static symbols (e. g. symbol "foo" will become
+     "foo.1" in function scope). */
+  namelen = strlen (name);
+  for (i = 0; i < info->currentfile->nsyms; i++)
+    {
+      symp = info->currentfile->syms[i];
+      if (symp == NULL)
+	continue;
+      if (strncmp (name, symp->name, namelen) == 0
+	  && (symp->name[namelen] == '\0' || symp->name[namelen] == '.')
+	  && ((symp->flags & BSF_FUNCTION) != 0) == (isfunction == TRUE))
+	{
+	  info->currentfile->syms[i] = NULL;
+	  info->currentfile->totsyms--;
+	  return symp;
+	}
+    }
+  return NULL;
+}
+
+static void
+coff_record_symbol (info, csymp)
+     struct coff_write_handle *info;
+     coff_symbol_type *csymp;
+{
+  struct coff_private_symdata *priv;
+
+  info->syms = (asymbol **) xrealloc (info->syms,
+				      ++info->nsyms * sizeof (asymbol *));
+  info->syms[info->nsyms - 1] = (asymbol *)csymp;
+
+  if ((priv = csymp->symbol.udata.p) != NULL)
+    {
+      if (priv->shash != NULL)
+	{
+	  struct coff_struct_hash_entry *shash = priv->shash;
+	  shash->fixidxs = (long *)
+	    xrealloc (shash->fixidxs, ++shash->nfixidxs * sizeof (long));
+	  shash->fixidxs[shash->nfixidxs - 1] = info->nsyms - 1;
+	}
+      if (priv->ehash != NULL)
+	{
+	  struct coff_enum_hash_entry *ehash = priv->ehash;
+	  ehash->fixidxs = (long *)
+	    xrealloc (ehash->fixidxs, ++ehash->nfixidxs * sizeof (long));
+	  ehash->fixidxs[ehash->nfixidxs - 1] = info->nsyms - 1;
+	}
+      free (priv);
+      csymp->symbol.udata.p = NULL;
+    }
+
+  /* If there are any pending endndx fixes, pop the last element from
+     that stack, and record the current symbol for fixing.  We need to
+     do this here since we need to record our current csymp->native
+     (where that csymp is completely unrelated to whatever symbol was
+     previously generated that requested the fixup).  The stack of
+     pending fixes is required since several endndx fixes could be
+     nested, e. g. the start of a function has a pending fix that
+     needs to point to the first symbol after the function, but there
+     could be an anonymous struct definition inside that function's
+     local variables where the endndx needs to point after the last
+     symbol of this struct.  Also, structs and unions could be nested.
+
+     Each call to coff_record_symbol() can fix at most one endndx
+     (even if more are pending in the stack), but that's OK.
+
+     Note that bfd/coffgen.c converts that csymp->native into a
+     symtable slot number after coff_renumber_symbols() has been
+     run. */
+  if (info->flags & COFF_FL_FIX_ENDNDX)
+    {
+      struct coff_fix_stack *fsp, *ofsp;
+      union internal_auxent *aux;
+
+      assert (info->fixes != NULL);
+
+      fsp = info->fixes;
+      ofsp = NULL;
+      while (fsp->next != NULL)
+	{
+	  ofsp = fsp;
+	  fsp = fsp->next;
+	}
+      if (ofsp == NULL)
+	info->fixes = NULL;
+      else
+	ofsp->next = NULL;
+
+      aux = &(fsp->native->u.auxent);
+      fsp->native->fix_end = 1;
+      aux->x_sym.x_fcnary.x_fcn.x_endndx.p = csymp->native;
+      free (fsp);
+
+      info->flags &= ~COFF_FL_FIX_ENDNDX;
+    }
+}
+
+/* Fixup AVR COFF register handling: they don't only mention the
+   starting register number, but all registers, each within one byte
+   of the value.  Unused register positions are filled up with
+   0xff. */
+static symvalue
+coff_fixup_avr_register (val, size)
+     symvalue val;
+     int size;
+{
+  union
+  {
+    unsigned char c[4];
+    symvalue v;
+  } u;
+
+  u.c[1] = u.c[2] = u.c[3] = 0xff;
+  u.c[0] = val;
+  if (size > 8)
+    u.c[1] = val + 1;
+  if (size > 16)
+    {
+      u.c[2] = val + 2;
+      u.c[3] = val + 3;
+    }
+
+  return u.v;
+}
+
+/* Initialize an entry in the hash tables.  */
+
+static struct bfd_hash_entry *
+coff_name_type_newfunc (entry, table, string)
+     struct bfd_hash_entry *entry;
+     struct bfd_hash_table *table;
+     const char *string;
+{
+  struct coff_name_type_hash_entry *ret =
+    (struct coff_name_type_hash_entry *) entry;
+
+  /* Allocate the structure if it has not already been allocated by a
+     subclass.  */
+  if (ret == NULL)
+    ret = ((struct coff_name_type_hash_entry *)
+	   bfd_hash_allocate (table, sizeof *ret));
+  if (ret == NULL)
+    return NULL;
+
+  /* Call the allocation method of the superclass.  */
+  ret = ((struct coff_name_type_hash_entry *)
+	 bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
+  if (ret)
+    {
+      /* Set local fields.  */
+      ret->types = NULL;
+      ret->emitted = FALSE;
+    }
+
+  return (struct bfd_hash_entry *) ret;
+}
+
+static struct bfd_hash_entry *
+coff_struct_newfunc (entry, table, string)
+     struct bfd_hash_entry *entry;
+     struct bfd_hash_table *table;
+     const char *string;
+{
+  struct coff_struct_hash_entry *ret =
+    (struct coff_struct_hash_entry *) entry;
+
+  /* Allocate the structure if it has not already been allocated by a
+     subclass.  */
+  if (ret == NULL)
+    ret = ((struct coff_struct_hash_entry *)
+	   bfd_hash_allocate (table, sizeof *ret));
+  if (ret == NULL)
+    return NULL;
+
+  /* Call the allocation method of the superclass.  */
+  ret = ((struct coff_struct_hash_entry *)
+	 bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
+  if (ret)
+    {
+      /* Set local fields.  */
+      ret->types = NULL;
+      ret->emitted = FALSE;
+      ret->fixidxs = NULL;
+      ret->nfixidxs = 0;
+      ret->native = NULL;
+    }
+
+  return (struct bfd_hash_entry *) ret;
+}
+
+static struct bfd_hash_entry *
+coff_enum_newfunc (entry, table, string)
+     struct bfd_hash_entry *entry;
+     struct bfd_hash_table *table;
+     const char *string;
+{
+  struct coff_enum_hash_entry *ret =
+    (struct coff_enum_hash_entry *) entry;
+
+  /* Allocate the structure if it has not already been allocated by a
+     subclass.  */
+  if (ret == NULL)
+    ret = ((struct coff_enum_hash_entry *)
+	   bfd_hash_allocate (table, sizeof *ret));
+  if (ret == NULL)
+    return NULL;
+
+  /* Call the allocation method of the superclass.  */
+  ret = ((struct coff_enum_hash_entry *)
+	 bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
+  if (ret)
+    {
+      /* Set local fields.  */
+      ret->types = NULL;
+      ret->emitted = FALSE;
+      ret->fixidxs = NULL;
+      ret->nfixidxs = 0;
+      ret->native = NULL;
+    }
+
+  return (struct bfd_hash_entry *) ret;
+}
+
+/* Look up an entry in the hash tables.  */
+
+#define coff_name_type_hash_lookup(table, string, create, copy) \
+  ((struct coff_name_type_hash_entry *) \
+   bfd_hash_lookup (&(table)->root, (string), (create), (copy)))
+
+/* Traverse the hash table.  */
+
+#define coff_name_type_hash_traverse(table, func, info)			\
+  (bfd_hash_traverse							\
+   (&(table)->root,							\
+    (bfd_boolean (*) PARAMS ((struct bfd_hash_entry *, PTR))) (func),	\
+    (info)))
+
+#define coff_struct_hash_lookup(table, string, create, copy) \
+  ((struct coff_struct_hash_entry *) \
+   bfd_hash_lookup (&(table)->root, (string), (create), (copy)))
+
+/* Traverse the hash table.  */
+
+#define coff_struct_hash_traverse(table, func, info)			\
+  (bfd_hash_traverse							\
+   (&(table)->root,							\
+    (bfd_boolean (*) PARAMS ((struct bfd_hash_entry *, PTR))) (func),	\
+    (info)))
+
+#define coff_enum_hash_lookup(table, string, create, copy) \
+  ((struct coff_enum_hash_entry *) \
+   bfd_hash_lookup (&(table)->root, (string), (create), (copy)))
+
+/* Traverse the hash table.  */
+
+#define coff_enum_hash_traverse(table, func, info)			\
+  (bfd_hash_traverse							\
+   (&(table)->root,							\
+    (bfd_boolean (*) PARAMS ((struct bfd_hash_entry *, PTR))) (func),	\
+    (info)))
+
+#define coff_push_type(kind) \
+  tst = (struct coff_type_stack *) xmalloc (sizeof (struct coff_type_stack)); \
+  memset (tst, 0, sizeof (*tst)); \
+  tst->next = info->tstack; \
+  tst->tsk = kind; \
+  info->tstack = tst
+
+#define coff_pop_type() \
+  tst = info->tstack; \
+  if (tst == NULL) { \
+    fprintf (stderr, _("empty type stack in coff_pop_type()\n")); \
+    return FALSE; \
+  } \
+  info->tstack = tst->next; \
+  tst->next = NULL
+
+#define coff_complain_unsupp(s) \
+  fprintf (stderr, _("%s type not supported in %s\n"), \
+	   s, info->abfd->xvec->name); \
+  return FALSE
+
+/* These function is called via the hash traverse routine when freeing
+   a hash table (at the end of a translation unit). */
+static bfd_boolean
+coff_free_type_info (h, p)
+     struct coff_name_type_hash_entry *h;
+     PTR p ATTRIBUTE_UNUSED;
+{
+  struct coff_type_stack *tst, *otst;
+
+  for (tst = h->types; tst != NULL;)
+    {
+      otst = tst;
+      tst = tst->next;
+      free (otst);
+    }
+  return TRUE;
+}
+
+static bfd_boolean
+coff_free_struct_info (h, p)
+     struct coff_struct_hash_entry *h;
+     PTR p ATTRIBUTE_UNUSED;
+{
+  struct coff_type_stack *tst, *otst, *xtst, *xotst;
+  struct coff_struct_fields *fp;
+  long i;
+
+  for (tst = h->types; tst != NULL;)
+    {
+      otst = tst;
+      if (tst->u.ts_struct.tagismalloced)
+	free (tst->u.ts_struct.tag.malloctag);
+      for (i = 0, fp = tst->u.ts_struct.fields;
+	   i < tst->u.ts_struct.nfields;
+	   i++, fp++)
+	{
+	  xtst = fp->types;
+	  while (xtst != NULL)
+	    {
+	      xotst = xtst->next;
+	      free (xtst);
+	      xtst = xotst;
+	    }
+	}
+      free (tst->u.ts_struct.fields);
+      tst = tst->next;
+      free (otst);
+    }
+  return TRUE;
+}
+
+static bfd_boolean
+coff_free_enum_info (h, p)
+     struct coff_enum_hash_entry *h;
+     PTR p ATTRIBUTE_UNUSED;
+{
+  struct coff_type_stack *tst, *otst;
+
+  for (tst = h->types; tst != NULL;)
+    {
+      otst = tst;
+      if (tst->u.ts_enum.tagismalloced)
+	free (tst->u.ts_enum.tag.malloctag);
+      tst = tst->next;
+      free (otst);
+    }
+  return TRUE;
+}
+
+static unsigned int
+coff_get_fundamental_type (info, tst)
+     struct coff_write_handle *info ATTRIBUTE_UNUSED;
+     struct coff_type_stack *tst;
+{
+  size_t i;
+
+  /* See if one of our predefined types will fit. */
+  if (tst->tsk == TS_INT)
+    {
+      for (i = 0;
+	   i < sizeof coff_predef_types / sizeof (struct coff_predef_type);
+	   i++)
+	{
+	  if (coff_predef_types[i].kind == TS_INT
+	      && coff_predef_types[i].size == tst->u.ts_int.size
+	      && coff_predef_types[i].isunsigned == tst->u.ts_int.isunsigned)
+	    return coff_predef_types[i].slot;
+	}
+      fprintf (stderr,
+	       _("%ssigned %d-bit integer type not available in COFF\n"),
+	       tst->u.ts_int.isunsigned? "un": "", tst->u.ts_int.size * 8);
+    }
+  else
+    {
+      for (i = 0;
+	   i < sizeof coff_predef_types / sizeof (struct coff_predef_type);
+	   i++)
+	{
+	  if (coff_predef_types[i].kind == TS_FLOAT
+	      && coff_predef_types[i].size == tst->u.ts_float.size)
+	    return coff_predef_types[i].slot;
+	}
+      fprintf (stderr, _("%d-bit float type not available in COFF\n"),
+	       tst->u.ts_float.size * 8);
+    }
+
+  return T_NULL;
+}
+
+static bfd_boolean
+coff_make_typed_symbol (info, csympp, stopat)
+     struct coff_write_handle *info;
+     coff_symbol_type **csympp;
+     enum ts_kind stopat;
+{
+  struct coff_type_stack *tst;
+  union internal_auxent *aux;
+  struct coff_struct_hash_entry *shash;
+  struct coff_enum_hash_entry *ehash;
+  struct coff_private_symdata *priv;
+  unsigned int type, numaux, arydim, size, i, nele, nderived;
+  const char *name;
+  bfd_boolean oldavrcoff = (info->flags & (COFF_FL_AVR | COFF_FL_EXT_AVR))
+    == COFF_FL_AVR;
+
+  /* Synthesize a new internal COFF symbol. */
+  *csympp = (coff_symbol_type *) coff_bfd_make_debug_symbol (info->abfd, 0, 0);
+  if (*csympp == NULL)
+    return FALSE;
+
+  priv = (struct coff_private_symdata *) xmalloc (sizeof *priv);
+  memset (priv, 0, sizeof *priv);
+
+  type = arydim = size = nderived = 0;
+
+  aux = &(((*csympp)->native + 1)->u.auxent);
+
+  /* Now, walk the type stack, and see how we could convert the info
+     we've got to what COFF understands. */
+  for (;;)
+    {
+      if (info->tstack == NULL)
+	break;
+
+      /* If we have been advised to not pop the entire stack, stop
+	 here. */
+      if (info->tstack->tsk == stopat && info->tstack->next == NULL)
+	break;
+
+      coff_pop_type ();
+
+      switch (tst->tsk)
+	{
+	case TS_NONE:
+	  /* cannot happen */
+	  break;
+
+	case TS_EMPTY:
+	  if (info->tstack != NULL && info->tstack->tsk != stopat)
+	    fprintf (stderr, _("empty type not last on type stack\n"));
+	  /* type |= T_NULL; */
+	  break;
+
+	case TS_VOID:
+	  if (info->tstack != NULL && info->tstack->tsk != stopat)
+	    fprintf (stderr, _("void type not last on type stack\n"));
+	  type |= T_VOID;
+	  break;
+
+	case TS_INT:
+	  if (info->tstack != NULL && info->tstack->tsk != stopat)
+	    fprintf (stderr, _("int type not last on type stack\n"));
+	  type |= coff_get_fundamental_type (info, tst);
+	  if (size == 0)
+	    size = tst->u.ts_int.size;
+	  break;
+
+	case TS_FLOAT:
+	  if (info->tstack != NULL && info->tstack->tsk != stopat)
+	    fprintf (stderr, _("float type not last on type stack\n"));
+	  type |= coff_get_fundamental_type (info, tst);
+	  if (size == 0)
+	    size = tst->u.ts_float.size;
+	  break;
+
+	case TS_POINTER:
+	  nderived++;
+	  type = ((type & ~N_BTMASK) << N_TSHIFT) | (DT_PTR << N_BTSHFT);
+	  size = info->pointersize;
+	  break;
+
+	case TS_FUNC:
+	  nderived++;
+	  type = ((type & ~N_BTMASK) << N_TSHIFT) | (DT_FCN << N_BTSHFT);
+	  /* AUX entry for DT_FCN will be filled in elsewhere. */
+	  break;
+
+	case TS_ARRAY:
+	  /* We need to limit arydim so the assignment below won't
+	     overwrite random locations. */
+	  if (arydim >= DIMNUM)
+	    {
+	      fprintf (stderr,
+		       _("More than %d array dimensions, result is invalid.\n"),
+		       DIMNUM);
+	      arydim = DIMNUM - 1;
+	    }
+	  nderived++;
+	  type = ((type & ~N_BTMASK) << N_TSHIFT) | (DT_ARY << N_BTSHFT);
+	  aux->x_sym.x_fcnary.x_ary.x_dimen[arydim++] =
+	    tst->u.ts_array.high - tst->u.ts_array.low + 1;
+
+	  break;
+
+	case TS_COMPLEX:
+	  coff_complain_unsupp (_("complex"));
+
+	case TS_ENUM:
+	  type |= T_ENUM;
+	  if (size == 0)
+	    size = info->enumsize;
+
+	  if (tst->u.ts_enum.ehash != NULL)
+	    {
+	      /* enum tag will be fixed later. */
+	      priv->ehash = tst->u.ts_enum.ehash;
+	      break;
+	    }
+	  if (tst->u.ts_enum.tagismalloced)
+	    name = tst->u.ts_enum.tag.malloctag;
+	  else
+	    name = tst->u.ts_enum.tag.fixtag;
+	  ehash = coff_enum_hash_lookup (&info->enums, name,
+					 TRUE, tst->u.ts_enum.tagismalloced);
+	  if (ehash == NULL)
+	    return FALSE;
+	  if (!ehash->emitted)
+	    {
+	      if (ehash->types == NULL)
+		{
+		  ehash->types = (struct coff_type_stack *)
+		    xmalloc (sizeof (struct coff_type_stack));
+		  memcpy (ehash->types, tst, sizeof (struct coff_type_stack));
+		}
+	      ehash->emitted = TRUE;
+	      coff_emit_enum (info, tst, ehash);
+	      if (ehash->nfixidxs != 0)
+		{
+		  coff_symbol_type *symp;
+		  unsigned i;
+
+		  for (i = 0; i < ehash->nfixidxs; i++)
+		    {
+		      combined_entry_type *np;
+
+		      symp = (coff_symbol_type *) info->syms[ehash->fixidxs[i]];
+		      symp->native->u.syment.n_type &= ~N_BTMASK;
+		      symp->native->u.syment.n_type |= T_ENUM;
+
+		      if (oldavrcoff)
+			continue;
+
+		      np = symp->native + 1;
+		      np->fix_tag = 1;
+		      np->u.auxent.x_sym.x_tagndx.p = ehash->native;
+		      if (np->u.auxent.x_sym.x_misc.x_fsize == 0)
+			np->u.auxent.x_sym.x_misc.x_lnsz.x_size = size;
+		    }
+
+		  free (ehash->fixidxs);
+		  ehash->nfixidxs = 0;
+		}
+	    }
+	  if (!oldavrcoff)
+	    {
+	      ((*csympp)->native + 1)->fix_tag = 1;
+	      aux->x_sym.x_tagndx.p = ehash->native;
+	      if (aux->x_sym.x_misc.x_fsize == 0)
+		aux->x_sym.x_misc.x_lnsz.x_size = size;
+	    }
+	  break;
+
+	case TS_STRUCT:
+	  if (tst->u.ts_struct.isstruct)
+	    type |= T_STRUCT;
+	  else
+	    type |= T_UNION;
+	  if (size == 0)
+	    size = tst->u.ts_struct.size;
+
+	  if (tst->u.ts_struct.shash != NULL)
+	    {
+	      /* struct tag will be fixed later. */
+	      priv->shash = tst->u.ts_struct.shash;
+	      break;
+	    }
+	  if (tst->u.ts_struct.tagismalloced)
+	    name = tst->u.ts_struct.tag.malloctag;
+	  else
+	    name = tst->u.ts_struct.tag.fixtag;
+	  shash = coff_struct_hash_lookup (&info->structs, name,
+					   TRUE, tst->u.ts_struct.tagismalloced);
+	  if (shash == NULL)
+	    return FALSE;
+	  if (!shash->emitted)
+	    {
+	      if (shash->types == NULL)
+		{
+		  shash->types = (struct coff_type_stack *)
+		    xmalloc (sizeof (struct coff_type_stack));
+		  memcpy (shash->types, tst, sizeof (struct coff_type_stack));
+		}
+	      shash->emitted = TRUE;
+	      coff_emit_struct (info, tst, shash);
+	      if (shash->nfixidxs != 0)
+		{
+		  coff_symbol_type *symp;
+		  unsigned i;
+
+		  for (i = 0; i < shash->nfixidxs; i++)
+		    {
+		      combined_entry_type *np;
+
+		      symp = (coff_symbol_type *) info->syms[shash->fixidxs[i]];
+		      symp->native->u.syment.n_type &= ~N_BTMASK;
+		      if (tst->u.ts_struct.isstruct)
+			symp->native->u.syment.n_type |= T_STRUCT;
+		      else
+			symp->native->u.syment.n_type |= T_UNION;
+
+		      if (oldavrcoff)
+			continue;
+
+		      np = symp->native + 1;
+		      np->fix_tag = 1;
+		      np->u.auxent.x_sym.x_tagndx.p = shash->native;
+		      if (np->u.auxent.x_sym.x_misc.x_fsize == 0)
+			np->u.auxent.x_sym.x_misc.x_lnsz.x_size = size;
+		    }
+
+		  free (shash->fixidxs);
+		  shash->nfixidxs = 0;
+		}
+	    }
+	  if (!oldavrcoff)
+	    {
+	      ((*csympp)->native + 1)->fix_tag = 1;
+	      aux->x_sym.x_tagndx.p = shash->native;
+	      if (aux->x_sym.x_misc.x_fsize == 0)
+		aux->x_sym.x_misc.x_lnsz.x_size = size;
+	    }
+	  break;
+	}
+      free (tst);
+    }
+
+  if (nderived > 6)
+    fprintf (stderr,
+	     _("More than 6 derived type specifiers, result is invalid.\n"));
+
+  /* Our type computation so far used the reverse order for derived
+     type specifiers.  Fix this here if there was more than one
+     derived type specifier. */
+  if (nderived > 1)
+    {
+      unsigned int nty, bty;
+      bty = type & N_BTMASK;
+      type = type >> N_BTSHFT;
+      nty = 0;
+      while (nderived-- > 0)
+	{
+	  nty = (nty << N_TSHIFT) | (type & (N_TMASK >> N_BTSHFT));
+	  type >>= N_TSHIFT;
+	}
+      type = (nty << N_BTSHFT) | bty;
+    }
+
+  if (ISARY (type))
+    {
+      /* Compute size of entire array. */
+      for (i = 0, nele = 1; i < arydim; i++)
+	nele *= aux->x_sym.x_fcnary.x_ary.x_dimen[i];
+      aux->x_sym.x_misc.x_lnsz.x_size = size * nele;
+    }
+
+  numaux = 0;
+  if (ISARY (type) || ISFCN (type))
+    numaux++;
+  if ((BTYPE (type) == T_STRUCT || BTYPE (type) == T_UNION
+       || BTYPE (type) == T_ENUM)
+      && !oldavrcoff)
+    numaux++;
+  /* Only AVR COFF uses multiple AUX entries. */
+  if (numaux > 1 && (info->flags & COFF_FL_AVR) == 0)
+    numaux = 1;
+
+  priv->size = size;
+  (*csympp)->symbol.udata.p = priv;
+  (*csympp)->native->u.syment.n_type = type;
+  (*csympp)->native->u.syment.n_numaux = numaux;
+
+  /* If the fundamental type comes out as T_NULL, this means we don't
+     have any type information.  Just don't emit any aux entries in
+     that case, and drop any derived type information as well. */
+  if (BTYPE (type) == T_NULL)
+    {
+      printf ("coff_make_typed_symbol() -> T_NULL\n");
+      //(*csympp)->native->u.syment.n_type = T_NULL;
+      (*csympp)->native->u.syment.n_numaux = 0;
+    }
+
+  return TRUE;
+}
+
+static bfd_boolean coff_emit_struct (info, tst, shash)
+     struct coff_write_handle *info;
+     struct coff_type_stack *tst;
+     struct coff_struct_hash_entry *shash;
+{
+  coff_symbol_type *csymp, *scsymp, *ecsymp;
+  union internal_auxent *aux;
+  struct coff_fix_stack *fixp, *ofp;
+  bfd_boolean isstruct = tst->u.ts_struct.isstruct;
+  bfd_boolean isbitfield = FALSE;
+  struct coff_type_stack *savedtst;
+  struct coff_struct_fields *fp;
+  unsigned short sclass;
+  long i;
+
+  if ((info->flags & (COFF_FL_AVR | COFF_FL_EXT_AVR)) ==
+      COFF_FL_AVR)
+    /* old AVR COFF doesn't support struct debugging */
+    return TRUE;
+
+  /* Synthesize a new internal COFF symbol for the struct/union. */
+  scsymp = (coff_symbol_type *) coff_bfd_make_debug_symbol (info->abfd, 0, 0);
+  if (scsymp == NULL)
+    return FALSE;
+
+  if (tst->u.ts_struct.tagismalloced)
+    scsymp->symbol.name = xstrdup (tst->u.ts_struct.tag.malloctag);
+  else
+    scsymp->symbol.name = tst->u.ts_struct.tag.fixtag;
+  scsymp->symbol.flags = BSF_NOT_AT_END;
+  scsymp->symbol.section = bfd_und_section_ptr;
+  scsymp->native->u.syment.n_sclass = isstruct? C_STRTAG: C_UNTAG;
+  scsymp->native->u.syment.n_type = isstruct? T_STRUCT: T_UNION;
+  scsymp->native->u.syment.n_numaux = 1;
+  scsymp->symbol.udata.p = NULL;
+  scsymp->symbol.value = 0;
+
+  shash->native = scsymp->native;
+
+  /* Synthesize a new internal COFF symbol for the end of struct/union. */
+  ecsymp = (coff_symbol_type *) coff_bfd_make_debug_symbol (info->abfd, 0, 0);
+  if (ecsymp == NULL)
+    return FALSE;
+
+  ecsymp->symbol.name = ".eos";
+  ecsymp->symbol.flags = BSF_NOT_AT_END;
+  /* We need to use the com section here since bfd/coffgen.c
+     translates this into an N_UNDEF one without clobbering the
+     value. */
+  ecsymp->symbol.section = bfd_com_section_ptr;
+  ecsymp->native->u.syment.n_sclass = C_EOS;
+  ecsymp->symbol.udata.p = NULL;
+  ecsymp->symbol.value = tst->u.ts_struct.size;
+  ecsymp->native->u.syment.n_numaux = 1;
+  (ecsymp->native + 1)->fix_tag = 1;
+  aux = &((ecsymp->native + 1)->u.auxent);
+  aux->x_sym.x_tagndx.p = scsymp->native;
+  aux->x_sym.x_misc.x_lnsz.x_size = tst->u.ts_struct.size;
+
+  coff_record_symbol (info, scsymp);
+
+  savedtst = info->tstack;
+
+  if (isstruct)
+    {
+      /* First, make a quick walk along all the fields, and figure out
+       * whether we've got a genuine struct or a bitfield struct. */
+      for (i = 0, fp = tst->u.ts_struct.fields;
+	   i < tst->u.ts_struct.nfields;
+	   i++, fp++)
+	if (fp->bitsize % 8 != 0)
+	  {
+	    isbitfield = TRUE;
+	    break;
+	  }
+    }
+
+  sclass = isstruct? (isbitfield? C_FIELD: C_MOS): C_MOU;
+
+  for (i = 0, fp = tst->u.ts_struct.fields;
+       i < tst->u.ts_struct.nfields;
+       i++, fp++)
+    {
+      if (strlen (fp->name) == 0)
+	{
+	  /* empty name could happen inside bitfield */
+	  fp->types = NULL;
+	  continue;
+	}
+
+      info->tstack = fp->types;
+      if (!coff_make_typed_symbol (info, &csymp, TS_NONE))
+	return FALSE;
+
+      csymp->symbol.name = xstrdup (fp->name);
+      csymp->symbol.flags = BSF_NOT_AT_END;
+      csymp->symbol.section = bfd_com_section_ptr;
+      csymp->native->u.syment.n_sclass = sclass;
+      csymp->symbol.value = isbitfield? fp->bitpos: fp->bitpos / 8;
+      if (isbitfield)
+	{
+	  csymp->native->u.syment.n_numaux = 1;
+	  aux = &((csymp->native + 1)->u.auxent);
+	  aux->x_sym.x_misc.x_lnsz.x_size = fp->bitsize;
+	}
+
+      coff_record_symbol (info, csymp);
+
+      fp->types = NULL;
+    }
+
+  info->tstack = savedtst;
+
+  /* Record our endndx field for later fixing. */
+  fixp = (struct coff_fix_stack *) xmalloc (sizeof (struct coff_fix_stack));
+  fixp->native = scsymp->native + 1;	/* points to first AUX */
+  fixp->next = NULL;
+  if (info->fixes == NULL)
+    info->fixes = fixp;
+  else
+    {
+      for (ofp = info->fixes; ofp->next != NULL;)
+	ofp = ofp->next;
+      ofp->next = fixp;
+    }
+
+  coff_record_symbol (info, ecsymp);
+  info->flags |= COFF_FL_FIX_ENDNDX;
+
+  return TRUE;
+}
+
+static bfd_boolean coff_emit_enum (info, tst, ehash)
+     struct coff_write_handle *info;
+     struct coff_type_stack *tst;
+     struct coff_enum_hash_entry *ehash;
+{
+  coff_symbol_type *csymp, *scsymp, *ecsymp;
+  union internal_auxent *aux;
+  struct coff_fix_stack *fixp, *ofp;
+  int i;
+
+  if ((info->flags & (COFF_FL_AVR | COFF_FL_EXT_AVR)) ==
+      COFF_FL_AVR)
+    /* old AVR COFF doesn't support enum debugging */
+    return TRUE;
+
+  /* Synthesize a new internal COFF symbol for the enum. */
+  scsymp = (coff_symbol_type *) coff_bfd_make_debug_symbol (info->abfd, 0, 0);
+  if (scsymp == NULL)
+    return FALSE;
+
+  if (tst->u.ts_enum.tagismalloced)
+    scsymp->symbol.name = xstrdup (tst->u.ts_enum.tag.malloctag);
+  else
+    scsymp->symbol.name = tst->u.ts_enum.tag.fixtag;
+  scsymp->symbol.flags = BSF_NOT_AT_END;
+  scsymp->symbol.section = bfd_und_section_ptr;
+  scsymp->native->u.syment.n_sclass = C_ENTAG;
+  scsymp->native->u.syment.n_type = T_ENUM;
+  scsymp->native->u.syment.n_numaux = 1;
+  scsymp->symbol.udata.p = NULL;
+  scsymp->symbol.value = 0;
+
+  ehash->native = scsymp->native;
+
+  /* Synthesize a new internal COFF symbol for the end of struct/union. */
+  ecsymp = (coff_symbol_type *) coff_bfd_make_debug_symbol (info->abfd, 0, 0);
+  if (ecsymp == NULL)
+    return FALSE;
+
+  ecsymp->symbol.name = ".eos";
+  ecsymp->symbol.flags = BSF_NOT_AT_END;
+  /* We need to use the com section here since bfd/coffgen.c
+     translates this into an N_UNDEF one without clobbering the
+     value. */
+  ecsymp->symbol.section = bfd_com_section_ptr;
+  ecsymp->native->u.syment.n_sclass = C_EOS;
+  ecsymp->symbol.udata.p = NULL;
+  ecsymp->symbol.value = info->enumsize;
+  ecsymp->native->u.syment.n_numaux = 1;
+  (ecsymp->native + 1)->fix_tag = 1;
+  aux = &((ecsymp->native + 1)->u.auxent);
+  aux->x_sym.x_tagndx.p = scsymp->native;
+  aux->x_sym.x_misc.x_lnsz.x_size = info->enumsize;
+
+  coff_record_symbol (info, scsymp);
+
+  for (i = 0;; i++)
+    {
+      const char *name = tst->u.ts_enum.names[i];
+      if (name == NULL)
+	break;
+
+      /* Synthesize a new internal COFF symbol for the enum. */
+      csymp = (coff_symbol_type *) coff_bfd_make_debug_symbol (info->abfd, 0, 0);
+      if (csymp == NULL)
+	return FALSE;
+
+      csymp->symbol.name = xstrdup (name);
+      csymp->symbol.flags = BSF_NOT_AT_END;
+      csymp->symbol.section = bfd_com_section_ptr;
+      csymp->native->u.syment.n_sclass = C_MOE;
+      csymp->symbol.udata.p = NULL;
+      csymp->symbol.value = tst->u.ts_enum.vals[i];
+
+      coff_record_symbol (info, csymp);
+    }
+
+  /* Record our endndx field for later fixing. */
+  fixp = (struct coff_fix_stack *) xmalloc (sizeof (struct coff_fix_stack));
+  fixp->native = scsymp->native + 1;	/* points to first AUX */
+  fixp->next = NULL;
+  if (info->fixes == NULL)
+    info->fixes = fixp;
+  else
+    {
+      for (ofp = info->fixes; ofp->next != NULL;)
+	ofp = ofp->next;
+      ofp->next = fixp;
+    }
+
+  coff_record_symbol (info, ecsymp);
+  info->flags |= COFF_FL_FIX_ENDNDX;
+
+  return TRUE;
+}
+
+/* Emit a non-debugging symbol that came from the input symbol table,
+   and has not been claimed by one of the debugging symbols. */
+static bfd_boolean
+coff_emit_ndebug_sym (info, osymp, localp)
+     struct coff_write_handle *info;
+     asymbol *osymp;
+     bfd_boolean localp;
+{
+  coff_symbol_type *csymp;
+
+  /* Create new COFF symbol. */
+  csymp = (coff_symbol_type *) coff_bfd_make_debug_symbol (info->abfd, 0, 0);
+  if (csymp == NULL)
+    return FALSE;
+
+  csymp->symbol.name = xstrdup (osymp->name);
+  csymp->symbol.value = osymp->value;
+  csymp->symbol.flags = localp? BSF_LOCAL: BSF_GLOBAL;
+  csymp->symbol.section = osymp->section;
+  csymp->symbol.udata.p = NULL;
+  csymp->native->u.syment.n_sclass = localp? C_STAT: C_EXT;
+  csymp->native->u.syment.n_type = T_NULL;
+
+  coff_record_symbol (info, csymp);
+
+  return TRUE;
+}
+
+/* The general routine to write out COFF debugging information.  This
+   synthesizes and accumulates the COFF symbols.  Actual symbol table
+   output is performed later on by the BFD functions.  ABFD is the BFD
+   and DHANDLE is the handle for the debugging information.  symcountp
+   and symppp point to the incoming (parsed) symbol list on entry, and
+   will be updated to point to the new symbol table's values upon
+   exit. */
+
+bfd_boolean
+write_coff_debugging_info (abfd, dhandle, symcountp, symppp)
+     bfd *abfd;
+     PTR dhandle;
+     long *symcountp;
+     asymbol ***symppp;
+{
+  struct coff_write_handle info;
+  long i, l;
+  asymbol *symp;
+  struct coff_compilation_unit *up;
+  coff_symbol_type *csymp;
+
+  memset ((void *)&info, 0, sizeof info);
+
+  info.abfd = abfd;
+
+  info.pointersize = info.enumsize = 4;
+
+  switch (bfd_get_arch (abfd))
+    {
+    case bfd_arch_avr:
+      info.flags |= COFF_FL_AVR;
+      if (strcmp (abfd->xvec->name, "coff-ext-avr") == 0)
+	info.flags |= COFF_FL_EXT_AVR;
+      /* Fix the builtin type sizes. */
+      coff_predef_types[0].size = 2;	/* sizeof(int) == 2 */
+      coff_predef_types[4].size = 4;	/* sizeof(double) == 4 */
+      coff_predef_types[6].size = 2;	/* sizeof(unsigned int) == 2 */
+      info.pointersize = info.enumsize = 2;
+      break;
+
+    default:
+      ;
+    }
+
+  coff_copy_symbols(&info, *symcountp, *symppp);
+
+  if (info.textsect == NULL)
+    {
+      fprintf (stderr, _("Warning: no \"text\" section found in output file\n"));
+      info.textsect = bfd_abs_section_ptr;
+    }
+  if (info.datasect == NULL)
+    {
+      fprintf (stderr, _("Warning: no \"data\" section found in output file\n"));
+      info.datasect = bfd_abs_section_ptr;
+    }
+
+  if (! bfd_hash_table_init (&info.types.root, coff_name_type_newfunc,
+			     sizeof(struct coff_name_type_hash_entry)))
+    return FALSE;
+
+  if (! bfd_hash_table_init (&info.structs.root, coff_struct_newfunc,
+			     sizeof(struct coff_struct_hash_entry)))
+    return FALSE;
+
+  if (! bfd_hash_table_init (&info.enums.root, coff_enum_newfunc,
+			     sizeof(struct coff_enum_hash_entry)))
+    return FALSE;
+
+  if (! debug_write (dhandle, &coff_fns, (PTR) &info))
+    return FALSE;
+
+  /* If there is an old compilation unit that has got any local
+     non-debugging symbols left over, send them out now. */
+  if (info.currentfile != NULL && info.currentfile->totsyms != 0)
+    for (i = 0; i < info.currentfile->nsyms; i++)
+      {
+	up = info.currentfile;
+
+	if (up->syms[i] != NULL)
+	  {
+	    coff_emit_ndebug_sym (&info, up->syms[i], TRUE);
+	    up->syms[i] = NULL;
+	    up->totsyms--;
+	  }
+      }
+
+  /* See whether there are any non-debugging symbols left from the
+     input symbol table.  First look at all local symbols which must
+     be from entire compilation units we didn't see yet in the
+     debugging information, because anything else has already been
+     handled at the end of each compilation unit (like in the loop
+     immediately above).  Any compilation unit that has already been
+     processed that way is supposed to have its "totsyms" counted down
+     to 0 now, so we can skip them.
+
+     Finally, put out all remaining global non-debugging symbols. */
+  for (l = 0; l < info.nunits; l++)
+    {
+      const char *bn;
+
+      up = info.units + l;
+      if (up->totsyms == 0)
+	continue;
+
+      /* Create COFF symbol for this compilation unit. */
+      csymp = (coff_symbol_type *) coff_bfd_make_debug_symbol (info.abfd, 0, 0);
+      if (csymp == NULL)
+	return FALSE;
+
+      bn = bu_basename (up->fname);
+
+      if (bfd_coff_long_filenames (info.abfd))
+	csymp->symbol.name = up->fname;
+      else
+	csymp->symbol.name = bn;
+
+      csymp->symbol.value = 0;
+      csymp->symbol.udata.p = NULL;
+      csymp->native->u.syment.n_sclass = C_FILE;
+      csymp->native->u.syment.n_numaux = 1; /* force filename into aux entry */
+      coff_record_symbol (&info, csymp);
+
+      for (i = 0; i < up->nsyms; i++)
+	{
+	  symp = up->syms[i];
+	  if (symp == NULL)
+	    continue;
+
+	  coff_emit_ndebug_sym (&info, symp, TRUE);
+	}
+    }
+
+  for (i = 0; i < info.nglobals; i++)
+    {
+      symp = info.globals[i];
+      if (symp == NULL)
+	continue;
+
+      coff_emit_ndebug_sym (&info, symp, FALSE);
+    }
+
+  /* Fixup the AUX entries for the section symbols we have emitted
+     earlier (so they are guaranteed to be at the beginning of the
+     symbol table).  In particular, the line number count (which we
+     only have for the text section) is known right now. */
+  for (i = 0; i < info.nsecsyms; i++)
+    {
+      union internal_auxent *aux;
+
+      csymp = info.secsyms[i];
+
+      aux = &((csymp->native + 1)->u.auxent);
+      aux->x_scn.x_scnlen = csymp->symbol.section->output_section->rawsize;
+      aux->x_scn.x_nreloc = csymp->symbol.section->reloc_count;
+      if (csymp->symbol.section == info.textsect)
+	aux->x_scn.x_nlinno = info.totlnos;
+    }
+  free (info.secsyms);
+
+  coff_name_type_hash_traverse (&info.types, coff_free_type_info, NULL);
+  bfd_hash_table_free (&info.types.root);
+
+  coff_struct_hash_traverse (&info.structs, coff_free_struct_info, NULL);
+  bfd_hash_table_free (&info.structs.root);
+
+  coff_enum_hash_traverse (&info.enums, coff_free_enum_info, NULL);
+  bfd_hash_table_free (&info.enums.root);
+
+  /* FIXME: free all the other stuff remembered in "info". */
+
+  free (*symppp);
+
+  *symcountp = info.nsyms;
+  *symppp = (asymbol **)info.syms;
+
+  return TRUE;
+}
+
+/* Start writing out information for a compilation unit.  */
+
+static bfd_boolean
+coff_start_compilation_unit (p, filename)
+     PTR p;
+     const char *filename;
+{
+  struct coff_write_handle *info = (struct coff_write_handle *) p;
+  long i;
+  const char *bn;
+  bfd_boolean found;
+  coff_symbol_type *csymp;
+
+#if COFF_DEBUG
+  printf ("coff_start_compilation_unit(%s)\n", filename);
+#endif
+
+  /* If there is an old compilation unit that has got any local
+     non-debugging symbols left over, send them out now. */
+  if (info->currentfile != NULL && info->currentfile->totsyms != 0)
+    for (i = 0; i < info->currentfile->nsyms; i++)
+      {
+	struct coff_compilation_unit *up = info->currentfile;
+
+	if (up->syms[i] != NULL)
+	  {
+	    coff_emit_ndebug_sym (info, up->syms[i], TRUE);
+	    up->syms[i] = NULL;
+	    up->totsyms--;
+	  }
+      }
+
+  /* symtab (and thus COFF debugging) symbols can only transfer the
+     basename of the file, so strip the dirname */
+  bn = bu_basename (filename);
+
+  for (i = 0, found = FALSE; i < info->nunits; i++)
+    {
+      if (strcmp (info->units[i].fname, bn) == 0)
+	{
+	  info->currentfile = info->units + i;
+	  found = TRUE;
+	  break;
+	}
+    }
+  if (!found)
+    {
+      fprintf(stderr,
+	      _("Warning: file %s not found in symbol table, ignoring\n"),
+	      filename);
+      info->currentfile = NULL;
+      return TRUE;
+    }
+
+  /* Synthesize a new internal COFF symbol. */
+  csymp = (coff_symbol_type *) coff_bfd_make_debug_symbol (info->abfd, 0, 0);
+  if (csymp == NULL)
+    return FALSE;
+
+  /* Note that coff_fix_symbol_name() [coffgen.c] will fix this for
+     us: the symbol name will be replaced by ".file", and the filename
+     will be moved to the aux entries.  We use the long name obtained
+     from the debugging information (that includes the full path) if
+     our COFF format supports long filenames, otherwise we only use
+     the basename of the file. */
+  if (bfd_coff_long_filenames (info->abfd))
+    csymp->symbol.name = filename;
+  else
+    csymp->symbol.name = bn;
+  csymp->symbol.value = 0;
+  csymp->symbol.udata.p = NULL;
+  csymp->native->u.syment.n_sclass = C_FILE;
+  csymp->native->u.syment.n_numaux = 1;	/* force filename into aux entry */
+  coff_record_symbol (info, csymp);
+
+  return TRUE;
+}
+
+/* Start writing out information for a particular source file.  */
+
+static bfd_boolean
+coff_start_source (p, filename)
+     PTR p ATTRIBUTE_UNUSED;
+     const char *filename ATTRIBUTE_UNUSED;
+{
+
+#if COFF_DEBUG
+  printf ("coff_start_source(%s)\n", filename);
+#endif
+
+  /* COFF cannot handle include filenames. */
+
+  return TRUE;
+}
+
+/* Push an empty type.  This shouldn't normally happen.  */
+
+static bfd_boolean
+coff_empty_type (p)
+     PTR p;
+{
+  struct coff_write_handle *info = (struct coff_write_handle *) p;
+  struct coff_type_stack *tst;
+
+#if COFF_DEBUG
+  printf ("coff_empty_type()\n");
+#endif
+
+  coff_push_type (TS_EMPTY);
+
+  return TRUE;
+}
+
+/* Push a void type.  */
+
+static bfd_boolean
+coff_void_type (p)
+     PTR p;
+{
+  struct coff_write_handle *info = (struct coff_write_handle *) p;
+  struct coff_type_stack *tst;
+
+#if COFF_DEBUG
+  printf ("coff_void_type()\n");
+#endif
+
+  coff_push_type (TS_VOID);
+
+  return TRUE;
+}
+
+/* Push an integer type.  */
+
+static bfd_boolean
+coff_int_type (p, size, unsignedp)
+     PTR p;
+     unsigned int size;
+     bfd_boolean unsignedp;
+{
+  struct coff_write_handle *info = (struct coff_write_handle *) p;
+  struct coff_type_stack *tst;
+
+#if COFF_DEBUG
+  printf ("coff_int_type(%d, %d)\n", size, unsignedp);
+#endif
+
+  coff_push_type (TS_INT);
+  tst->u.ts_int.size = size;
+  tst->u.ts_int.isunsigned = unsignedp;
+
+  return TRUE;
+}
+
+/* Push a floating point type.  */
+
+static bfd_boolean
+coff_float_type (p, size)
+     PTR p;
+     unsigned int size;
+{
+  struct coff_write_handle *info = (struct coff_write_handle *) p;
+  struct coff_type_stack *tst;
+
+#if COFF_DEBUG
+  printf ("coff_float_type(%d)\n", size);
+#endif
+
+  coff_push_type (TS_FLOAT);
+  tst->u.ts_float.size = size;
+
+  return TRUE;
+}
+
+/* Push a complex type.  */
+
+static bfd_boolean
+coff_complex_type (p, size)
+     PTR p;
+     unsigned int size ATTRIBUTE_UNUSED;
+{
+  struct coff_write_handle *info = (struct coff_write_handle *) p;
+  struct coff_type_stack *tst;
+
+#if COFF_DEBUG
+  printf ("coff_complex_type(%d)\n", size);
+#endif
+
+  coff_push_type (TS_COMPLEX);
+
+  return TRUE;
+}
+
+/* Push a bfd_boolean type. */
+
+static bfd_boolean
+coff_bool_type (p, size)
+     PTR p;
+     unsigned int size;
+{
+  struct coff_write_handle *info = (struct coff_write_handle *) p;
+  struct coff_type_stack *tst;
+
+#if COFF_DEBUG
+  printf ("coff_bool_type(%d)\n", size);
+#endif
+
+  coff_push_type (TS_INT);
+  tst->u.ts_int.size = size;
+  tst->u.ts_int.isunsigned = TRUE;
+
+  return TRUE;
+}
+
+/* Push an enum type.  */
+
+static bfd_boolean
+coff_enum_type (p, tag, names, vals)
+     PTR p;
+     const char *tag;
+     const char **names;
+     bfd_signed_vma *vals;
+{
+  struct coff_write_handle *info = (struct coff_write_handle *) p;
+  struct coff_type_stack *tst;
+  char buf[20];
+
+#if COFF_DEBUG
+  int idx;
+  printf ("coff_enum_type(%s [", tag);
+  for (idx = 0; names[idx] != NULL; idx++)
+    printf ("%s -> %d, ", names[idx], (int)vals[idx]);
+  printf ("])\n");
+#endif
+
+  coff_push_type (TS_ENUM);
+
+  if (tag == NULL)
+    {
+      sprintf(buf, ".%dfake", info->nenums++);
+      tst->u.ts_enum.tag.malloctag = xstrdup (buf);
+      tst->u.ts_enum.tagismalloced = TRUE;
+    }
+  else
+    tst->u.ts_enum.tag.fixtag = tag;
+  tst->u.ts_enum.names = names;
+  tst->u.ts_enum.vals = vals;
+
+  return TRUE;
+}
+
+/* Push a pointer type.  */
+
+static bfd_boolean
+coff_pointer_type (p)
+     PTR p;
+{
+  struct coff_write_handle *info = (struct coff_write_handle *) p;
+  struct coff_type_stack *tst;
+
+#if COFF_DEBUG
+  printf ("coff_pointer_type()\n");
+#endif
+
+  coff_push_type (TS_POINTER);
+
+  return TRUE;
+}
+
+/* Push a function type.  */
+
+static bfd_boolean
+coff_function_type (p, argcount, varargs)
+     PTR p;
+     int argcount;
+     bfd_boolean varargs ATTRIBUTE_UNUSED;
+{
+  struct coff_write_handle *info = (struct coff_write_handle *) p;
+  struct coff_type_stack *tst;
+
+#if COFF_DEBUG
+  printf ("coff_function_type(%d, %d)\n", argcount, varargs);
+#endif
+
+  coff_push_type (TS_FUNC);
+
+  /* FIXME should properly discard function arguments */
+  if (argcount > -1)
+    {
+      fprintf (stderr,
+	       _("coff_function_type() called with positive argcount\n"));
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+/* Push a reference type.  */
+
+static bfd_boolean
+coff_reference_type (p)
+     PTR p;
+{
+  struct coff_write_handle *info = (struct coff_write_handle *) p;
+
+#if COFF_DEBUG
+  printf ("coff_reference_type()\n");
+#endif
+
+  coff_complain_unsupp (_("reference"));
+
+  return TRUE;
+}
+
+/* Push a range type.  */
+
+static bfd_boolean
+coff_range_type (p, low, high)
+     PTR p;
+     bfd_signed_vma low ATTRIBUTE_UNUSED;
+     bfd_signed_vma high ATTRIBUTE_UNUSED;
+{
+  struct coff_write_handle *info = (struct coff_write_handle *) p;
+
+#if COFF_DEBUG
+  printf ("coff_range_type([%d..%d)\n", (int)low, (int)high);
+#endif
+
+  coff_complain_unsupp (_("range"));
+
+  return TRUE;
+}
+
+/* Push an array type.  */
+
+static bfd_boolean
+coff_array_type (p, low, high, stringp)
+     PTR p;
+     bfd_signed_vma low;
+     bfd_signed_vma high;
+     bfd_boolean stringp;
+{
+  struct coff_write_handle *info = (struct coff_write_handle *) p;
+  struct coff_type_stack *tst;
+
+#if COFF_DEBUG
+  printf ("coff_array_type([%d..%d], %d)\n",
+	  (int)low, (int)high, stringp);
+#endif
+
+  /* Pop the range type, but ignore it.  COFF doesn't use it. */
+  coff_pop_type ();
+
+  /* FIXME  What to do here? */
+  if (stringp)
+    {
+      fprintf(stderr, _("coff_array_type(): stringp == TRUE\n"));
+      return FALSE;
+    }
+
+  coff_push_type (TS_ARRAY);
+  tst->u.ts_array.low = low;
+  tst->u.ts_array.high = high;
+
+  return TRUE;
+}
+
+/* Push a set type.  */
+
+static bfd_boolean
+coff_set_type (p, bitstringp)
+     PTR p;
+     bfd_boolean bitstringp ATTRIBUTE_UNUSED;
+{
+  struct coff_write_handle *info = (struct coff_write_handle *) p;
+
+#if COFF_DEBUG
+  printf ("coff_set_type(%d)\n", bitstringp);
+#endif
+
+  coff_complain_unsupp (_("set"));
+
+  return TRUE;
+}
+
+/* Push an offset type.  */
+
+static bfd_boolean
+coff_offset_type (p)
+     PTR p;
+{
+  struct coff_write_handle *info = (struct coff_write_handle *) p;
+
+#if COFF_DEBUG
+  printf ("coff_offset_type()\n");
+#endif
+
+  coff_complain_unsupp (_("offset"));
+
+  return TRUE;
+}
+
+/* Push a method type.  */
+
+static bfd_boolean
+coff_method_type (p, domainp, argcount, varargs)
+     PTR p;
+     bfd_boolean domainp ATTRIBUTE_UNUSED;
+     int argcount ATTRIBUTE_UNUSED;
+     bfd_boolean varargs ATTRIBUTE_UNUSED;
+{
+  struct coff_write_handle *info = (struct coff_write_handle *) p;
+
+#if COFF_DEBUG
+  printf ("coff_method_type(%d, %d, %d)\n",
+	  domainp, argcount, varargs);
+#endif
+
+  coff_complain_unsupp (_("method"));
+
+  return TRUE;
+}
+
+/* Push a const version of a type.  */
+
+static bfd_boolean
+coff_const_type (p)
+     PTR p ATTRIBUTE_UNUSED;
+{
+
+#if COFF_DEBUG
+  printf ("coff_const_type()\n");
+#endif
+
+  /* const modifier is ignored by COFF */
+
+  return TRUE;
+}
+
+/* Push a volatile version of a type.  */
+
+static bfd_boolean
+coff_volatile_type (p)
+     PTR p ATTRIBUTE_UNUSED;
+{
+
+#if COFF_DEBUG
+  printf ("coff_volatile_type()\n");
+#endif
+
+  /* volatile modifier is ignored by COFF */
+
+  return TRUE;
+}
+
+/* Start outputting a struct.  */
+
+static bfd_boolean
+coff_start_struct_type (p, tag, id, structp, size)
+     PTR p;
+     const char *tag;
+     unsigned int id;
+     bfd_boolean structp;
+     unsigned int size;
+{
+  struct coff_write_handle *info = (struct coff_write_handle *) p;
+  struct coff_type_stack *tst, *savedts;
+  struct coff_struct_hash_entry *shash;
+  char buf[20];
+  const char *name;
+
+#if COFF_DEBUG
+  printf ("coff_start_struct_type(%s, %d, %d, %d)\n",
+	  tag, id, structp, size);
+#endif
+
+  savedts = info->tstack;
+  info->tstack = NULL;
+
+  coff_push_type (TS_STRUCT);
+
+  if (tag == NULL)
+    {
+      sprintf(buf, ".%dfake", id);
+      name = tst->u.ts_struct.tag.malloctag = xstrdup (buf);
+      tst->u.ts_struct.tagismalloced = TRUE;
+    }
+  else
+    name = tst->u.ts_struct.tag.fixtag = tag;
+  tst->u.ts_struct.id = id;
+  tst->u.ts_struct.isstruct = structp;
+  tst->u.ts_struct.size = size;
+  tst->u.ts_struct.savedts = savedts;
+
+  shash = coff_struct_hash_lookup (&info->structs, name, FALSE, FALSE);
+  if (shash != NULL && shash->types != NULL)
+    {
+#if COFF_DEBUG
+      printf ("new %s definition for %s\n",
+	      tst->u.ts_struct.isstruct? "struct": "union", name);
+#endif
+      coff_free_struct_info (shash, NULL);
+      shash->types = NULL;
+      shash->emitted = FALSE;
+    }
+  else
+    (void)coff_struct_hash_lookup (&info->structs, name,
+			     TRUE, tst->u.ts_struct.tagismalloced);
+
+  return TRUE;
+}
+
+/* Add a field to a struct.  */
+
+static bfd_boolean
+coff_struct_field (p, name, bitpos, bitsize, visibility)
+     PTR p;
+     const char *name;
+     bfd_vma bitpos;
+     bfd_vma bitsize;
+     enum debug_visibility visibility;
+{
+  struct coff_write_handle *info = (struct coff_write_handle *) p;
+  struct coff_type_stack *tst, *otst;
+  struct coff_struct_fields *fp;
+  struct coff_struct_hash_entry *shash;
+  struct coff_enum_hash_entry *ehash;
+  const char *tag;
+
+#if COFF_DEBUG
+  printf ("coff_struct_field(%s, %d, %d, %d)\n",
+	  name, (int)bitpos, (int)bitsize, (int)visibility);
+#endif
+
+  /* Find the last element on the type stack. */
+  assert (info->tstack != NULL);
+  for (tst = info->tstack, otst = NULL; tst->next != NULL;)
+    {
+      otst = tst;
+      tst = tst->next;
+    }
+  if (otst != NULL)
+    otst->next = NULL;
+
+  if (tst->tsk != TS_STRUCT)
+    {
+      fprintf (stderr, "coff_struct_field() not within structure definition\n");
+      return FALSE;
+    }
+  tst->u.ts_struct.fields = (struct coff_struct_fields *)
+    xrealloc (tst->u.ts_struct.fields,
+	      ++tst->u.ts_struct.nfields * sizeof (struct coff_struct_fields));
+  fp = tst->u.ts_struct.fields + (tst->u.ts_struct.nfields - 1);
+  fp->name = name;
+  fp->bitpos = bitpos;
+  fp->bitsize = bitsize;
+  fp->visibility = visibility;
+  otst = fp->types = info->tstack;
+  while (otst->next != NULL)
+    otst = otst->next;
+  if (otst->tsk == TS_STRUCT && otst->u.ts_struct.shash == NULL)
+    {
+      if (otst->u.ts_struct.tagismalloced)
+	tag = otst->u.ts_struct.tag.malloctag;
+      else
+	tag = otst->u.ts_struct.tag.fixtag;
+      shash = coff_struct_hash_lookup (&info->structs, tag, FALSE, FALSE);
+      assert (shash != NULL);
+      if (!shash->emitted)
+	{
+	  if (shash->types == NULL)
+	    {
+	      shash->types = (struct coff_type_stack *)
+		xmalloc (sizeof (struct coff_type_stack));
+	      memcpy (shash->types, otst, sizeof (struct coff_type_stack));
+	    }
+	  shash->emitted = TRUE;
+	  coff_emit_struct (info, otst, shash);
+	}
+    }
+  else if (otst->tsk == TS_ENUM)
+    {
+      if (otst->u.ts_enum.tagismalloced)
+	tag = otst->u.ts_enum.tag.malloctag;
+      else
+	tag = otst->u.ts_enum.tag.fixtag;
+      ehash = coff_enum_hash_lookup (&info->enums, tag, TRUE, FALSE);
+      assert (ehash != NULL);
+      if (!ehash->emitted)
+	{
+	  if (ehash->types == NULL)
+	    {
+	      ehash->types = (struct coff_type_stack *)
+		xmalloc (sizeof (struct coff_type_stack));
+	      memcpy (ehash->types, otst, sizeof (struct coff_type_stack));
+	    }
+	  ehash->emitted = TRUE;
+	  coff_emit_enum (info, otst, ehash);
+	}
+    }
+
+  info->tstack = tst;
+
+  return TRUE;
+}
+
+/* Finish up a struct.  */
+
+static bfd_boolean
+coff_end_struct_type (p)
+     PTR p;
+{
+  struct coff_write_handle *info = (struct coff_write_handle *) p;
+  struct coff_type_stack *tst, *savedts;
+
+#if COFF_DEBUG
+  printf ("coff_end_struct_type()\n");
+#endif
+
+  /* Our struct definition should be the only type stack element by
+     now. */
+  assert (info->tstack != NULL);
+  tst = info->tstack;
+  if (tst->tsk != TS_STRUCT || tst->next != NULL)
+    {
+      fprintf (stderr, "coff_struct_field() not within structure definition\n");
+      return FALSE;
+    }
+
+  /* Restore saved type stack, and push our now complete struct
+     definition on top. */
+  savedts = tst->u.ts_struct.savedts;
+  tst->u.ts_struct.savedts = info->tstack;
+  info->tstack = savedts;
+  tst->next = info->tstack;
+  info->tstack = tst;
+
+  return TRUE;
+}
+
+/* Start outputting a class.  */
+
+static bfd_boolean
+coff_start_class_type (p, tag, id, structp, size, vptr, ownvptr)
+     PTR p;
+     const char *tag ATTRIBUTE_UNUSED;
+     unsigned int id ATTRIBUTE_UNUSED;
+     bfd_boolean structp ATTRIBUTE_UNUSED;
+     unsigned int size ATTRIBUTE_UNUSED;
+     bfd_boolean vptr ATTRIBUTE_UNUSED;
+     bfd_boolean ownvptr ATTRIBUTE_UNUSED;
+{
+  struct coff_write_handle *info = (struct coff_write_handle *) p;
+
+#if COFF_DEBUG
+  printf ("coff_start_class_type(%s, %d, %d, %d, %d, %d)\n",
+	  tag, id, structp, size, vptr, ownvptr);
+#endif
+
+  coff_complain_unsupp (_("class"));
+
+  return TRUE;
+}
+
+/* Add a static member to the class on the type stack.  */
+
+static bfd_boolean
+coff_class_static_member (p, name, physname, visibility)
+     PTR p ATTRIBUTE_UNUSED;
+     const char *name ATTRIBUTE_UNUSED;
+     const char *physname ATTRIBUTE_UNUSED;
+     enum debug_visibility visibility ATTRIBUTE_UNUSED;
+{
+
+#if COFF_DEBUG
+  printf ("coff_class_static_member(%s, %s, %d)\n",
+	  name, physname, (int)visibility);
+#endif
+
+  return TRUE;
+}
+
+/* Add a base class to the class on the type stack.  */
+
+static bfd_boolean
+coff_class_baseclass (p, bitpos, virtual, visibility)
+     PTR p ATTRIBUTE_UNUSED;
+     bfd_vma bitpos ATTRIBUTE_UNUSED;
+     bfd_boolean virtual ATTRIBUTE_UNUSED;
+     enum debug_visibility visibility ATTRIBUTE_UNUSED;
+{
+
+#if COFF_DEBUG
+  printf ("coff_class_baseclass(%d, %d, %d)\n",
+	  (int)bitpos, virtual, (int)visibility);
+#endif
+
+  return TRUE;
+}
+
+/* Start adding a method to the class on the type stack.  */
+
+static bfd_boolean
+coff_class_start_method (p, name)
+     PTR p ATTRIBUTE_UNUSED;
+     const char *name ATTRIBUTE_UNUSED;
+{
+
+#if COFF_DEBUG
+  printf ("coff_class_start_method(%s)\n", name);
+#endif
+
+  return TRUE;
+}
+
+/* Add a variant to the current method.  */
+
+static bfd_boolean
+coff_class_method_variant (p, physname, visibility, constp, volatilep,
+			   voffset, contextp)
+     PTR p ATTRIBUTE_UNUSED;
+     const char *physname ATTRIBUTE_UNUSED;
+     enum debug_visibility visibility ATTRIBUTE_UNUSED;
+     bfd_boolean constp ATTRIBUTE_UNUSED;
+     bfd_boolean volatilep ATTRIBUTE_UNUSED;
+     bfd_vma voffset ATTRIBUTE_UNUSED;
+     bfd_boolean contextp ATTRIBUTE_UNUSED;
+{
+
+#if COFF_DEBUG
+  printf ("coff_class_method_variant(%s, %d, %d, %d, %d, %d)\n",
+	  physname, (int)visibility, constp, volatilep,
+	  (int)voffset, contextp);
+#endif
+
+  return TRUE;
+}
+
+/* Add a static variant to the current method.  */
+
+static bfd_boolean
+coff_class_static_method_variant (p, physname, visibility, constp, volatilep)
+     PTR p ATTRIBUTE_UNUSED;
+     const char *physname ATTRIBUTE_UNUSED;
+     enum debug_visibility visibility ATTRIBUTE_UNUSED;
+     bfd_boolean constp ATTRIBUTE_UNUSED;
+     bfd_boolean volatilep ATTRIBUTE_UNUSED;
+{
+
+#if COFF_DEBUG
+  printf ("coff_class_static_method_variant(%s, %d, %d, %d)\n",
+	  physname, (int)visibility, constp, volatilep);
+#endif
+
+  return TRUE;
+}
+
+/* Finish up a method.  */
+
+static bfd_boolean
+coff_class_end_method (p)
+     PTR p ATTRIBUTE_UNUSED;
+{
+
+#if COFF_DEBUG
+  printf ("coff_class_end_method()\n");
+#endif
+
+  return TRUE;
+}
+
+/* Finish up a class.  */
+
+static bfd_boolean
+coff_end_class_type (p)
+     PTR p ATTRIBUTE_UNUSED;
+{
+
+#if COFF_DEBUG
+  printf ("coff_end_class_type()\n");
+#endif
+
+  return TRUE;
+}
+
+/* Push a typedef which was previously defined.  */
+
+static bfd_boolean
+coff_typedef_type (p, name)
+     PTR p;
+     const char *name;
+{
+  struct coff_write_handle *info = (struct coff_write_handle *) p;
+  struct coff_name_type_hash_entry *nthash;
+  struct coff_type_stack *tst, *newchain, *newst, *temp;
+
+#if COFF_DEBUG
+  printf ("coff_typedef_type(%s)\n", name);
+#endif
+
+  nthash = coff_name_type_hash_lookup (&info->types, name, FALSE, FALSE);
+
+  /* nthash should never be NULL, since that would imply that the
+     generic debugging code has asked for a typedef which it has not
+     yet defined.  */
+  assert (nthash != NULL);
+
+  /* Just push the entire type stack snapshot we've got on top of the
+     existing typestack.  See coff_typdef() below for how this
+     works.  We need to copy over each element however, since anybody
+     popping elements off the typestack is supposed to free() each of
+     them. */
+
+  for (tst = nthash->types, temp = newst = newchain = NULL; tst != NULL;)
+    {
+      temp = newst;
+      newst = (struct coff_type_stack *) xmalloc (sizeof (*newst));
+      if (newchain == NULL)
+	newchain = newst;
+      memcpy (newst, tst, sizeof (*newst));
+      if (temp != NULL)
+	temp->next = newst;
+
+      tst = tst->next;
+    }
+  newst->next = info->tstack;
+  info->tstack = newchain;
+
+  return TRUE;
+}
+
+/* Push a struct, union or class tag.  */
+
+static bfd_boolean
+coff_tag_type (p, name, id, kind)
+     PTR p;
+     const char *name;
+     unsigned int id ATTRIBUTE_UNUSED;
+     enum debug_type_kind kind;
+{
+  struct coff_write_handle *info = (struct coff_write_handle *) p;
+  struct coff_type_stack *tst, *newchain, *newst, *temp;
+  struct coff_struct_hash_entry *shash;
+  struct coff_enum_hash_entry *ehash;
+  char buf[20];
+  bfd_boolean needcopy = FALSE;
+  bfd_boolean isstruct = TRUE;
+
+#if COFF_DEBUG
+  printf ("coff_tag_type(%s, %d, %d)\n",
+	  name, id, kind);
+#endif
+
+  if (name == NULL)
+    {
+      sprintf(buf, ".%dfake", id);
+      needcopy = TRUE;
+    }
+
+  switch (kind)
+    {
+    case DEBUG_KIND_UNION:
+    case DEBUG_KIND_UNION_CLASS:
+      isstruct = FALSE;
+      /* FALLTHROUGH */
+    case DEBUG_KIND_STRUCT:
+    case DEBUG_KIND_CLASS:
+      shash = coff_struct_hash_lookup (&info->structs,
+				       name == NULL? buf: name, TRUE, needcopy);
+      assert (shash != NULL);
+      tst = shash->types;
+      if (tst == NULL)
+	{
+	  /* This is a reference to a tag that has not yet been
+	     defined (i. e., a forward reference).  Synthesize a
+	     ts_struct entry by now, and mark it for later fixup. */
+	  tst = (struct coff_type_stack *) xmalloc (sizeof *tst);
+	  memset (tst, 0, sizeof *tst);
+	  tst->tsk = TS_STRUCT;
+	  tst->u.ts_struct.isstruct = isstruct;
+	  tst->u.ts_struct.shash = shash;
+	}
+    docopystack:
+      /* Just push the entire type stack snapshot we've got on top of the
+	 existing typestack.  See coff_typdef() below for how this
+	 works.  We need to copy over each element however, since anybody
+	 popping elements off the typestack is supposed to free() each of
+	 them. */
+      for (temp = newst = newchain = NULL; tst != NULL;)
+	{
+	  temp = newst;
+	  newst = (struct coff_type_stack *) xmalloc (sizeof (*newst));
+	  if (newchain == NULL)
+	    newchain = newst;
+	  memcpy (newst, tst, sizeof (*newst));
+	  if (temp != NULL)
+	    temp->next = newst;
+
+	  tst = tst->next;
+	}
+      if (newst)
+	{
+	  newst->next = info->tstack;
+	  info->tstack = newchain;
+	}
+      break;
+
+    case DEBUG_KIND_ENUM:
+      ehash = coff_enum_hash_lookup (&info->enums,
+				     name == NULL? buf: name, TRUE, needcopy);
+      assert (ehash != NULL);
+      tst = ehash->types;
+      if (tst == NULL)
+	{
+	  /* This is a reference to a tag that has not yet been
+	     defined (i. e., a forward reference).  Synthesize a
+	     ts_enum entry by now, and mark it for later fixup. */
+	  tst = (struct coff_type_stack *) xmalloc (sizeof *tst);
+	  memset (tst, 0, sizeof *tst);
+	  tst->tsk = TS_ENUM;
+	  tst->u.ts_enum.ehash = ehash;
+	}
+      goto docopystack;
+
+    default:
+      fprintf (stderr, _("illegal kind %d in coff_tag_type()\n"),
+	       (int)kind);
+      return FALSE;
+    }
+  return TRUE;
+}
+
+/* Define a typedef.  */
+
+static bfd_boolean
+coff_typdef (p, name)
+     PTR p;
+     const char *name;
+{
+  struct coff_write_handle *info = (struct coff_write_handle *) p;
+  struct coff_name_type_hash_entry *nthash;
+
+#if COFF_DEBUG
+  printf ("coff_typdef(%s)\n", name);
+#endif
+
+  /* COFF cannot really handle typedefs.  While there is the option to
+     mark a symbol using the storage class C_TPDEF (so the COFF reader
+     will know that name), there is no way to place a reference to
+     that typedef into the just 16 bits COFF reserves for all of its
+     type information.  Thus, any use of the typedef must always fully
+     dereference the typedef again.  We do this by "snapshotting" the
+     current type stack under the name of our typedef, and later on,
+     when BFD debugging tells us to make use of the typedef (in
+     coff_typedef_type()), we just look it up, and push all we've got
+     completely onto the type stack again. */
+
+  if (info->tstack == NULL)
+    {
+      fprintf (stderr, _("coff_typdef() on an empty type stack\n"));
+      return FALSE;
+    }
+
+  nthash = coff_name_type_hash_lookup (&info->types, name, FALSE, FALSE);
+  if (nthash != NULL)
+    {
+#if COFF_DEBUG
+      printf ("new typedef for %s\n", name);
+#endif
+      coff_free_type_info (nthash, NULL);
+    }
+  else
+    nthash = coff_name_type_hash_lookup (&info->types, name, TRUE, FALSE);
+  if (nthash == NULL)
+    return FALSE;
+  nthash->types = info->tstack;
+
+  /* If the typestack is "sufficiently complex", emit a C_TPDEF symbol
+     for it.  We assume it to be sufficiently complex if there are
+     either at least two derived types, or one derived type where the
+     base type is not a simple scalar one. */
+  if (!nthash->emitted
+      && info->tstack->next != NULL
+      && (info->tstack->next->next != NULL || info->tstack->next->tsk >= TS_ENUM))
+    {
+      struct coff_type_stack *newchain, *otst, *tst, *ntst;
+      coff_symbol_type *csymp;
+
+      nthash->emitted = TRUE;
+
+      for (tst = info->tstack, newchain = otst = NULL;
+	   tst != NULL;
+	   tst = tst->next)
+	{
+	  ntst = (struct coff_type_stack *)
+	    xmalloc (sizeof (struct coff_type_stack));
+	  memcpy (ntst, tst, sizeof (struct coff_type_stack));
+	  if (otst == NULL)
+	    newchain = ntst;
+	  else
+	    otst->next = ntst;
+	  otst = ntst;
+	}
+      info->tstack = newchain;
+      if (!coff_make_typed_symbol (info, &csymp, TS_NONE))
+	return FALSE;
+
+      csymp->symbol.name = xstrdup (name);
+      csymp->symbol.flags = BSF_NOT_AT_END;
+      csymp->symbol.section = bfd_com_section_ptr;
+      csymp->native->u.syment.n_sclass = C_TPDEF;
+      csymp->symbol.value = 0;
+
+      coff_record_symbol (info, csymp);
+    }
+  info->tstack = NULL;
+
+  return TRUE;
+}
+
+/* Define a tag.  */
+
+static bfd_boolean
+coff_tag (p, tag)
+     PTR p;
+     const char *tag;
+{
+  struct coff_write_handle *info = (struct coff_write_handle *) p;
+  struct coff_type_stack *tst = NULL;
+  struct coff_struct_hash_entry *shash;
+  struct coff_enum_hash_entry *ehash;
+
+
+#if COFF_DEBUG
+  printf ("coff_tag(%s)\n", tag);
+#endif
+
+  if (info->tstack == NULL)
+    {
+      fprintf (stderr, _("coff_tag() called on an empty typestack\n"));
+      return FALSE;
+    }
+
+  switch (info->tstack->tsk)
+    {
+    case TS_STRUCT:
+      shash = coff_struct_hash_lookup (&info->structs, tag, FALSE, FALSE);
+      assert (shash != NULL);
+      shash->types = info->tstack;
+      info->tstack = NULL;
+      break;
+
+    case TS_ENUM:
+      ehash = coff_enum_hash_lookup (&info->enums, tag, FALSE, FALSE);
+      if (ehash != NULL && ehash->types != NULL)
+	{
+#if COFF_DEBUG
+	  printf ("new enum definition for %s\n", tag);
+#endif
+	  coff_free_enum_info (ehash, NULL);
+	}
+      else
+	ehash = coff_enum_hash_lookup (&info->enums, tag, TRUE, FALSE);
+      if (ehash == NULL)
+	return FALSE;
+      ehash->types = info->tstack;
+      info->tstack = NULL;
+      break;
+
+    default:
+      fprintf (stderr, _("Illegal typestack (%d) in coff_tag()\n"), tst->tsk);
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+/* Define an integer constant.  */
+
+static bfd_boolean
+coff_int_constant (p, name, val)
+     PTR p;
+     const char *name ATTRIBUTE_UNUSED;
+     bfd_vma val ATTRIBUTE_UNUSED;
+{
+  struct coff_write_handle *info = (struct coff_write_handle *) p;
+
+#if COFF_DEBUG
+  printf ("coff_int_constant(%s, %d)\n", name, (int)val);
+#endif
+
+  coff_complain_unsupp (_("int constant"));
+
+  return TRUE;
+}
+
+/* Define a floating point constant.  */
+
+static bfd_boolean
+coff_float_constant (p, name, val)
+     PTR p;
+     const char *name ATTRIBUTE_UNUSED;
+     double val ATTRIBUTE_UNUSED;
+{
+  struct coff_write_handle *info = (struct coff_write_handle *) p;
+
+#if COFF_DEBUG
+  printf ("coff_float_constant(%s, %g)\n", name, val);
+#endif
+
+  coff_complain_unsupp (_("float constant"));
+
+  return TRUE;
+}
+
+/* Define a typed constant.  */
+
+static bfd_boolean
+coff_typed_constant (p, name, val)
+     PTR p;
+     const char *name ATTRIBUTE_UNUSED;
+     bfd_vma val ATTRIBUTE_UNUSED;
+{
+  struct coff_write_handle *info = (struct coff_write_handle *) p;
+
+#if COFF_DEBUG
+  printf ("coff_typed_constant(%s, %d)\n", name, (int)val);
+#endif
+
+  coff_complain_unsupp (_("typed constant"));
+
+  return TRUE;
+}
+
+/* Record a variable.  */
+
+static bfd_boolean
+coff_variable (p, name, kind, val)
+     PTR p;
+     const char *name;
+     enum debug_var_kind kind;
+     bfd_vma val;
+{
+  struct coff_write_handle *info = (struct coff_write_handle *) p;
+  unsigned char class;
+  asymbol *symp = NULL;
+  coff_symbol_type *csymp;
+  bfd_boolean global = FALSE;
+  flagword flags = BSF_LOCAL;
+  bfd_vma vmadiff = 0;
+
+#if COFF_DEBUG
+  printf ("coff_variable(%s, %d, %d)\n",
+	  name, (int)kind, (int)val);
+#endif
+
+  switch (kind)
+    {
+    default:
+      abort ();
+
+    case DEBUG_GLOBAL:
+      flags = BSF_GLOBAL;
+      global = TRUE;
+      /* AVR COFF historically used C_EXTDEF for global variables, and
+	 C_EXT for global functions.  Since some AVR COFF consumers
+	 apparently depend on this, we mimic this behaviour as
+	 well. */
+      class = info->flags & COFF_FL_AVR? C_EXTDEF: C_EXT;
+      break;
+
+    case DEBUG_STATIC:
+    case DEBUG_LOCAL_STATIC:
+      class = C_STAT;
+      break;
+
+    case DEBUG_LOCAL:
+      class = C_AUTO;
+      break;
+
+    case DEBUG_REGISTER:
+      class = C_REG;
+      break;
+    }
+
+  if (!coff_make_typed_symbol (info, &csymp, TS_NONE))
+    return FALSE;
+
+  if (class == C_REG && (info->flags & COFF_FL_AVR) != 0)
+    {
+      struct coff_private_symdata *priv = (struct coff_private_symdata *)
+	csymp->symbol.udata.p;
+      val = coff_fixup_avr_register (val, priv->size * 8);
+    }
+
+  csymp->symbol.name = name;
+  csymp->symbol.flags = flags;	/* Note: this clears BSF_DEBUGGING. */
+
+  /* Match the debugging symbol against the input symtab symbols.  If
+     we found one, use the section information from it.  Otherwise, we
+     are lost here and just use the absolute section that was
+     predeclared by coff_bfd_make_debug_symbol().  C_REG and C_AUTO
+     symbols (which we do not attempt to lookup in the symtab symbols
+     at all) go into the ABS section anyway. */
+  if (class != C_REG && class != C_AUTO)
+    {
+      symp = coff_find_symbol (info, name, FALSE, global);
+      if (symp)
+	{
+	  csymp->symbol.section = symp->section;
+	  vmadiff = symp->section->vma;
+	}
+    }
+
+  /* Symbols are relative to section vma. */
+  csymp->symbol.value = val - vmadiff;
+  csymp->native->u.syment.n_sclass = class;
+  coff_record_symbol (info, csymp);
+
+  return TRUE;
+}
+
+/* Start outputting a function.  */
+
+static bfd_boolean
+coff_start_function (p, name, globalp)
+     PTR p;
+     const char *name;
+     bfd_boolean globalp;
+{
+  struct coff_write_handle *info = (struct coff_write_handle *) p;
+  struct coff_type_stack *tst, *savedts;
+
+#if COFF_DEBUG
+  printf ("coff_start_function(%s, %d)\n",
+	  name, globalp);
+#endif
+
+  savedts = info->tstack;
+  info->tstack = NULL;
+
+  coff_push_type (TS_FUNC);
+
+  if (info->funname != NULL)
+    {
+      fprintf (stderr,
+	       _("coff_start_function() called twice, pending %s, new %s\n"),
+	       info->funname, name);
+      return FALSE;
+    }
+  info->funname = name;
+  info->funglobal = globalp;
+  info->flags |= COFF_FL_START_FCN;
+  tst->u.ts_func.savedts = savedts;
+
+  return TRUE;
+}
+
+/* Output a function parameter.  */
+
+static bfd_boolean
+coff_function_parameter (p, name, kind, val)
+     PTR p;
+     const char *name;
+     enum debug_parm_kind kind;
+     bfd_vma val;
+{
+  struct coff_write_handle *info = (struct coff_write_handle *) p;
+  coff_symbol_type *csymp;
+  unsigned char class;
+
+#if COFF_DEBUG
+  printf ("coff_function_parameter(%s, %d, %d)\n",
+	  name, (int)kind, (int)val);
+#endif
+
+  switch (kind)
+    {
+    default:
+      abort ();
+
+    case DEBUG_PARM_STACK:
+      class = C_ARG;
+      break;
+
+    case DEBUG_PARM_REG:
+      class = C_REGPARM;
+      break;
+
+    case DEBUG_PARM_REFERENCE:
+    case DEBUG_PARM_REF_REG:
+      fprintf (stderr, _("Reference parameters not available in COFF\n"));
+      return TRUE;
+    }
+
+  if (!coff_make_typed_symbol (info, &csymp, TS_FUNC))
+    return FALSE;
+
+  if (class == C_REGPARM && (info->flags & COFF_FL_AVR) != 0)
+    {
+      struct coff_private_symdata *priv = (struct coff_private_symdata *)
+	csymp->symbol.udata.p;
+      val = coff_fixup_avr_register (val, priv->size * 8);
+    }
+
+  csymp->symbol.name = name;
+  csymp->symbol.value = val;
+  csymp->symbol.flags |= BSF_LOCAL;
+  csymp->native->u.syment.n_sclass = class;
+
+  /* Since function parameters precede the actual function definition,
+     defer their output until the function has been created. */
+  info->fargs = (coff_symbol_type **)
+    xrealloc (info->fargs, ++info->nfargs * sizeof (coff_symbol_type *));
+  info->fargs[info->nfargs - 1] = csymp;
+
+  return TRUE;
+}
+
+/* Start a block.  */
+
+static bfd_boolean
+coff_start_block (p, addr)
+     PTR p;
+     bfd_vma addr;
+{
+  struct coff_write_handle *info = (struct coff_write_handle *) p;
+  struct coff_type_stack *tst, *otst;
+  struct coff_fix_stack *fixp, *ofp;
+  asymbol *symp;
+  coff_symbol_type *csymp;
+  unsigned int i;
+  bfd_boolean is_start_fcn;
+
+#if COFF_DEBUG
+  printf ("coff_start_block(%#x)\n", (int)addr);
+#endif
+
+  is_start_fcn = info->flags & COFF_FL_START_FCN;
+
+  if (is_start_fcn)
+    {
+      /* This is the starting block of a function.  We are going to
+         write three symbols here, one for the function itself, one
+         ".bf" symbol to indicate the begin of the function, and
+         finally one ".bb" for the first block inside the function. */
+      info->flags &= ~COFF_FL_START_FCN;
+
+      /* Our function definition should be the only type stack element
+	 by now. */
+      assert (info->tstack != NULL);
+      tst = info->tstack;
+      if (tst->tsk != TS_FUNC || tst->next != NULL)
+	{
+	  fprintf (stderr,
+		   _("coff_start_block() not within function definition\n"));
+	  return FALSE;
+	}
+
+      /* Restore saved type stack, and push our now complete function
+	 definition on top. */
+      info->tstack = tst->u.ts_func.savedts;
+      tst->next = info->tstack;
+      info->tstack = tst;
+
+      if (info->currentfile == NULL)
+	{
+	  fprintf (stderr,
+		   _("Warning: ignoring function %s() outside any compilation unit\n"),
+		   info->funname);
+	  for (tst = info->tstack, otst = NULL; tst != NULL;)
+	    {
+	      otst = tst;
+	      tst = otst->next;
+	      if (otst->tsk == TS_ENUM &&
+		  otst->u.ts_enum.tagismalloced)
+		free (otst->u.ts_enum.tag.malloctag);
+	      else if (otst->tsk == TS_STRUCT &&
+		       otst->u.ts_struct.tagismalloced)
+		free (otst->u.ts_struct.tag.malloctag);
+	      free (otst);
+	    }
+	  info->tstack = NULL;
+	  info->funname = NULL;
+
+	  return TRUE;
+	}
+
+      if (!coff_make_typed_symbol (info, &csymp, TS_NONE))
+	return FALSE;
+
+      csymp->symbol.name = info->funname;
+      csymp->symbol.flags = BSF_FUNCTION |
+	(info->funglobal? BSF_GLOBAL: BSF_LOCAL);
+      symp = coff_find_symbol (info, info->funname, TRUE, info->funglobal);
+      if (symp == NULL)
+	{
+	  fprintf (stderr,
+		   _("function %s not found in symbol table, defaulting to \"text\" section\n"),
+		   info->funname);
+	  csymp->symbol.section = info->funcsection = info->textsect;
+	}
+      else
+	csymp->symbol.section = info->funcsection = symp->section;
+
+      /* Symbol addresses are relative to section vma. */
+      csymp->symbol.value = addr - info->funcsection->vma;
+      csymp->native->u.syment.n_sclass = info->funglobal? C_EXT: C_STAT;
+      /* Create two initial line number entries.  The first one holds
+	 the function symbol, the second one is the trailing record
+	 that is required by coffgen.c::coff_write_native_symbol() to
+	 have a line number of zero. */
+      csymp->lineno = (alent *) xmalloc (2 * sizeof (alent));
+      memset (csymp->lineno, 0, 2 * sizeof (alent));
+      info->nlnos = 2;
+      info->totlnos++;
+      csymp->lineno[0].u.sym = (asymbol *)csymp;
+      coff_record_symbol (info, csymp);
+      info->funcindex = info->nsyms - 1; /* remember for later */
+      /* Record our endndx field for later fixing. */
+      fixp = (struct coff_fix_stack *) xmalloc (sizeof (struct coff_fix_stack));
+      fixp->native = csymp->native + 1;	/* points to first AUX */
+      fixp->next = NULL;
+      if (info->fixes == NULL)
+	info->fixes = fixp;
+      else
+	{
+	  for (ofp = info->fixes; ofp->next != NULL;)
+	    ofp = ofp->next;
+	  ofp->next = fixp;
+	}
+
+      csymp = (coff_symbol_type *) coff_bfd_make_debug_symbol (info->abfd, 0, 0);
+      if (csymp == NULL)
+	return FALSE;
+
+      csymp->symbol.name = ".bf";
+      csymp->native->u.syment.n_sclass = C_FCN;
+      csymp->native->u.syment.n_numaux = 1;
+      csymp->symbol.value = addr - info->funcsection->vma;
+      csymp->symbol.section = info->funcsection;
+      csymp->symbol.udata.p = NULL;
+      coff_record_symbol (info, csymp);
+    }
+
+  if (info->funname == NULL)
+    return TRUE;
+
+  csymp = (coff_symbol_type *) coff_bfd_make_debug_symbol (info->abfd, 0, 0);
+  if (csymp == NULL)
+    return FALSE;
+
+  csymp->symbol.name = ".bb";
+  csymp->native->u.syment.n_sclass = C_BLOCK;
+  csymp->native->u.syment.n_numaux = 1;
+  csymp->symbol.value = addr - info->funcsection->vma;
+  csymp->symbol.section = info->funcsection;
+  csymp->symbol.udata.p = NULL;
+  coff_record_symbol (info, csymp);
+
+  info->flags |= COFF_FL_FIX_BB;
+
+  /* Output any pending function parameters, if any. */
+  if (is_start_fcn && info->nfargs)
+    {
+      for (i = 0; i < info->nfargs; i++)
+	coff_record_symbol (info, info->fargs[i]);
+
+      free (info->fargs);
+      info->fargs = NULL;
+      info->nfargs = 0;
+    }
+
+  return TRUE;
+}
+
+/* End a block.  */
+
+static bfd_boolean
+coff_end_block (p, addr)
+     PTR p;
+     bfd_vma addr;
+{
+  struct coff_write_handle *info = (struct coff_write_handle *) p;
+  coff_symbol_type *csymp;
+  union internal_auxent *aux;
+
+#if COFF_DEBUG
+  printf ("coff_end_block(%#x)\n", (int)addr);
+#endif
+
+  if (info->funname == NULL)
+    return TRUE;
+
+  csymp = (coff_symbol_type *) coff_bfd_make_debug_symbol (info->abfd, 0, 0);
+  if (csymp == NULL)
+    return FALSE;
+
+  csymp->symbol.name = ".eb";
+  csymp->symbol.value = addr - info->funcsection->vma;
+  csymp->native->u.syment.n_sclass = C_BLOCK;
+  csymp->native->u.syment.n_numaux = 1;
+  csymp->symbol.udata.p = NULL;
+  csymp->symbol.section = info->funcsection;
+  aux = &((csymp->native + 1)->u.auxent);
+  aux->x_sym.x_misc.x_lnsz.x_lnno = info->lastlno;
+  coff_record_symbol (info, csymp);
+
+  info->endaddr = addr;
+
+  return TRUE;
+}
+
+/* End a function.  */
+
+static bfd_boolean
+coff_end_function (p)
+     PTR p;
+{
+  struct coff_write_handle *info = (struct coff_write_handle *) p;
+  coff_symbol_type *csymp;
+  union internal_auxent *aux;
+
+#if COFF_DEBUG
+  printf ("coff_end_function()\n");
+#endif
+
+  if (info->funname == NULL)
+    return TRUE;
+
+  csymp = (coff_symbol_type *) coff_bfd_make_debug_symbol (info->abfd, 0, 0);
+  if (csymp == NULL)
+    return FALSE;
+
+  csymp->symbol.name = ".ef";
+  csymp->symbol.value = info->endaddr - info->funcsection->vma;
+  csymp->native->u.syment.n_sclass = C_FCN;
+  csymp->native->u.syment.n_numaux = 1;
+  csymp->symbol.udata.p = NULL;
+  csymp->symbol.section = info->funcsection;
+  aux = &((csymp->native + 1)->u.auxent);
+  aux->x_sym.x_misc.x_lnsz.x_lnno = info->lastlno;
+
+  coff_record_symbol (info, csymp);
+
+  csymp = (coff_symbol_type *) info->syms[info->funcindex];
+  aux = &((csymp->native + 1)->u.auxent);
+  aux->x_sym.x_misc.x_fsize = info->endaddr - csymp->symbol.value;
+
+  info->flags |= COFF_FL_FIX_ENDNDX;
+  info->funname = NULL;
+
+  return TRUE;
+}
+
+/* Output a line number.  */
+
+static bfd_boolean
+coff_lineno (p, file, lineno, addr)
+     PTR p;
+     const char *file ATTRIBUTE_UNUSED;
+     unsigned long lineno;
+     bfd_vma addr;
+{
+  struct coff_write_handle *info = (struct coff_write_handle *) p;
+  coff_symbol_type *csymp;
+  union internal_auxent *aux;
+  long i;
+
+#if COFF_DEBUG
+  printf ("coff_lineno(%s, %ld, %d)\n",
+	  file, lineno, (int)addr);
+#endif
+
+  /* COFF can inherently only handle line numbers inside of functions.
+     If we are not inside a function, punt. */
+  if (info->funname == NULL)
+    return TRUE;
+
+  if (info->nlnos == 2)
+    {
+      /* This is the first line number of this function.  Fix the line
+	 number for the .bf symbol immediately following the start of
+	 function.  We also have to remember the starting line number
+	 of our function since all line number entries are relative to
+	 it in COFF.  Since regular line numbers must always be
+	 non-zero, we artificially force the function to start one
+	 line earlier. */
+      csymp = (coff_symbol_type *) info->syms[info->funcindex + 1];
+      aux = &((csymp->native + 1)->u.auxent);
+      aux->x_sym.x_misc.x_lnsz.x_lnno = lineno;
+      info->funlno = lineno - 1;
+    }
+
+  if (info->flags & COFF_FL_FIX_BB)
+    {
+      /* This is the first line number after one (or more) .bb
+	 symbols.  Fix them.  In order to cope with multiple blocks
+	 starting at the same line number, we walk back the list of
+	 symbols until we find a C_BLOCK one that had already been
+	 fixed, or until we find a C_FCN symbol (presumably, the start
+	 of our current function). */
+      info->flags &= ~COFF_FL_FIX_BB;
+
+      for (i = info->nsyms - 1; i >= 0; i--)
+	{
+	  csymp = (coff_symbol_type *) info->syms[i];
+	  if (csymp->native->u.syment.n_sclass == C_FCN)
+	    break;
+	  if (csymp->native->u.syment.n_sclass == C_BLOCK)
+	    {
+	      aux = &((csymp->native + 1)->u.auxent);
+	      if (aux->x_sym.x_misc.x_lnsz.x_lnno != 0)
+		/* already set up properly */
+		break;
+	      aux->x_sym.x_misc.x_lnsz.x_lnno = lineno;
+	    }
+	}
+    }
+
+  csymp = (coff_symbol_type *) info->syms[info->funcindex];
+  csymp->lineno = (alent *) xrealloc (csymp->lineno,
+				      ++info->nlnos * sizeof (alent));
+  memset (csymp->lineno + info->nlnos - 1, 0, sizeof (alent));
+  if (lineno > info->funlno)
+    csymp->lineno[info->nlnos - 2].line_number = lineno - info->funlno;
+  else
+    /* Line number unreasonable.  Can e. g. happen for a line number
+       from an include file, which we cannot process in COFF.  Just
+       set it to the first line, to avoid generating a large unsigned
+       short (~ 65000) line number. */
+    csymp->lineno[info->nlnos - 2].line_number = 1;
+  csymp->lineno[info->nlnos - 2].u.offset = addr;
+
+  info->lastlno = lineno;
+  info->totlnos++;
+
+  return TRUE;
+}
diff -Nur ../binutils-2.18.orig/bfd/Makefile.am ./bfd/Makefile.am
--- ../binutils-2.18.orig/bfd/Makefile.am	Tue Oct 23 21:44:07 2007
+++ ./bfd/Makefile.am	Tue Oct 23 22:41:01 2007
@@ -208,6 +208,8 @@
 	coff-apollo.lo \
 	coff-arm.lo \
 	coff-aux.lo \
+	coff-avr.lo \
+	coff-ext-avr.lo \
 	coff-h8300.lo \
 	coff-h8500.lo \
 	coff-i386.lo \
@@ -387,6 +389,8 @@
 	coff-apollo.c \
 	coff-arm.c \
 	coff-aux.c \
+	coff-avr.c \
+	coff-ext-avr.c \
 	coff-h8300.c \
 	coff-h8500.c \
 	coff-i386.c \
@@ -976,13 +980,13 @@
 bfdver.h: $(srcdir)/version.h $(srcdir)/Makefile.in
 	@echo "creating $@"
 	@bfd_version=`echo "$(VERSION)" | sed -e 's/\([^\.]*\)\.*\([^\.]*\)\.*\([^\.]*\)\.*\([^\.]*\)\.*\([^\.]*\).*/\1.00\2.00\3.00\4.00\5/' -e 's/\([^\.]*\)\..*\(..\)\..*\(..\)\..*\(..\)\..*\(..\)$$/\1\2\3\4\5/'` ;\
-	bfd_version_string="\"$(VERSION)\"" ;\
+	bfd_version_string="\"$(VERSION) + coff-avr-patch (20050630)\"" ;\
 	bfd_soversion="$(VERSION)" ;\
 	bfd_version_package="\"$(PKGVERSION)\"" ;\
 	report_bugs_to="\"$(REPORT_BUGS_TO)\"" ;\
 	if test "x$(RELEASE)" = x ; then \
 	  bfd_version_date=`sed -n -e 's/.*DATE //p' < $(srcdir)/version.h` ;\
-	  bfd_version_string="\"$(VERSION).$${bfd_version_date}\"" ;\
+	  bfd_version_string="\"$(VERSION).$${bfd_version_date} + coff-avr-patch (20050630)\"" ;\
 	  bfd_soversion="$(VERSION).$${bfd_version_date}" ;\
 	fi ;\
 	sed -e "s,@bfd_version@,$$bfd_version," \
@@ -1186,6 +1190,12 @@
   coff-m68k.c $(INCDIR)/hashtab.h $(INCDIR)/coff/m68k.h \
   $(INCDIR)/coff/internal.h libcoff.h $(INCDIR)/bfdlink.h \
   coffcode.h coffswap.h
+coff-avr.lo: coff-avr.c $(INCDIR)/filenames.h $(INCDIR)/coff/avr.h \
+  $(INCDIR)/coff/external.h $(INCDIR)/coff/internal.h \
+  libcoff.h $(INCDIR)/bfdlink.h coffcode.h coffswap.h
+coff-ext-avr.lo: coff-ext-avr.c $(INCDIR)/filenames.h $(INCDIR)/coff/avr.h \
+  $(INCDIR)/coff/external.h $(INCDIR)/coff/internal.h \
+  libcoff.h $(INCDIR)/bfdlink.h coffcode.h coffswap.h
 coff-h8300.lo: coff-h8300.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h \
   $(INCDIR)/bfdlink.h genlink.h $(INCDIR)/coff/h8300.h \
   $(INCDIR)/coff/external.h $(INCDIR)/coff/internal.h \
diff -Nur ../binutils-2.18.orig/bfd/Makefile.in ./bfd/Makefile.in
--- ../binutils-2.18.orig/bfd/Makefile.in	Tue Oct 23 21:44:07 2007
+++ ./bfd/Makefile.in	Tue Oct 23 22:41:31 2007
@@ -458,6 +458,8 @@
 	coff-apollo.lo \
 	coff-arm.lo \
 	coff-aux.lo \
+	coff-avr.lo \
+	coff-ext-avr.lo \
 	coff-h8300.lo \
 	coff-h8500.lo \
 	coff-i386.lo \
@@ -637,6 +639,8 @@
 	coff-apollo.c \
 	coff-arm.c \
 	coff-aux.c \
+	coff-avr.c \
+	coff-ext-avr.c \
 	coff-h8300.c \
 	coff-h8500.c \
 	coff-i386.c \
@@ -1556,13 +1560,13 @@
 bfdver.h: $(srcdir)/version.h $(srcdir)/Makefile.in
 	@echo "creating $@"
 	@bfd_version=`echo "$(VERSION)" | sed -e 's/\([^\.]*\)\.*\([^\.]*\)\.*\([^\.]*\)\.*\([^\.]*\)\.*\([^\.]*\).*/\1.00\2.00\3.00\4.00\5/' -e 's/\([^\.]*\)\..*\(..\)\..*\(..\)\..*\(..\)\..*\(..\)$$/\1\2\3\4\5/'` ;\
-	bfd_version_string="\"$(VERSION)\"" ;\
+	bfd_version_string="\"$(VERSION) + coff-avr-patch (20050630)\"" ;\
 	bfd_soversion="$(VERSION)" ;\
 	bfd_version_package="\"$(PKGVERSION)\"" ;\
 	report_bugs_to="\"$(REPORT_BUGS_TO)\"" ;\
 	if test "x$(RELEASE)" = x ; then \
 	  bfd_version_date=`sed -n -e 's/.*DATE //p' < $(srcdir)/version.h` ;\
-	  bfd_version_string="\"$(VERSION).$${bfd_version_date}\"" ;\
+	  bfd_version_string="\"$(VERSION).$${bfd_version_date} + coff-avr-patch (20050630)\"" ;\
 	  bfd_soversion="$(VERSION).$${bfd_version_date}" ;\
 	fi ;\
 	sed -e "s,@bfd_version@,$$bfd_version," \
@@ -1766,6 +1770,12 @@
   coff-m68k.c $(INCDIR)/hashtab.h $(INCDIR)/coff/m68k.h \
   $(INCDIR)/coff/internal.h libcoff.h $(INCDIR)/bfdlink.h \
   coffcode.h coffswap.h
+coff-avr.lo: coff-avr.c $(INCDIR)/filenames.h $(INCDIR)/coff/avr.h \
+  $(INCDIR)/coff/external.h $(INCDIR)/coff/internal.h \
+  libcoff.h $(INCDIR)/bfdlink.h coffcode.h coffswap.h
+coff-ext-avr.lo: coff-ext-avr.c $(INCDIR)/filenames.h $(INCDIR)/coff/avr.h \
+  $(INCDIR)/coff/external.h $(INCDIR)/coff/internal.h \
+  libcoff.h $(INCDIR)/bfdlink.h coffcode.h coffswap.h
 coff-h8300.lo: coff-h8300.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h \
   $(INCDIR)/bfdlink.h genlink.h $(INCDIR)/coff/h8300.h \
   $(INCDIR)/coff/external.h $(INCDIR)/coff/internal.h \
diff -Nur ../binutils-2.18.orig/bfd/coff-avr.c ./bfd/coff-avr.c
--- ../binutils-2.18.orig/bfd/coff-avr.c	Thu Jan  1 01:00:00 1970
+++ ./bfd/coff-avr.c	Tue Oct 23 22:18:44 2007
@@ -0,0 +1,609 @@
+/* BFD back-end for Atmel AVR COFF files.
+   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1999, 2000, 2001, 2003
+   Free Software Foundation, Inc.
+   Created mostly by substituting "avr" for "i860" in coff-i860.c
+
+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 "libbfd.h"
+
+#include "coff/avr.h"
+
+#include "coff/internal.h"
+
+#include "libcoff.h"
+
+static bfd_reloc_status_type coff_avr_reloc
+  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+static reloc_howto_type *coff_avr_rtype_to_howto
+  PARAMS ((bfd *, asection *, struct internal_reloc *,
+	   struct coff_link_hash_entry *, struct internal_syment *,
+	   bfd_vma *));
+static const bfd_target * coff_avr_object_p PARAMS ((bfd *));
+
+#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2)
+/* The page size is a guess based on ELF.  */
+
+#define COFF_PAGE_SIZE 0x1000
+
+/* For some reason when using avr COFF the value stored in the .text
+   section for a reference to a common symbol is the value itself plus
+   any desired offset.  Ian Taylor, Cygnus Support.  */
+
+/* If we are producing relocateable output, we need to do some
+   adjustments to the object file that are not done by the
+   bfd_perform_relocation function.  This function is called by every
+   reloc type to make any required adjustments.  */
+
+static bfd_reloc_status_type
+coff_avr_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd,
+		 error_message)
+     bfd *abfd;
+     arelent *reloc_entry;
+     asymbol *symbol;
+     PTR data;
+     asection *input_section ATTRIBUTE_UNUSED;
+     bfd *output_bfd;
+     char **error_message ATTRIBUTE_UNUSED;
+{
+  symvalue diff;
+
+  if (output_bfd == (bfd *) NULL)
+    return bfd_reloc_continue;
+
+  if (bfd_is_com_section (symbol->section))
+    {
+      /* We are relocating a common symbol.  The current value in the
+	 object file is ORIG + OFFSET, where ORIG is the value of the
+	 common symbol as seen by the object file when it was compiled
+	 (this may be zero if the symbol was undefined) and OFFSET is
+	 the offset into the common symbol (normally zero, but may be
+	 non-zero when referring to a field in a common structure).
+	 ORIG is the negative of reloc_entry->addend, which is set by
+	 the CALC_ADDEND macro below.  We want to replace the value in
+	 the object file with NEW + OFFSET, where NEW is the value of
+	 the common symbol which we are going to put in the final
+	 object file.  NEW is symbol->value.  */
+      diff = symbol->value + reloc_entry->addend;
+    }
+  else
+    {
+      /* For some reason bfd_perform_relocation always effectively
+	 ignores the addend for a COFF target when producing
+	 relocateable output.  This seems to be always wrong for 860
+	 COFF, so we handle the addend here instead.  */
+      diff = reloc_entry->addend;
+    }
+
+#define DOIT(x) \
+  x = ((x & ~howto->dst_mask) | (((x & howto->src_mask) + diff) & howto->dst_mask))
+
+    if (diff != 0)
+      {
+	reloc_howto_type *howto = reloc_entry->howto;
+	unsigned char *addr = (unsigned char *) data + reloc_entry->address;
+
+	switch (howto->size)
+	  {
+	  case 0:
+	    {
+	      char x = bfd_get_8 (abfd, addr);
+	      DOIT (x);
+	      bfd_put_8 (abfd, x, addr);
+	    }
+	    break;
+
+	  case 1:
+	    {
+	      short x = bfd_get_16 (abfd, addr);
+	      DOIT (x);
+	      bfd_put_16 (abfd, (bfd_vma) x, addr);
+	    }
+	    break;
+
+	  case 2:
+	    {
+	      long x = bfd_get_32 (abfd, addr);
+	      DOIT (x);
+	      bfd_put_32 (abfd, (bfd_vma) x, addr);
+	    }
+	    break;
+
+	  default:
+	    abort ();
+	  }
+      }
+
+  /* Now let bfd_perform_relocation finish everything up.  */
+  return bfd_reloc_continue;
+}
+
+#ifndef PCRELOFFSET
+#define PCRELOFFSET FALSE
+#endif
+
+static reloc_howto_type howto_table[] =
+{
+  EMPTY_HOWTO (0),
+  EMPTY_HOWTO (1),
+  EMPTY_HOWTO (2),
+  EMPTY_HOWTO (3),
+  EMPTY_HOWTO (4),
+  EMPTY_HOWTO (5),
+  HOWTO (R_DIR32,               /* type */
+	 0,	                /* rightshift */
+	 2,	                /* size (0 = byte, 1 = short, 2 = long) */
+	 32,	                /* bitsize */
+	 FALSE,	                /* pc_relative */
+	 0,	                /* bitpos */
+	 complain_overflow_bitfield, /* complain_on_overflow */
+	 coff_avr_reloc,       /* special_function */
+	 "dir32",               /* name */
+	 TRUE,	                /* partial_inplace */
+	 0xffffffff,            /* src_mask */
+	 0xffffffff,            /* dst_mask */
+	 TRUE),                /* pcrel_offset */
+  /* {7}, */
+  HOWTO (R_IMAGEBASE,            /* type */
+	 0,	                /* rightshift */
+	 2,	                /* size (0 = byte, 1 = short, 2 = long) */
+	 32,	                /* bitsize */
+	 FALSE,	                /* pc_relative */
+	 0,	                /* bitpos */
+	 complain_overflow_bitfield, /* complain_on_overflow */
+	 coff_avr_reloc,       /* special_function */
+	 "rva32",	           /* name */
+	 TRUE,	                /* partial_inplace */
+	 0xffffffff,            /* src_mask */
+	 0xffffffff,            /* dst_mask */
+	 FALSE),                /* pcrel_offset */
+  EMPTY_HOWTO (010),
+  EMPTY_HOWTO (011),
+  EMPTY_HOWTO (012),
+  EMPTY_HOWTO (013),
+  EMPTY_HOWTO (014),
+  EMPTY_HOWTO (015),
+  EMPTY_HOWTO (016),
+  HOWTO (R_RELBYTE,		/* type */
+	 0,			/* rightshift */
+	 0,			/* size (0 = byte, 1 = short, 2 = long) */
+	 8,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_bitfield, /* complain_on_overflow */
+	 coff_avr_reloc,	/* special_function */
+	 "8",			/* name */
+	 TRUE,			/* partial_inplace */
+	 0x000000ff,		/* src_mask */
+	 0x000000ff,		/* dst_mask */
+	 PCRELOFFSET),		/* pcrel_offset */
+  HOWTO (R_RELWORD,		/* type */
+	 0,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_bitfield, /* complain_on_overflow */
+	 coff_avr_reloc,	/* special_function */
+	 "16",			/* name */
+	 TRUE,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 PCRELOFFSET),		/* pcrel_offset */
+  HOWTO (R_RELLONG,		/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_bitfield, /* complain_on_overflow */
+	 coff_avr_reloc,	/* special_function */
+	 "32",			/* name */
+	 TRUE,			/* partial_inplace */
+	 0xffffffff,		/* src_mask */
+	 0xffffffff,		/* dst_mask */
+	 PCRELOFFSET),		/* pcrel_offset */
+  HOWTO (R_PCRBYTE,		/* type */
+	 0,			/* rightshift */
+	 0,			/* size (0 = byte, 1 = short, 2 = long) */
+	 8,			/* bitsize */
+	 TRUE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 coff_avr_reloc,	/* special_function */
+	 "DISP8",		/* name */
+	 TRUE,			/* partial_inplace */
+	 0x000000ff,		/* src_mask */
+	 0x000000ff,		/* dst_mask */
+	 PCRELOFFSET),		/* pcrel_offset */
+  HOWTO (R_PCRWORD,		/* type */
+	 0,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 TRUE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 coff_avr_reloc,	/* special_function */
+	 "DISP16",		/* name */
+	 TRUE,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 PCRELOFFSET),		/* pcrel_offset */
+  HOWTO (R_PCRLONG,		/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
+	 TRUE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 coff_avr_reloc,	/* special_function */
+	 "DISP32",		/* name */
+	 TRUE,			/* partial_inplace */
+	 0xffffffff,		/* src_mask */
+	 0xffffffff,		/* dst_mask */
+	 PCRELOFFSET)		/* pcrel_offset */
+};
+
+/* Turn a howto into a reloc  nunmber */
+
+#define SELECT_RELOC(x,howto) { x.r_type = howto->type; }
+#define BADMAG(x) AVRBADMAG(x)
+#define AVR 1			/* Customize coffcode.h */
+
+#define RTYPE2HOWTO(cache_ptr, dst) \
+	    (cache_ptr)->howto = howto_table + (dst)->r_type;
+
+/* For AVR COFF a STYP_NOLOAD | STYP_BSS section is part of a shared
+   library.  On some other COFF targets STYP_BSS is normally
+   STYP_NOLOAD.  */
+#define BSS_NOLOAD_IS_SHARED_LIBRARY
+
+/* Compute the addend of a reloc.  If the reloc is to a common symbol,
+   the object file contains the value of the common symbol.  By the
+   time this is called, the linker may be using a different symbol
+   from a different object file with a different value.  Therefore, we
+   hack wildly to locate the original symbol from this file so that we
+   can make the correct adjustment.  This macro sets coffsym to the
+   symbol from the original file, and uses it to set the addend value
+   correctly.  If this is not a common symbol, the usual addend
+   calculation is done, except that an additional tweak is needed for
+   PC relative relocs.
+   FIXME: This macro refers to symbols and asect; these are from the
+   calling function, not the macro arguments.  */
+
+#define CALC_ADDEND(abfd, ptr, reloc, cache_ptr)		\
+  {								\
+    coff_symbol_type *coffsym = (coff_symbol_type *) NULL;	\
+    if (ptr && bfd_asymbol_bfd (ptr) != abfd)			\
+      coffsym = (obj_symbols (abfd)				\
+	         + (cache_ptr->sym_ptr_ptr - symbols));		\
+    else if (ptr)						\
+      coffsym = coff_symbol_from (abfd, ptr);			\
+    if (coffsym != (coff_symbol_type *) NULL			\
+	&& coffsym->native->u.syment.n_scnum == 0)		\
+      cache_ptr->addend = - coffsym->native->u.syment.n_value;	\
+    else if (ptr && bfd_asymbol_bfd (ptr) == abfd		\
+	     && ptr->section != (asection *) NULL)		\
+      cache_ptr->addend = - (ptr->section->vma + ptr->value);	\
+    else							\
+      cache_ptr->addend = 0;					\
+    if (ptr && howto_table[reloc.r_type].pc_relative)		\
+      cache_ptr->addend += asect->vma;				\
+  }
+
+/* We use the special COFF backend linker.  */
+#define coff_relocate_section _bfd_coff_generic_relocate_section
+
+static reloc_howto_type *
+coff_avr_rtype_to_howto (abfd, sec, rel, h, sym, addendp)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     asection *sec;
+     struct internal_reloc *rel;
+     struct coff_link_hash_entry *h;
+     struct internal_syment *sym;
+     bfd_vma *addendp;
+{
+
+  reloc_howto_type *howto;
+
+  howto = howto_table + rel->r_type;
+
+  if (howto->pc_relative)
+    *addendp += sec->vma;
+
+  if (sym != NULL && sym->n_scnum == 0 && sym->n_value != 0)
+    {
+      /* This is a common symbol.  The section contents include the
+	 size (sym->n_value) as an addend.  The relocate_section
+	 function will be adding in the final value of the symbol.  We
+	 need to subtract out the current size in order to get the
+	 correct result.  */
+
+      BFD_ASSERT (h != NULL);
+
+      /* I think we *do* want to bypass this.  If we don't, I have seen some data
+	 parameters get the wrong relcation address.  If I link two versions
+	 with and without this section bypassed and then do a binary comparison,
+	 the addresses which are different can be looked up in the map.  The
+	 case in which this section has been bypassed has addresses which correspond
+	 to values I can find in the map.  */
+      *addendp -= sym->n_value;
+    }
+
+  /* If the output symbol is common (in which case this must be a
+     relocateable link), we need to add in the final size of the
+     common symbol.  */
+  if (h != NULL && h->root.type == bfd_link_hash_common)
+    *addendp += h->root.u.c.size;
+
+  return howto;
+}
+
+#define coff_rtype_to_howto coff_avr_rtype_to_howto
+
+#include "coffcode.h"
+
+static const bfd_target *
+coff_avr_object_p(a)
+     bfd *a;
+{
+  return coff_object_p (a);
+}
+
+/* Handle all the abominations of AVR COFF:
+
+   Generic COFF always uses the D1 slot to indicate the "most
+   important" derived type, and the D2...Dn slots for decreasing
+   importance.  E. g., a function symbol will always have its DT_FCN
+   element in D1, an array its DT_ARY (its first DT_ARY in a
+   multi-dimensional array).  In contrast, AVR COFF expects this most
+   important derived type specifier in the upmost Dn slot that is
+   allocated at all (i. e. that is != 0).
+
+   Generic COFF says that "Any symbol that satisfies more than one
+   condition [... for AUX entries] should have a union format in its
+   auxiliary entry."  AVR COFF uses sepearate AUX entries for multiple
+   derived types, and in some cases (like the ISFCN one), even puts
+   the most important one into the last allocated AUX entry.  We
+   join/split them here at the border as well.  Note that when
+   generating AUX entries (where we need to split them), the n_numaux
+   field must already have been set up properly (e. g. in
+   binutils/wrcoff.c) since the entry renumbering and pointerization
+   would not work otherwise.  Thus, we only split the information into
+   multiple records if n_numaux > 1.  For similar reasons, we keep
+   n_numaux > 1 on input to keep the appropriate AUX entries
+   allocated, so a symbol can be reconstructed if it is being passed
+   through one of the GNU tools.
+
+   Note that this adjustment is called after the symbol itself has
+   been swapped in, but before the AUX entries are swapped in.  This
+   is the only hook available that could swap (or merge) AUX entries
+   at all, so we have to operate on the external AUX entries still. */
+
+void
+avr_coff_adjust_sym_in_post (abfd, ext, in)
+     bfd *abfd;
+     PTR ext;
+     PTR in;
+{
+  struct internal_syment *dst = (struct internal_syment *)in;
+  unsigned short dt, bt, ndt;
+  dt = dst->n_type & ~N_BTMASK;
+  bt = BTYPE (dst->n_type);
+
+  /* Some AVR COFF producers seem to violate the COFF specs, and
+     produce symbols for tag names that have the C_FOO filled in
+     properly, but T_NULL as the base type value.  Patch up here,
+     since some of our generic COFF tools (in particular
+     binutils/rdcoff.c) rely on the correct data. */
+  if (bt == T_NULL)
+    switch (dst->n_sclass)
+      {
+      case C_STRTAG:
+	bt = T_STRUCT;
+	break;
+
+      case C_UNTAG:
+	bt = T_UNION;
+	break;
+
+      case C_ENTAG:
+	bt = T_ENUM;
+	break;
+      }
+
+  /* Swap the derived type slots. */
+  if (dt != 0)
+    {
+      ndt = 0;
+      while (dt != 0)
+	{
+	  ndt = (ndt << N_TSHIFT) | (dt & (N_TMASK >> N_BTSHFT));
+	  dt >>= N_TSHIFT;
+	}
+      dst->n_type = (ndt << N_BTSHFT) | bt;
+    }
+  else
+    dst->n_type = bt;
+
+  /* If the derived type is function, and there is more than one AUX
+     entry, swap the first and the last AUX entry, so the most
+     interesting one will become the first.
+
+     If the fundamental type is a tagged type (struct/union/enum), try
+     to find the AUX entry describing the tagged type (the one that
+     has x_sym.x_tagndx filled in), and merge the tag index into the
+     first AUX entry.  Depending on the actual input file, there might
+     be further DT_PTR entries which we just ignore, since we could
+     not handle that information anyway. */
+  if (dst->n_numaux > 1 && dst->n_sclass != C_FILE)
+    {
+      AUXENT caux, *auxp1, *auxp2;
+      size_t symesz;
+      unsigned int i;
+
+      symesz = bfd_coff_symesz (abfd);
+      i = dst->n_numaux;
+
+      auxp1 = (AUXENT *)((char *)ext + symesz);
+      auxp2 = (AUXENT *)((char *)ext + i * symesz);
+
+      if (ISFCN (dst->n_type)
+	  || (ISPTR(dst->n_type)
+	      && (bt == T_STRUCT || bt == T_UNION || bt == T_ENUM)))
+	{
+	  caux = *auxp2;
+	  *auxp2 = *auxp1;
+	  *auxp1 = caux;
+	}
+      else
+	caux = *auxp1;
+
+      if ((ISFCN (dst->n_type) || ISARY (dst->n_type))
+	  && (bt == T_STRUCT || bt == T_UNION || bt == T_ENUM))
+	{
+	  while (i > 1)
+	    {
+	      auxp2 = (AUXENT *)((char *)ext + i * symesz);
+
+	      if (auxp2->x_sym.x_tagndx[0] != 0 || auxp2->x_sym.x_tagndx[1] != 0
+		  || auxp2->x_sym.x_tagndx[2] != 0 || auxp2->x_sym.x_tagndx[3] != 0)
+		{
+		  memcpy (caux.x_sym.x_tagndx, auxp2->x_sym.x_tagndx,
+			  4 * sizeof (char));
+		  break;
+		}
+	      i--;
+	    }
+	  if (i > 1)
+	    *auxp1 = caux;
+	}
+    }
+}
+
+/* When exporting an AVR COFF file, just undo all that has been done
+   above.  Again, we are called after the symbol itself has been
+   swapped out, but before the AUX entries are being written.
+   Unfortunately, we are only given a pointer to the symbol itself, so
+   we have to derive the pointer to the respective aux entries from
+   that address, which is a bit clumsy. */
+void
+avr_coff_adjust_sym_out_post (abfd, in, ext)
+     bfd *abfd;
+     PTR in;
+     PTR ext;
+{
+  struct internal_syment *src = (struct internal_syment *)(in);
+  struct external_syment *dst = (struct external_syment *)(ext);
+  unsigned short dt, bt, ndt;
+
+  dt = src->n_type & ~N_BTMASK;
+  bt = BTYPE (src->n_type);
+
+  if (dt != 0)
+    {
+      ndt = 0;
+      while (dt != 0)
+	{
+	  ndt = (ndt << N_TSHIFT) | (dt & (N_TMASK >> N_BTSHFT));
+	  dt >>= N_TSHIFT;
+	}
+      H_PUT_16 (abfd, (ndt << N_BTSHFT) | bt, dst->e_type);
+    }
+
+  if (src->n_numaux > 1 && src->n_sclass != C_FILE)
+    {
+      combined_entry_type *srce, *dste;
+      char *hackp;
+      unsigned int i;
+
+      /* Recover the original combinend_entry_type *. */
+      hackp = (char *)in;
+      hackp -= offsetof(combined_entry_type, u.syment);
+      srce = (combined_entry_type *)hackp;
+      srce++;
+
+      /* We simply duplicate the first AUX entry as many times as
+	 needed.  Since COFF itself normally uses just a single AUX
+	 entry for all the information, this will work -- each COFF
+	 consumer will then just pick the fields it is particularly
+	 interested in.  This would not work for the AVR COFF specific
+	 DT_PTR AUX entries, but we don't support them anyway. */
+      for (i = 1; i < src->n_numaux; i++)
+	{
+	  dste = srce + i;
+	  *dste = *srce;
+	}
+    }
+}
+
+const bfd_target
+#ifdef TARGET_SYM
+  TARGET_SYM =
+#else
+  avrcoff_vec =
+#endif
+{
+#ifdef TARGET_NAME
+  TARGET_NAME,
+#else
+  "coff-avr",			/* name */
+#endif
+  bfd_target_coff_flavour,
+  BFD_ENDIAN_LITTLE,		/* data byte order is little */
+  BFD_ENDIAN_LITTLE,		/* header byte order is little */
+
+  (HAS_RELOC | EXEC_P |		/* object flags */
+   HAS_LINENO | HAS_DEBUG |
+   HAS_SYMS | HAS_LOCALS | WP_TEXT),
+
+  (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
+  0,				/* leading char */
+  '/',				/* ar_pad_char */
+  15,				/* ar_max_namelen */
+
+  bfd_getl64, bfd_getl_signed_64, bfd_putl64,
+     bfd_getl32, bfd_getl_signed_32, bfd_putl32,
+     bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */
+  bfd_getl64, bfd_getl_signed_64, bfd_putl64,
+     bfd_getl32, bfd_getl_signed_32, bfd_putl32,
+     bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */
+
+/* Note that we allow an object file to be treated as a core file as well.  */
+    {_bfd_dummy_target, coff_avr_object_p, /* bfd_check_format */
+       bfd_generic_archive_p, coff_avr_object_p},
+    {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */
+       bfd_false},
+    {bfd_false, coff_write_object_contents, /* bfd_write_contents */
+       _bfd_write_archive_contents, bfd_false},
+
+     BFD_JUMP_TABLE_GENERIC (coff),
+     BFD_JUMP_TABLE_COPY (coff),
+     BFD_JUMP_TABLE_CORE (_bfd_nocore),
+     BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),
+     BFD_JUMP_TABLE_SYMBOLS (coff),
+     BFD_JUMP_TABLE_RELOCS (coff),
+     BFD_JUMP_TABLE_WRITE (coff),
+     BFD_JUMP_TABLE_LINK (coff),
+     BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
+
+  NULL,
+
+  COFF_SWAP_TABLE
+};
diff -Nur ../binutils-2.18.orig/bfd/coff-ext-avr.c ./bfd/coff-ext-avr.c
--- ../binutils-2.18.orig/bfd/coff-ext-avr.c	Thu Jan  1 01:00:00 1970
+++ ./bfd/coff-ext-avr.c	Tue Oct 23 22:18:44 2007
@@ -0,0 +1,424 @@
+/* BFD back-end for Atmel AVR "extended" COFF files.
+   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1999, 2000, 2001, 2003
+   Free Software Foundation, Inc.
+   This is mostly the same as avr-coff, except of the presence of the
+   COFF optional header.
+
+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 "libbfd.h"
+
+#define AVR_EXT_COFF 1
+#include "coff/avr.h"
+
+#include "coff/internal.h"
+
+#include "libcoff.h"
+
+static bfd_reloc_status_type coff_ext_avr_reloc
+  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+static reloc_howto_type *coff_ext_avr_rtype_to_howto
+  PARAMS ((bfd *, asection *, struct internal_reloc *,
+	   struct coff_link_hash_entry *, struct internal_syment *,
+	   bfd_vma *));
+static const bfd_target * coff_ext_avr_object_p PARAMS ((bfd *));
+
+#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2)
+/* The page size is a guess based on ELF.  */
+
+#define COFF_PAGE_SIZE 0x1000
+
+/* For some reason when using avr COFF the value stored in the .text
+   section for a reference to a common symbol is the value itself plus
+   any desired offset.  Ian Taylor, Cygnus Support.  */
+
+/* If we are producing relocateable output, we need to do some
+   adjustments to the object file that are not done by the
+   bfd_perform_relocation function.  This function is called by every
+   reloc type to make any required adjustments.  */
+
+static bfd_reloc_status_type
+coff_ext_avr_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd,
+		 error_message)
+     bfd *abfd;
+     arelent *reloc_entry;
+     asymbol *symbol;
+     PTR data;
+     asection *input_section ATTRIBUTE_UNUSED;
+     bfd *output_bfd;
+     char **error_message ATTRIBUTE_UNUSED;
+{
+  symvalue diff;
+
+  if (output_bfd == (bfd *) NULL)
+    return bfd_reloc_continue;
+
+  if (bfd_is_com_section (symbol->section))
+    {
+      /* We are relocating a common symbol.  The current value in the
+	 object file is ORIG + OFFSET, where ORIG is the value of the
+	 common symbol as seen by the object file when it was compiled
+	 (this may be zero if the symbol was undefined) and OFFSET is
+	 the offset into the common symbol (normally zero, but may be
+	 non-zero when referring to a field in a common structure).
+	 ORIG is the negative of reloc_entry->addend, which is set by
+	 the CALC_ADDEND macro below.  We want to replace the value in
+	 the object file with NEW + OFFSET, where NEW is the value of
+	 the common symbol which we are going to put in the final
+	 object file.  NEW is symbol->value.  */
+      diff = symbol->value + reloc_entry->addend;
+    }
+  else
+    {
+      /* For some reason bfd_perform_relocation always effectively
+	 ignores the addend for a COFF target when producing
+	 relocateable output.  This seems to be always wrong for 860
+	 COFF, so we handle the addend here instead.  */
+      diff = reloc_entry->addend;
+    }
+
+#define DOIT(x) \
+  x = ((x & ~howto->dst_mask) | (((x & howto->src_mask) + diff) & howto->dst_mask))
+
+    if (diff != 0)
+      {
+	reloc_howto_type *howto = reloc_entry->howto;
+	unsigned char *addr = (unsigned char *) data + reloc_entry->address;
+
+	switch (howto->size)
+	  {
+	  case 0:
+	    {
+	      char x = bfd_get_8 (abfd, addr);
+	      DOIT (x);
+	      bfd_put_8 (abfd, x, addr);
+	    }
+	    break;
+
+	  case 1:
+	    {
+	      short x = bfd_get_16 (abfd, addr);
+	      DOIT (x);
+	      bfd_put_16 (abfd, (bfd_vma) x, addr);
+	    }
+	    break;
+
+	  case 2:
+	    {
+	      long x = bfd_get_32 (abfd, addr);
+	      DOIT (x);
+	      bfd_put_32 (abfd, (bfd_vma) x, addr);
+	    }
+	    break;
+
+	  default:
+	    abort ();
+	  }
+      }
+
+  /* Now let bfd_perform_relocation finish everything up.  */
+  return bfd_reloc_continue;
+}
+
+#ifndef PCRELOFFSET
+#define PCRELOFFSET FALSE
+#endif
+
+static reloc_howto_type howto_table[] =
+{
+  EMPTY_HOWTO (0),
+  EMPTY_HOWTO (1),
+  EMPTY_HOWTO (2),
+  EMPTY_HOWTO (3),
+  EMPTY_HOWTO (4),
+  EMPTY_HOWTO (5),
+  HOWTO (R_DIR32,               /* type */
+	 0,	                /* rightshift */
+	 2,	                /* size (0 = byte, 1 = short, 2 = long) */
+	 32,	                /* bitsize */
+	 FALSE,	                /* pc_relative */
+	 0,	                /* bitpos */
+	 complain_overflow_bitfield, /* complain_on_overflow */
+	 coff_ext_avr_reloc,       /* special_function */
+	 "dir32",               /* name */
+	 TRUE,	                /* partial_inplace */
+	 0xffffffff,            /* src_mask */
+	 0xffffffff,            /* dst_mask */
+	 TRUE),                /* pcrel_offset */
+  /* {7}, */
+  HOWTO (R_IMAGEBASE,            /* type */
+	 0,	                /* rightshift */
+	 2,	                /* size (0 = byte, 1 = short, 2 = long) */
+	 32,	                /* bitsize */
+	 FALSE,	                /* pc_relative */
+	 0,	                /* bitpos */
+	 complain_overflow_bitfield, /* complain_on_overflow */
+	 coff_ext_avr_reloc,       /* special_function */
+	 "rva32",	           /* name */
+	 TRUE,	                /* partial_inplace */
+	 0xffffffff,            /* src_mask */
+	 0xffffffff,            /* dst_mask */
+	 FALSE),                /* pcrel_offset */
+  EMPTY_HOWTO (010),
+  EMPTY_HOWTO (011),
+  EMPTY_HOWTO (012),
+  EMPTY_HOWTO (013),
+  EMPTY_HOWTO (014),
+  EMPTY_HOWTO (015),
+  EMPTY_HOWTO (016),
+  HOWTO (R_RELBYTE,		/* type */
+	 0,			/* rightshift */
+	 0,			/* size (0 = byte, 1 = short, 2 = long) */
+	 8,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_bitfield, /* complain_on_overflow */
+	 coff_ext_avr_reloc,	/* special_function */
+	 "8",			/* name */
+	 TRUE,			/* partial_inplace */
+	 0x000000ff,		/* src_mask */
+	 0x000000ff,		/* dst_mask */
+	 PCRELOFFSET),		/* pcrel_offset */
+  HOWTO (R_RELWORD,		/* type */
+	 0,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_bitfield, /* complain_on_overflow */
+	 coff_ext_avr_reloc,	/* special_function */
+	 "16",			/* name */
+	 TRUE,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 PCRELOFFSET),		/* pcrel_offset */
+  HOWTO (R_RELLONG,		/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_bitfield, /* complain_on_overflow */
+	 coff_ext_avr_reloc,	/* special_function */
+	 "32",			/* name */
+	 TRUE,			/* partial_inplace */
+	 0xffffffff,		/* src_mask */
+	 0xffffffff,		/* dst_mask */
+	 PCRELOFFSET),		/* pcrel_offset */
+  HOWTO (R_PCRBYTE,		/* type */
+	 0,			/* rightshift */
+	 0,			/* size (0 = byte, 1 = short, 2 = long) */
+	 8,			/* bitsize */
+	 TRUE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 coff_ext_avr_reloc,	/* special_function */
+	 "DISP8",		/* name */
+	 TRUE,			/* partial_inplace */
+	 0x000000ff,		/* src_mask */
+	 0x000000ff,		/* dst_mask */
+	 PCRELOFFSET),		/* pcrel_offset */
+  HOWTO (R_PCRWORD,		/* type */
+	 0,			/* rightshift */
+	 1,			/* size (0 = byte, 1 = short, 2 = long) */
+	 16,			/* bitsize */
+	 TRUE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 coff_ext_avr_reloc,	/* special_function */
+	 "DISP16",		/* name */
+	 TRUE,			/* partial_inplace */
+	 0x0000ffff,		/* src_mask */
+	 0x0000ffff,		/* dst_mask */
+	 PCRELOFFSET),		/* pcrel_offset */
+  HOWTO (R_PCRLONG,		/* type */
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
+	 TRUE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_signed, /* complain_on_overflow */
+	 coff_ext_avr_reloc,	/* special_function */
+	 "DISP32",		/* name */
+	 TRUE,			/* partial_inplace */
+	 0xffffffff,		/* src_mask */
+	 0xffffffff,		/* dst_mask */
+	 PCRELOFFSET)		/* pcrel_offset */
+};
+
+/* Turn a howto into a reloc  nunmber */
+
+#define SELECT_RELOC(x,howto) { x.r_type = howto->type; }
+#define BADMAG(x) AVRBADMAG(x)
+#define AVR 1			/* Customize coffcode.h */
+
+#define RTYPE2HOWTO(cache_ptr, dst) \
+	    (cache_ptr)->howto = howto_table + (dst)->r_type;
+
+/* For AVR COFF a STYP_NOLOAD | STYP_BSS section is part of a shared
+   library.  On some other COFF targets STYP_BSS is normally
+   STYP_NOLOAD.  */
+#define BSS_NOLOAD_IS_SHARED_LIBRARY
+
+/* Compute the addend of a reloc.  If the reloc is to a common symbol,
+   the object file contains the value of the common symbol.  By the
+   time this is called, the linker may be using a different symbol
+   from a different object file with a different value.  Therefore, we
+   hack wildly to locate the original symbol from this file so that we
+   can make the correct adjustment.  This macro sets coffsym to the
+   symbol from the original file, and uses it to set the addend value
+   correctly.  If this is not a common symbol, the usual addend
+   calculation is done, except that an additional tweak is needed for
+   PC relative relocs.
+   FIXME: This macro refers to symbols and asect; these are from the
+   calling function, not the macro arguments.  */
+
+#define CALC_ADDEND(abfd, ptr, reloc, cache_ptr)		\
+  {								\
+    coff_symbol_type *coffsym = (coff_symbol_type *) NULL;	\
+    if (ptr && bfd_asymbol_bfd (ptr) != abfd)			\
+      coffsym = (obj_symbols (abfd)				\
+	         + (cache_ptr->sym_ptr_ptr - symbols));		\
+    else if (ptr)						\
+      coffsym = coff_symbol_from (abfd, ptr);			\
+    if (coffsym != (coff_symbol_type *) NULL			\
+	&& coffsym->native->u.syment.n_scnum == 0)		\
+      cache_ptr->addend = - coffsym->native->u.syment.n_value;	\
+    else if (ptr && bfd_asymbol_bfd (ptr) == abfd		\
+	     && ptr->section != (asection *) NULL)		\
+      cache_ptr->addend = - (ptr->section->vma + ptr->value);	\
+    else							\
+      cache_ptr->addend = 0;					\
+    if (ptr && howto_table[reloc.r_type].pc_relative)		\
+      cache_ptr->addend += asect->vma;				\
+  }
+
+/* We use the special COFF backend linker.  */
+#define coff_relocate_section _bfd_coff_generic_relocate_section
+
+static reloc_howto_type *
+coff_ext_avr_rtype_to_howto (abfd, sec, rel, h, sym, addendp)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     asection *sec;
+     struct internal_reloc *rel;
+     struct coff_link_hash_entry *h;
+     struct internal_syment *sym;
+     bfd_vma *addendp;
+{
+
+  reloc_howto_type *howto;
+
+  howto = howto_table + rel->r_type;
+
+  if (howto->pc_relative)
+    *addendp += sec->vma;
+
+  if (sym != NULL && sym->n_scnum == 0 && sym->n_value != 0)
+    {
+      /* This is a common symbol.  The section contents include the
+	 size (sym->n_value) as an addend.  The relocate_section
+	 function will be adding in the final value of the symbol.  We
+	 need to subtract out the current size in order to get the
+	 correct result.  */
+
+      BFD_ASSERT (h != NULL);
+
+      /* I think we *do* want to bypass this.  If we don't, I have seen some data
+	 parameters get the wrong relcation address.  If I link two versions
+	 with and without this section bypassed and then do a binary comparison,
+	 the addresses which are different can be looked up in the map.  The
+	 case in which this section has been bypassed has addresses which correspond
+	 to values I can find in the map.  */
+      *addendp -= sym->n_value;
+    }
+
+  /* If the output symbol is common (in which case this must be a
+     relocateable link), we need to add in the final size of the
+     common symbol.  */
+  if (h != NULL && h->root.type == bfd_link_hash_common)
+    *addendp += h->root.u.c.size;
+
+  return howto;
+}
+
+#define coff_rtype_to_howto coff_ext_avr_rtype_to_howto
+
+#include "coffcode.h"
+
+static const bfd_target *
+coff_ext_avr_object_p(a)
+     bfd *a;
+{
+  return coff_object_p (a);
+}
+
+const bfd_target
+#ifdef TARGET_SYM
+  TARGET_SYM =
+#else
+  avrextcoff_vec =
+#endif
+{
+#ifdef TARGET_NAME
+  TARGET_NAME,
+#else
+  "coff-ext-avr",			/* name */
+#endif
+  bfd_target_coff_flavour,
+  BFD_ENDIAN_LITTLE,		/* data byte order is little */
+  BFD_ENDIAN_LITTLE,		/* header byte order is little */
+
+  (HAS_RELOC | EXEC_P |		/* object flags */
+   HAS_LINENO | HAS_DEBUG |
+   HAS_SYMS | HAS_LOCALS | WP_TEXT),
+
+  (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
+  0,				/* leading char */
+  '/',				/* ar_pad_char */
+  15,				/* ar_max_namelen */
+
+  bfd_getl64, bfd_getl_signed_64, bfd_putl64,
+     bfd_getl32, bfd_getl_signed_32, bfd_putl32,
+     bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */
+  bfd_getl64, bfd_getl_signed_64, bfd_putl64,
+     bfd_getl32, bfd_getl_signed_32, bfd_putl32,
+     bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */
+
+/* Note that we allow an object file to be treated as a core file as well.  */
+    {_bfd_dummy_target, coff_ext_avr_object_p, /* bfd_check_format */
+       bfd_generic_archive_p, coff_ext_avr_object_p},
+    {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */
+       bfd_false},
+    {bfd_false, coff_write_object_contents, /* bfd_write_contents */
+       _bfd_write_archive_contents, bfd_false},
+
+     BFD_JUMP_TABLE_GENERIC (coff),
+     BFD_JUMP_TABLE_COPY (coff),
+     BFD_JUMP_TABLE_CORE (_bfd_nocore),
+     BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),
+     BFD_JUMP_TABLE_SYMBOLS (coff),
+     BFD_JUMP_TABLE_RELOCS (coff),
+     BFD_JUMP_TABLE_WRITE (coff),
+     BFD_JUMP_TABLE_LINK (coff),
+     BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
+
+  NULL,
+
+  COFF_SWAP_TABLE
+};
diff -Nur ../binutils-2.18.orig/bfd/coffcode.h ./bfd/coffcode.h
--- ../binutils-2.18.orig/bfd/coffcode.h	Tue Oct 23 21:44:07 2007
+++ ./bfd/coffcode.h	Tue Oct 23 22:18:44 2007
@@ -1,3 +1,4 @@
+
 /* Support for the generic parts of most COFF variants, for BFD.
    Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
    2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
@@ -1769,6 +1770,17 @@
   coff->relocbase = 0;
   coff->local_toc_sym_map = 0;
 
+  /* These members communicate important constants about the symbol
+     table to GDB's symbol-reading code.  These `constants'
+     unfortunately vary among coff implementations...  */
+  coff->local_n_btmask = N_BTMASK;
+  coff->local_n_btshft = N_BTSHFT;
+  coff->local_n_tmask = N_TMASK;
+  coff->local_n_tshift = N_TSHIFT;
+  coff->local_symesz = bfd_coff_symesz (abfd);
+  coff->local_auxesz = bfd_coff_auxesz (abfd);
+  coff->local_linesz = bfd_coff_linesz (abfd);
+
 /*  make_abs_section(abfd);*/
 
   return TRUE;
@@ -1793,17 +1805,6 @@
 
   coff->sym_filepos = internal_f->f_symptr;
 
-  /* These members communicate important constants about the symbol
-     table to GDB's symbol-reading code.  These `constants'
-     unfortunately vary among coff implementations...  */
-  coff->local_n_btmask = N_BTMASK;
-  coff->local_n_btshft = N_BTSHFT;
-  coff->local_n_tmask = N_TMASK;
-  coff->local_n_tshift = N_TSHIFT;
-  coff->local_symesz = bfd_coff_symesz (abfd);
-  coff->local_auxesz = bfd_coff_auxesz (abfd);
-  coff->local_linesz = bfd_coff_linesz (abfd);
-
   coff->timestamp = internal_f->f_timdat;
 
   obj_raw_syment_count (abfd) =
@@ -1930,6 +1931,11 @@
 	}
       break;
 #endif
+#ifdef AVRMAGIC
+    case AVRMAGIC:
+      arch = bfd_arch_avr;
+      break;
+#endif
 #ifdef MC68MAGIC
     case MC68MAGIC:
     case M68MAGIC:
@@ -2726,6 +2732,13 @@
       return TRUE;
 #endif
 
+#ifdef AVRMAGIC
+    case bfd_arch_avr:
+      *magicp = AVRMAGIC;
+      return TRUE;
+      break;
+#endif
+
 #ifdef PPCMAGIC
     case bfd_arch_powerpc:
       *magicp = PPCMAGIC;
@@ -3522,6 +3535,11 @@
       section.s_page = coff_get_section_load_page (current);
 #endif
 
+#ifdef AVR
+      /* AVR uses s_paddr the way GNU uses s_vaddr, and effectively
+	 ignores s_vaddr. */
+      section.s_paddr = current->vma;
+#endif
 #ifdef COFF_WITH_PE
       section.s_paddr = 0;
 #endif
@@ -3866,6 +3884,17 @@
     internal_a.magic = ZMAGIC;
 #endif
 
+#ifdef AVR
+    /* a.out is a dummy for non-extended COFF */
+    internal_a.magic = AVRAOUTMAGIC;
+    /* Upper nibble of f_flags must be set for historical reasons.
+       The upper byte remains blank on coff-avr, so undo the F_AR32WR
+       setting performed above. */
+    internal_f.f_flags |= F_JUNK;
+    internal_f.f_flags &= ~F_UNUSED;
+#define __A_MAGIC_SET__
+#endif /* AVR */
+
 #if defined(PPC_PE)
 #define __A_MAGIC_SET__
     internal_a.magic = IMAGE_NT_OPTIONAL_HDR_MAGIC;
@@ -3933,8 +3962,16 @@
 #endif
   }
 
+#ifdef AVR_EXT_COFF
+    /* Note that we do not set F_PTRINFO because the GNU toolchain
+       doesn't provide any information about the target of a pointer,
+       so we cannot derive which section our pointer target would be
+       in. */
+  internal_a.vstamp = F_FULLPATHS | F_STRUCTINFO;
+#else
   /* FIXME: Does anybody ever set this to another value?  */
   internal_a.vstamp = 0;
+#endif
 
   /* Now should write relocs, strings, syms.  */
   obj_sym_filepos (abfd) = sym_base;
@@ -4120,22 +4157,29 @@
       char * buff;
       bfd_size_type amount = bfd_coff_aoutsz (abfd);
 
-      buff = bfd_malloc (amount);
-      if (buff == NULL)
-	return FALSE;
+      /* Do not attempt to malloc() zero bytes.  According to the
+         C standard, the behaviour is implementation-defined, and
+	 malloc() might return NULL in that case, which would confuse
+	 us to assume an error where it actually isn't. */
+      if (amount != 0)
+	{
+	  buff = bfd_malloc (amount);
+	  if (buff == NULL)
+	    return FALSE;
 
-      coff_swap_aouthdr_out (abfd, & internal_a, buff);
-      amount = bfd_bwrite (buff, amount, abfd);
+	  coff_swap_aouthdr_out (abfd, & internal_a, buff);
+	  amount = bfd_bwrite (buff, amount, abfd);
 
-      free (buff);
+	  free (buff);
 
-      if (amount != bfd_coff_aoutsz (abfd))
-	return FALSE;
+	  if (amount != bfd_coff_aoutsz (abfd))
+	    return FALSE;
 
 #ifdef COFF_IMAGE_WITH_PE
-      if (! coff_apply_checksum (abfd))
-	return FALSE;
+	  if (! coff_apply_checksum (abfd))
+	    return FALSE;
 #endif
+	}
     }
 #ifdef RS6000COFF_C
   else
@@ -4491,6 +4535,10 @@
 	    /* In PE, 0x69 (105) denotes a weak external symbol.  */
 	    case C_NT_WEAK:
 #endif
+#ifdef AVR
+	    /* Some AVR COFF compilers handle EXTDEF like EXT. */
+	    case C_EXTDEF:	/* external definition		 */
+#endif
 	      switch (coff_classify_symbol (abfd, &src->u.syment))
 		{
 		case COFF_SYMBOL_GLOBAL:
@@ -4714,7 +4762,9 @@
 		  && src->u.syment.n_scnum == 0)
 		break;
 	      /* Fall through.  */
+#if !defined(AVR)
 	    case C_EXTDEF:	/* External definition.  */
+#endif
 	    case C_ULABEL:	/* Undefined label.  */
 	    case C_USTATIC:	/* Undefined static.  */
 #ifndef COFF_WITH_PE
diff -Nur ../binutils-2.18.orig/bfd/coffgen.c ./bfd/coffgen.c
--- ../binutils-2.18.orig/bfd/coffgen.c	Tue Oct 23 21:44:07 2007
+++ ./bfd/coffgen.c	Tue Oct 23 23:07:23 2007
@@ -687,6 +687,20 @@
 	      if (last_file != NULL)
 		last_file->n_value = native_index;
 	      last_file = &(s->u.syment);
+	      if (bfd_get_arch (bfd_ptr) == bfd_arch_avr
+		  && bfd_coff_long_filenames (bfd_ptr)
+		  && s->u.syment.n_numaux > 0)
+		{
+		  /* AVR COFF records long filenames in successive aux
+		     records.  Adjust the number of aux records
+		     required here, so the renumbering will account
+		     for them. */
+		  unsigned int filnmlen = bfd_coff_filnmlen (bfd_ptr);
+		  unsigned int namelen = strlen (coff_symbol_ptr->symbol.name);
+		  unsigned int n = (namelen + filnmlen - 1) / filnmlen;
+
+		  s->u.syment.n_numaux = n > NAUXENTS? NAUXENTS: n;
+		}
 	    }
 	  else
 	    /* Modify the symbol values according to their section and
@@ -815,6 +829,20 @@
 	{
 	  if (name_length <= filnmlen)
 	    strncpy (auxent->x_file.x_fname, name, filnmlen);
+	  else if (bfd_get_arch (abfd) == bfd_arch_avr)
+	    {
+	      /* AVR COFF records long filenames in successive aux records. */
+	      int i = 1;
+	      while (name_length > filnmlen && i < NAUXENTS)
+		{
+		  strncpy (auxent->x_file.x_fname, name, filnmlen);
+		  name += filnmlen;
+		  name_length -= filnmlen;
+		  i++;
+		  auxent = &(native + i)->u.auxent;
+		}
+	      strncpy (auxent->x_file.x_fname, name, filnmlen);
+	    }
 	  else
 	    {
 	      auxent->x_file.x_n.x_offset = *string_size_p + STRING_SIZE_SIZE;
@@ -1218,7 +1246,11 @@
 		  if (bfd_bwrite (".file", (bfd_size_type) 6, abfd) != 6)
 		    return FALSE;
 		}
-	      maxlen = bfd_coff_filnmlen (abfd);
+	      if (bfd_get_arch (abfd) == bfd_arch_avr)
+		/* AVR COFF handles long file names in aux records. */
+		maxlen = name_length;
+	      else
+		maxlen = bfd_coff_filnmlen (abfd);
 	    }
 	  else
 	    maxlen = bfd_coff_force_symnames_in_strings (abfd) ? 0 : SYMNMLEN;
@@ -1655,14 +1687,27 @@
 	    {
 	      /* Ordinary short filename, put into memory anyway.  The
                  Microsoft PE tools sometimes store a filename in
-                 multiple AUX entries.  */
+                 multiple AUX entries.
+		 AVR COFF does it that way, too. */
 	      if (internal_ptr->u.syment.n_numaux > 1
-		  && coff_data (abfd)->pe)
-		internal_ptr->u.syment._n._n_n._n_offset =
-		  ((bfd_hostptr_t)
-		   copy_name (abfd,
-			      (internal_ptr + 1)->u.auxent.x_file.x_fname,
-			      internal_ptr->u.syment.n_numaux * symesz));
+		  && (coff_data (abfd)->pe
+		      || (bfd_get_arch (abfd) == bfd_arch_avr)))
+		{
+		  char *b;
+		  unsigned int i;
+
+		  /* We allocate enough storage to fit the contents of
+		     this many aux records, and simply append a \0.
+		     This ensures the string will always be
+		     terminated, even in the case where it just fit
+		     into the aux records. */
+		  b = (char *) bfd_alloc (abfd,
+					  internal_ptr->u.syment.n_numaux * FILNMLEN + 1);
+		  internal_ptr->u.syment._n._n_n._n_offset = (bfd_hostptr_t) b;
+		  b[internal_ptr->u.syment.n_numaux * FILNMLEN] = '\0';
+		  for (i = 0; i < internal_ptr->u.syment.n_numaux; i++, b += FILNMLEN)
+		    memcpy (b, (internal_ptr + i + 1)->u.auxent.x_file.x_fname, FILNMLEN);
+		}
 	      else
 		internal_ptr->u.syment._n._n_n._n_offset =
 		  ((bfd_hostptr_t)
@@ -1768,9 +1813,9 @@
 
   if (new == NULL)
     return NULL;
-  /* @@ The 10 is a guess at a plausible maximum number of aux entries
-     (but shouldn't be a constant).  */
-  amt = sizeof (combined_entry_type) * 10;
+  /* @@ The NAUXENTS is a guess at a plausible maximum number of aux
+     entries (but shouldn't be a constant).  */
+  amt = sizeof (combined_entry_type) * (NAUXENTS + 1);
   new->native = bfd_zalloc (abfd, amt);
   if (!new->native)
     return NULL;
diff -Nur ../binutils-2.18.orig/bfd/coffswap.h ./bfd/coffswap.h
--- ../binutils-2.18.orig/bfd/coffswap.h	Tue Oct 23 21:44:07 2007
+++ ./bfd/coffswap.h	Tue Oct 23 22:18:44 2007
@@ -383,7 +383,11 @@
 		  void * ext1,
 		  int type,
 		  int class,
-		  int indx,
+		  int indx
+#if defined(AVR) && __GNUC__
+		  __attribute__((unused))
+#endif
+		  ,
 		  int numaux,
 		  void * in1)
 {
@@ -409,9 +413,13 @@
 #else
 	  if (numaux > 1)
 	    {
+#if defined(AVR)
+	      memcpy (in->x_file.x_fname, ext->x_file.x_fname, sizeof (AUXENT));
+#else
 	      if (indx == 0)
 		memcpy (in->x_file.x_fname, ext->x_file.x_fname,
 			numaux * sizeof (AUXENT));
+#endif
 	    }
 	  else
 	    memcpy (in->x_file.x_fname, ext->x_file.x_fname, FILNMLEN);
diff -Nur ../binutils-2.18.orig/bfd/config.bfd ./bfd/config.bfd
--- ../binutils-2.18.orig/bfd/config.bfd	Tue Oct 23 21:44:07 2007
+++ ./bfd/config.bfd	Tue Oct 23 22:18:44 2007
@@ -327,6 +327,7 @@
 
   avr-*-*)
     targ_defvec=bfd_elf32_avr_vec
+    targ_selvecs="bfd_elf32_avr_vec avrcoff_vec avrextcoff_vec"
     ;;
 
   bfin-*-*)
diff -Nur ../binutils-2.18.orig/bfd/configure ./bfd/configure
--- ../binutils-2.18.orig/bfd/configure	Tue Oct 23 21:44:09 2007
+++ ./bfd/configure	Tue Oct 23 22:18:44 2007
@@ -19034,6 +19034,8 @@
     armpe_little_vec)		tb="$tb pe-arm.lo peigen.lo cofflink.lo " ;;
     armpei_big_vec)		tb="$tb pei-arm.lo peigen.lo cofflink.lo " ;;
     armpei_little_vec)		tb="$tb pei-arm.lo peigen.lo cofflink.lo " ;;
+    avrcoff_vec)		tb="$tb coff-avr.lo cofflink.lo " ;;
+    avrextcoff_vec)		tb="$tb coff-ext-avr.lo cofflink.lo " ;;
     b_out_vec_big_host)		tb="$tb bout.lo aout32.lo" ;;
     b_out_vec_little_host)	tb="$tb bout.lo aout32.lo" ;;
     bfd_efi_app_ia32_vec)	tb="$tb efi-app-ia32.lo peigen.lo cofflink.lo" ;;
diff -Nur ../binutils-2.18.orig/bfd/configure.in ./bfd/configure.in
--- ../binutils-2.18.orig/bfd/configure.in	Tue Oct 23 21:44:07 2007
+++ ./bfd/configure.in	Tue Oct 23 22:18:44 2007
@@ -612,6 +612,8 @@
     armpe_little_vec)		tb="$tb pe-arm.lo peigen.lo cofflink.lo " ;;
     armpei_big_vec)		tb="$tb pei-arm.lo peigen.lo cofflink.lo " ;;
     armpei_little_vec)		tb="$tb pei-arm.lo peigen.lo cofflink.lo " ;;
+    avrcoff_vec)		tb="$tb coff-avr.lo cofflink.lo " ;;
+    avrextcoff_vec)		tb="$tb coff-ext-avr.lo cofflink.lo " ;;
     b_out_vec_big_host)		tb="$tb bout.lo aout32.lo" ;;
     b_out_vec_little_host)	tb="$tb bout.lo aout32.lo" ;;
     bfd_efi_app_ia32_vec)	tb="$tb efi-app-ia32.lo peigen.lo cofflink.lo" ;;
diff -Nur ../binutils-2.18.orig/bfd/targets.c ./bfd/targets.c
--- ../binutils-2.18.orig/bfd/targets.c	Tue Oct 23 21:44:09 2007
+++ ./bfd/targets.c	Tue Oct 23 22:18:44 2007
@@ -558,6 +558,8 @@
 extern const bfd_target armpe_little_vec;
 extern const bfd_target armpei_big_vec;
 extern const bfd_target armpei_little_vec;
+extern const bfd_target avrcoff_vec;
+extern const bfd_target avrextcoff_vec;
 extern const bfd_target b_out_vec_big_host;
 extern const bfd_target b_out_vec_little_host;
 extern const bfd_target bfd_efi_app_ia32_vec;
@@ -876,6 +878,8 @@
 	&armpe_little_vec,
 	&armpei_big_vec,
 	&armpei_little_vec,
+	&avrcoff_vec,
+	&avrextcoff_vec,
 	&b_out_vec_big_host,
 	&b_out_vec_little_host,
 	&bfd_efi_app_ia32_vec,
diff -Nur ../binutils-2.18.orig/include/coff/avr.h ./include/coff/avr.h
--- ../binutils-2.18.orig/include/coff/avr.h	Thu Jan  1 01:00:00 1970
+++ ./include/coff/avr.h	Tue Oct 23 22:18:44 2007
@@ -0,0 +1,110 @@
+/* coff information for Atmel AVR.
+   
+   Copyright 2001 Free Software Foundation, Inc.
+
+   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.  */
+
+/* This file was hacked from i860.h */
+
+#define L_LNNO_SIZE 2
+#include "coff/external.h"
+
+/* Bits for f_flags:
+ 	F_RELFLG	relocation info stripped from file
+ 	F_EXEC		file is executable (no unresolved external references)
+ 	F_LNNO		line numbers stripped from file
+ 	F_LSYMS		local symbols stripped from file  */
+
+#define F_RELFLG	(0x0001)
+#define F_EXEC		(0x0002)
+#define F_LNNO		(0x0004)
+#define F_LSYMS		(0x0008)
+/* Upper nibble of flags always needs to be set.  This used to be
+ * undocumented, recent information from Atmel says that bit 7 used to
+ * differentiate between an old vendor-specific deviation of the
+ * format and the current format. */
+#define F_JUNK		(0x00f0)
+#define F_UNUSED	(0xff00)
+
+#define	AVRMAGIC	0xa12
+
+#undef AOUTSZ
+#ifdef AVR_EXT_COFF
+
+/* AVR "extended" COFF format.  This uses the optional header ("a.out"
+   header) to inform the consumer about some additional features that
+   are supported. */
+#define COFF_LONG_FILENAMES yes	/* long filenames supported in consecutive aux entries */
+#define AOUTSZ		28	/* size of optional header in "extended" COFF */
+
+/* Flags in the optional header; they are stored in the vstamp field. */
+#define F_FULLPATHS	0x0001	/* long filenames supported */
+#define F_STRUCTINFO	0x0002	/* structure information contained */
+#define F_PTRINFO	0x0004	/* inter-segment pointers supported */
+
+#else /* old AVR COFF */
+
+#define AOUTSZ		0	/* no a.out for AVR */
+#endif
+
+/* #define AVRAOUTMAGIC	0x406 */ /* "general" magic number of optional header */
+/*
+ * The following magic number causes AVR Studio 4.x to recognize
+ * avr-gcc/GNU binutils produced AVR extended COFF files.  By now,
+ * the only special treatment for them is that the contents of .data
+ * will be appended after .text in the simulator flash.
+ *
+ * 0x9cc has been chosen since it resembles "gcc". ;-)
+ */
+#define AVRAOUTMAGIC	0x9cc	/* "gcc" magic number */
+
+/* By matching not only the magic number, but also the size of the
+   optional a.out header, we can differentiate between both
+   formats. */
+#define AVRBADMAG(x)   ((x).f_magic != AVRMAGIC || (x).f_opthdr != AOUTSZ)
+
+/* AVR COFF has several anomalities in the way the handle the derived
+   type information, and AUX entries, mainly because they apparently
+   didn't bother to learn how COFF is supposed to work before they
+   started.  We fix many of them at the export/import boundary, so all
+   the internal generic COFF handling will work mostly as designed. */
+
+/* NB: these functions are only defined in bfd/coff-avr.c, but also
+   used in coff-ext-avr.c, so the latter can only be configured if the
+   former is also present.  This is certainly always the case
+   anyway. */
+extern void avr_coff_adjust_sym_in_post
+  PARAMS((bfd *, PTR, PTR));
+
+extern void avr_coff_adjust_sym_out_post
+  PARAMS((bfd *, PTR, PTR));
+
+#define COFF_ADJUST_SYM_IN_POST(ABFD, EXT, INT) \
+	avr_coff_adjust_sym_in_post (ABFD, EXT, INT)
+
+#define COFF_ADJUST_SYM_OUT_POST(ABFD, INT, EXT) \
+	avr_coff_adjust_sym_out_post (ABFD, INT, EXT)
+
+/********************** RELOCATION DIRECTIVES **********************/
+
+struct external_reloc
+{
+  char r_vaddr[4];
+  char r_symndx[4];
+  char r_type[2];
+};
+
+#define RELOC struct external_reloc
+#define RELSZ 10
diff -Nur ../binutils-2.18.orig/include/coff/internal.h ./include/coff/internal.h
--- ../binutils-2.18.orig/include/coff/internal.h	Tue Oct 23 21:44:43 2007
+++ ./include/coff/internal.h	Tue Oct 23 22:18:44 2007
@@ -630,6 +630,8 @@
 
 };
 
+#define NAUXENTS 10		/* number of pre-allocated aux entries */
+
 /********************** RELOCATION DIRECTIVES **********************/
 
 struct internal_reloc