summarylogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.SRCINFO37
-rw-r--r--30-binutils-2.17-avr-size.patch404
-rw-r--r--31-binutils-2.17-avr-coff.patch5564
-rw-r--r--50-binutils-2.17-atmega256x.patch2323
-rw-r--r--51-binutils-2.17-newdevices.patch54
-rw-r--r--PKGBUILD116
-rw-r--r--dollarsign.patch49
-rw-r--r--makeinfo411.patch12
-rw-r--r--rfa1-newdevice.patch9
-rw-r--r--rfa1-size.patch11
10 files changed, 8579 insertions, 0 deletions
diff --git a/.SRCINFO b/.SRCINFO
new file mode 100644
index 000000000000..f4591cf831b2
--- /dev/null
+++ b/.SRCINFO
@@ -0,0 +1,37 @@
+pkgbase = binutils-avr-tinyos
+ pkgdesc = A set of programs to assemble and manipulate binary and object files for the avr architecture, with TinyOS patches
+ pkgver = 2.17
+ pkgrel = 1
+ url = http://www.gnu.org/software/binutils/
+ arch = i686
+ arch = x86_64
+ license = GPL
+ makedepends = subversion
+ depends = glibc>=2.12-5
+ depends = zlib
+ provides = binutils-avr
+ options = staticlibs
+ options = !libtool
+ options = !distcc
+ options = !ccache
+ source = http://ftp.gnu.org/gnu/binutils/binutils-2.17.tar.bz2
+ source = 30-binutils-2.17-avr-size.patch
+ source = 31-binutils-2.17-avr-coff.patch
+ source = 50-binutils-2.17-atmega256x.patch
+ source = 51-binutils-2.17-newdevices.patch
+ source = dollarsign.patch
+ source = makeinfo411.patch
+ source = rfa1-newdevice.patch
+ source = rfa1-size.patch
+ sha1sums = 0f5c10d155d7ef67c5eb1261f84e70e2b92293fa
+ sha1sums = 2b5d2e59f69062e12cfcdec05c7a7c1605548b8d
+ sha1sums = 9c7428e902e5064540e0ed51c4c4d39e7516232c
+ sha1sums = a44eb430bc0209b9f1e4d97353de6b3db12748bd
+ sha1sums = 5718008fd59182f828b65fde20d78559a700c5f5
+ sha1sums = cf6f21fc4fc99c5b3ca5a065145619a3ed85960c
+ sha1sums = 04f713709af32d149b77216b6e1419289f57c971
+ sha1sums = 99a0e9ad9206c98b02602bc23dce78238e67399b
+ sha1sums = 87d2de4f04199a8dcd1c10cd3f31a7d8ddfd058b
+
+pkgname = binutils-avr-tinyos
+
diff --git a/30-binutils-2.17-avr-size.patch b/30-binutils-2.17-avr-size.patch
new file mode 100644
index 000000000000..dbdbc1c48b0a
--- /dev/null
+++ b/30-binutils-2.17-avr-size.patch
@@ -0,0 +1,404 @@
+--- binutils/size.c 2005-10-03 13:37:44.000000000 -0600
++++ binutils/size.c 2007-03-30 17:15:44.135375000 -0600
+@@ -33,10 +33,31 @@
+ #include "libiberty.h"
+ #include "getopt.h"
+
+-#ifndef BSD_DEFAULT
+-#define BSD_DEFAULT 1
++typedef enum
++{
++ format_sysv = 0,
++ format_bsd = 1,
++ format_avr = 2,
++} format_type_t;
++
++
++/* Set the default format. */
++#define FORMAT_DEFAULT_SYSV 0
++#define FORMAT_DEFAULT_BSD 1
++#define FORMAT_DEFAULT_AVR 0
++
++#if FORMAT_DEFAULT_SYSV
++ #define FORMAT_DEFAULT format_sysv
++ #define FORMAT_NAME "sysv"
++#elif FORMAT_DEFAULT_BSD
++ #define FORMAT_DEFAULT format_bsd
++ #define FORMAT_NAME "berkeley"
++#elif FORMAT_DEFAULT_AVR
++ #define FORMAT_DEFAULT format_avr
++ #define FORMAT_NAME "avr"
+ #endif
+
++
+ /* Program options. */
+
+ enum
+@@ -45,9 +66,8 @@ enum
+ }
+ radix = decimal;
+
+-/* 0 means use AT&T-style output. */
+-static int berkeley_format = BSD_DEFAULT;
+
++format_type_t format = FORMAT_DEFAULT;
+ int show_version = 0;
+ int show_help = 0;
+ int show_totals = 0;
+@@ -59,6 +79,141 @@ static bfd_size_type total_textsize;
+ /* Program exit status. */
+ int return_code = 0;
+
++
++/* AVR Size specific stuff */
++
++#define AVR64 64UL
++#define AVR128 128UL
++#define AVR256 256UL
++#define AVR512 512UL
++#define AVR1K 1024UL
++#define AVR2K 2048UL
++#define AVR4K 4096UL
++#define AVR8K 8192UL
++#define AVR16K 16384UL
++#define AVR24K 24576UL
++#define AVR32K 32768UL
++#define AVR40K 40960UL
++#define AVR64K 65536UL
++#define AVR128K 131072UL
++#define AVR256K 262144UL
++
++typedef struct
++{
++ char *name;
++ long flash;
++ long ram;
++ long eeprom;
++} avr_device_t;
++
++avr_device_t avr[] =
++{
++ {"atmega2560", AVR256K, AVR8K, AVR4K},
++ {"atmega2561", AVR256K, AVR8K, AVR4K},
++
++ {"at43usb320", AVR128K, 608, 0},
++ {"at90can128", AVR128K, AVR4K, AVR4K},
++ {"at90usb1286", AVR128K, AVR8K, AVR4K},
++ {"at90usb1287", AVR128K, AVR8K, AVR4K},
++ {"atmega128", AVR128K, AVR4K, AVR4K},
++ {"atmega1280", AVR128K, AVR8K, AVR4K},
++ {"atmega1281", AVR128K, AVR8K, AVR4K},
++ {"atmega103", AVR128K, 4000, AVR4K},
++
++ {"at90can64", AVR64K, AVR4K, AVR2K},
++ {"at90usb646", AVR64K, AVR4K, AVR2K},
++ {"at90usb647", AVR64K, AVR4K, AVR2K},
++ {"atmega603", AVR64K, AVR4K, AVR2K},
++ {"atmega64", AVR64K, AVR4K, AVR2K},
++ {"atmega640", AVR64K, AVR8K, AVR4K},
++ {"atmega644", AVR64K, AVR4K, AVR2K},
++ {"atmega644p", AVR64K, AVR4K, AVR2K},
++ {"atmega645", AVR64K, AVR4K, AVR2K},
++ {"atmega6450", AVR64K, AVR4K, AVR2K},
++ {"atmega649", AVR64K, AVR4K, AVR2K},
++ {"atmega6490", AVR64K, AVR4K, AVR2K},
++
++ {"atmega406", AVR40K, AVR512, AVR2K},
++
++ {"at90can32", AVR32K, AVR2K, AVR1K},
++ {"at94k", AVR32K, AVR4K, 0},
++ {"atmega32", AVR32K, AVR2K, AVR1K},
++ {"atmega323", AVR32K, AVR2K, AVR1K},
++ {"atmega324p", AVR32K, AVR2K, AVR1K},
++ {"atmega325", AVR32K, AVR2K, AVR1K},
++ {"atmega325p", AVR32K, AVR2K, AVR1K},
++ {"atmega3250", AVR32K, AVR2K, AVR1K},
++ {"atmega3250p", AVR32K, AVR2K, AVR1K},
++ {"atmega329", AVR32K, AVR2K, AVR1K},
++ {"atmega329p", AVR32K, AVR2K, AVR1K},
++ {"atmega3290", AVR32K, AVR2K, AVR1K},
++ {"atmega3290p", AVR32K, AVR2K, AVR1K},
++
++ {"at43usb355", AVR24K, 1120, 0},
++
++ {"at76c711", AVR16K, AVR2K, 0},
++ {"at90usb162", AVR16K, AVR512, AVR512},
++ {"atmega16", AVR16K, AVR1K, AVR512},
++ {"atmega161", AVR16K, AVR1K, AVR512},
++ {"atmega162", AVR16K, AVR1K, AVR512},
++ {"atmega163", AVR16K, AVR1K, AVR512},
++ {"atmega164", AVR16K, AVR1K, AVR512},
++ {"atmega164p", AVR16K, AVR1K, AVR512},
++ {"atmega165", AVR16K, AVR1K, AVR512},
++ {"atmega165p", AVR16K, AVR1K, AVR512},
++ {"atmega168", AVR16K, AVR1K, AVR512},
++ {"atmega169", AVR16K, AVR1K, AVR512},
++ {"atmega169p", AVR16K, AVR1K, AVR512},
++
++ {"at90c8534", AVR8K, 352, AVR512},
++ {"at90pwm1", AVR8K, AVR512, AVR512},
++ {"at90pwm2", AVR8K, AVR512, AVR512},
++ {"at90pwm3", AVR8K, AVR512, AVR512},
++ {"at90s8515", AVR8K, AVR512, AVR512},
++ {"at90s8535", AVR8K, AVR512, AVR512},
++ {"at90usb82", AVR8K, AVR512, AVR512},
++ {"atmega8", AVR8K, AVR1K, AVR512},
++ {"atmega83", AVR8K, AVR1K, AVR512},
++ {"atmega85", AVR8K, AVR1K, AVR512},
++ {"atmega8515", AVR8K, AVR512, AVR512},
++ {"atmega8535", AVR8K, AVR512, AVR512},
++ {"atmega88", AVR8K, AVR1K, AVR512},
++ {"attiny84", AVR8K, AVR512, AVR512},
++ {"attiny85", AVR8K, AVR512, AVR512},
++ {"attiny861", AVR8K, AVR512, AVR512},
++
++ {"at90s4414", AVR4K, 352, AVR256},
++ {"at90s4433", AVR4K, AVR128, AVR256},
++ {"at90s4434", AVR4K, 352, AVR256},
++ {"atmega48", AVR4K, AVR512, AVR256},
++ {"attiny44", AVR4K, AVR256, AVR256},
++ {"attiny45", AVR4K, AVR256, AVR256},
++ {"attiny461", AVR4K, AVR256, AVR256},
++
++ {"at86rf401", AVR2K, 224, AVR128},
++ {"at90s2313", AVR2K, AVR128, AVR128},
++ {"at90s2323", AVR2K, AVR128, AVR128},
++ {"at90s2333", AVR2K, 224, AVR128},
++ {"at90s2343", AVR2K, AVR128, AVR128},
++ {"attiny22", AVR2K, 224, AVR128},
++ {"attiny2313", AVR2K, AVR128, AVR128},
++ {"attiny24", AVR2K, AVR128, AVR128},
++ {"attiny25", AVR2K, AVR128, AVR128},
++ {"attiny26", AVR2K, AVR128, AVR128},
++ {"attiny261", AVR2K, AVR128, AVR128},
++ {"attiny28", AVR2K, 0, 0},
++
++ {"at90s1200", AVR1K, 0, AVR64},
++ {"attiny10", AVR1K, 0, AVR64},
++ {"attiny11", AVR1K, 0, AVR64},
++ {"attiny12", AVR1K, 0, AVR64},
++ {"attiny13", AVR1K, AVR64, AVR64},
++ {"attiny15", AVR1K, 0, AVR64},
++};
++
++static char *avrmcu = NULL;
++
++
+ static char *target = NULL;
+
+ /* Static declarations. */
+@@ -83,7 +238,8 @@ usage (FILE *stream, int status)
+ fprintf (stream, _(" Displays the sizes of sections inside binary files\n"));
+ fprintf (stream, _(" If no input file(s) are specified, a.out is assumed\n"));
+ fprintf (stream, _(" The options are:\n\
+- -A|-B --format={sysv|berkeley} Select output style (default is %s)\n\
++ -A|-B|-C --format={sysv|berkeley|avr} Select output style (default is %s)\n\
++ --mcu=<avrmcu> MCU name for AVR format only\n\
+ -o|-d|-x --radix={8|10|16} Display numbers in octal, decimal or hex\n\
+ -t --totals Display the total sizes (Berkeley only)\n\
+ --target=<bfdname> Set the binary file format\n\
+@@ -91,11 +247,7 @@ usage (FILE *stream, int status)
+ -h --help Display this information\n\
+ -v --version Display the program's version\n\
+ \n"),
+-#if BSD_DEFAULT
+- "berkeley"
+-#else
+- "sysv"
+-#endif
++FORMAT_NAME
+ );
+ list_supported_targets (program_name, stream);
+ if (status == 0)
+@@ -108,6 +260,7 @@ static struct option long_options[] =
+ {"format", required_argument, 0, 200},
+ {"radix", required_argument, 0, 201},
+ {"target", required_argument, 0, 202},
++ {"mcu", required_argument, 0, 203},
+ {"totals", no_argument, &show_totals, 1},
+ {"version", no_argument, &show_version, 1},
+ {"help", no_argument, &show_help, 1},
+@@ -139,7 +292,7 @@ main (int argc, char **argv)
+ bfd_init ();
+ set_default_bfd_target ();
+
+- while ((c = getopt_long (argc, argv, "ABHhVvdfotx", long_options,
++ while ((c = getopt_long (argc, argv, "ABCHhVvdfotx", long_options,
+ (int *) 0)) != EOF)
+ switch (c)
+ {
+@@ -148,11 +301,15 @@ main (int argc, char **argv)
+ {
+ case 'B':
+ case 'b':
+- berkeley_format = 1;
++ format = format_bsd;
+ break;
+ case 'S':
+ case 's':
+- berkeley_format = 0;
++ format = format_sysv;
++ break;
++ case 'A':
++ case 'a':
++ format = format_avr;
+ break;
+ default:
+ non_fatal (_("invalid argument to --format: %s"), optarg);
+@@ -160,6 +317,10 @@ main (int argc, char **argv)
+ }
+ break;
+
++ case 203: /* --mcu */
++ avrmcu = optarg;
++ break;
++
+ case 202: /* --target */
+ target = optarg;
+ break;
+@@ -188,11 +349,14 @@ main (int argc, char **argv)
+ break;
+
+ case 'A':
+- berkeley_format = 0;
++ format = format_sysv;
+ break;
+ case 'B':
+- berkeley_format = 1;
++ format = format_bsd;
+ break;
++ case 'C':
++ format = format_avr;
++ break;
+ case 'v':
+ case 'V':
+ show_version = 1;
+@@ -238,7 +402,7 @@ main (int argc, char **argv)
+ for (; optind < argc;)
+ display_file (argv[optind++]);
+
+- if (show_totals && berkeley_format)
++ if (show_totals && format == format_bsd)
+ {
+ bfd_size_type total = total_textsize + total_datasize + total_bsssize;
+
+@@ -542,11 +706,115 @@ print_sysv_format (bfd *file)
+ printf ("\n\n");
+ }
+
++
++static avr_device_t *
++avr_find_device (void)
++{
++ unsigned int i;
++ if (avrmcu != NULL)
++ {
++ for (i = 0; i < sizeof(avr) / sizeof(avr[0]); i++)
++ {
++ if (strcmp(avr[i].name, avrmcu) == 0)
++ {
++ /* Match found */
++ return (&avr[i]);
++ }
++ }
++ }
++ return (NULL);
++}
++
++
++
++static void
++print_avr_format (bfd *file)
++{
++ char *avr_name = "Unknown";
++ int flashmax = 0;
++ int rammax = 0;
++ int eeprommax = 0;
++ asection *section;
++ bfd_size_type datasize = 0;
++ bfd_size_type textsize = 0;
++ bfd_size_type bsssize = 0;
++ bfd_size_type bootloadersize = 0;
++ bfd_size_type noinitsize = 0;
++ bfd_size_type eepromsize = 0;
++
++ avr_device_t *avrdevice = avr_find_device();
++ if (avrdevice != NULL)
++ {
++ avr_name = avrdevice->name;
++ flashmax = avrdevice->flash;
++ rammax = avrdevice->ram;
++ eeprommax = avrdevice->eeprom;
++ }
++
++ if ((section = bfd_get_section_by_name (file, ".data")) != NULL)
++ datasize = bfd_section_size (file, section);
++ if ((section = bfd_get_section_by_name (file, ".text")) != NULL)
++ textsize = bfd_section_size (file, section);
++ if ((section = bfd_get_section_by_name (file, ".bss")) != NULL)
++ bsssize = bfd_section_size (file, section);
++ if ((section = bfd_get_section_by_name (file, ".bootloader")) != NULL)
++ bootloadersize = bfd_section_size (file, section);
++ if ((section = bfd_get_section_by_name (file, ".noinit")) != NULL)
++ noinitsize = bfd_section_size (file, section);
++ if ((section = bfd_get_section_by_name (file, ".eeprom")) != NULL)
++ eepromsize = bfd_section_size (file, section);
++
++ bfd_size_type text = textsize + datasize + bootloadersize;
++ bfd_size_type data = datasize + bsssize + noinitsize;
++ bfd_size_type eeprom = eepromsize;
++
++ printf ("AVR Memory Usage\n"
++ "----------------\n"
++ "Device: %s\n\n", avr_name);
++
++ /* Text size */
++ printf ("Program:%8ld bytes", text);
++ if (flashmax > 0)
++ {
++ printf (" (%2.1f%% Full)", ((float)text / flashmax) * 100);
++ }
++ printf ("\n(.text + .data + .bootloader)\n\n");
++
++ /* Data size */
++ printf ("Data: %8ld bytes", data);
++ if (rammax > 0)
++ {
++ printf (" (%2.1f%% Full)", ((float)data / rammax) * 100);
++ }
++ printf ("\n(.data + .bss + .noinit)\n\n");
++
++ /* EEPROM size */
++ if (eeprom > 0)
++ {
++ printf ("EEPROM: %8ld bytes", eeprom);
++ if (eeprommax > 0)
++ {
++ printf (" (%2.1f%% Full)", ((float)eeprom / eeprommax) * 100);
++ }
++ printf ("\n(.eeprom)\n\n");
++ }
++}
++
++
+ static void
+ print_sizes (bfd *file)
+ {
+- if (berkeley_format)
+- print_berkeley_format (file);
+- else
+- print_sysv_format (file);
++ switch (format)
++ {
++ case format_sysv:
++ print_sysv_format (file);
++ break;
++ case format_bsd:
++ print_berkeley_format (file);
++ break;
++ case format_avr:
++ default:
++ print_avr_format (file);
++ break;
++ }
+ }
diff --git a/31-binutils-2.17-avr-coff.patch b/31-binutils-2.17-avr-coff.patch
new file mode 100644
index 000000000000..dc7759f917f1
--- /dev/null
+++ b/31-binutils-2.17-avr-coff.patch
@@ -0,0 +1,5564 @@
+--- ./binutils/doc/objcopy.1.orig Fri Jun 23 20:19:49 2006
++++ ./binutils/doc/objcopy.1 Tue Sep 26 00:25:05 2006
+@@ -190,6 +190,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]
+@@ -745,6 +747,23 @@
+ full executable. It does not have to be a file created by the
+ \&\fB\-\-only\-keep\-debug\fR switch.
+ .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
+--- ./binutils/Makefile.am.orig Thu Apr 6 23:49:26 2006
++++ ./binutils/Makefile.am Tue Sep 26 00:25:05 2006
+@@ -97,14 +97,14 @@
+ rdcoff.c rddbg.c readelf.c rename.c \
+ resbin.c rescoff.c resrc.c resres.c \
+ size.c srconv.c stabs.c strings.c sysdump.c version.c \
+- windres.c winduni.c wrstabs.c
++ windres.c winduni.c wrcoff.c wrstabs.c
+
+ GENERATED_CFILES = \
+ arparse.c arlex.c sysroff.c sysinfo.c syslex.c \
+ defparse.c deflex.c nlmheader.c rcparse.c rclex.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
+--- ./binutils/Makefile.in.orig Fri Jun 2 04:21:08 2006
++++ ./binutils/Makefile.in Tue Sep 26 00:25:05 2006
+@@ -133,7 +133,7 @@
+ nm_new_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \
+ $(am__DEPENDENCIES_3)
+ 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)
+@@ -424,14 +424,14 @@
+ rdcoff.c rddbg.c readelf.c rename.c \
+ resbin.c rescoff.c resrc.c resres.c \
+ size.c srconv.c stabs.c strings.c sysdump.c version.c \
+- windres.c winduni.c wrstabs.c
++ windres.c winduni.c wrcoff.c wrstabs.c
+
+ GENERATED_CFILES = \
+ arparse.c arlex.c sysroff.c sysinfo.c syslex.c \
+ defparse.c deflex.c nlmheader.c rcparse.c rclex.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
+--- ./binutils/bucomm.c.orig Mon Mar 13 23:27:22 2006
++++ ./binutils/bucomm.c Tue Sep 26 00:25:05 2006
+@@ -452,6 +452,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. */
+--- ./binutils/bucomm.h.orig Thu Feb 9 12:49:53 2006
++++ ./binutils/bucomm.h Tue Sep 26 00:25:05 2006
+@@ -205,6 +205,8 @@
+
+ off_t get_file_size (const char *);
+
++const char *bu_basename PARAMS ((const char *));
++
+ extern char *program_name;
+
+ /* filemode.c */
+--- ./binutils/budbg.h.orig Sun May 8 16:17:38 2005
++++ ./binutils/budbg.h Tue Sep 26 00:25:05 2006
+@@ -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 Sun May 8 16:17:38 2005
++++ ./binutils/debug.c Tue Sep 26 00:25:05 2006
+@@ -553,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 *);
+@@ -589,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. */
+
+@@ -681,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);
+@@ -721,6 +741,8 @@
+
+ if (name == NULL)
+ name = "";
++ else
++ name = debug_xlat_pathname (name);
+
+ if (info->current_unit == NULL)
+ {
+@@ -3370,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;
+ }
+--- ./binutils/debug.h.orig Sun May 8 16:17:38 2005
++++ ./binutils/debug.h Tue Sep 26 00:25:05 2006
+@@ -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.
+--- ./binutils/objcopy.c.orig Tue Feb 28 17:09:01 2006
++++ ./binutils/objcopy.c Tue Sep 26 00:25:14 2006
+@@ -31,6 +31,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
+@@ -257,7 +258,9 @@
+ OPTION_READONLY_TEXT,
+ OPTION_WRITABLE_TEXT,
+ OPTION_PURE,
+- OPTION_IMPURE
++ OPTION_IMPURE,
++ OPTION_CHANGE_PATHNAME,
++ OPTION_BASENAME
+ };
+
+ /* Options to handle if running as "strip". */
+@@ -301,10 +304,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},
+@@ -483,6 +488,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\
+@@ -821,6 +828,8 @@
+ long src_count = 0, dst_count = 0;
+ int relocatable = (abfd->flags & (HAS_RELOC | EXEC_P | DYNAMIC))
+ == HAS_RELOC;
++ bfd_boolean need_for_debugging = convert_debugging
++ && bfd_get_arch (abfd) == bfd_arch_avr;
+
+ for (; src_count < symcount; src_count++)
+ {
+@@ -916,9 +925,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. */
+@@ -2417,6 +2427,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;
+@@ -3096,6 +3110,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:
+--- ./binutils/rdcoff.c.orig Sun May 8 16:17:39 2005
++++ ./binutils/rdcoff.c Tue Sep 26 00:25:05 2006
+@@ -80,6 +80,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);
+@@ -99,6 +102,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. */
+
+@@ -269,8 +273,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;
+
+@@ -285,7 +288,7 @@
+ break;
+
+ case T_DOUBLE:
+- ret = debug_make_float_type (dhandle, 8);
++ ret = debug_make_float_type (dhandle, types->doublesize);
+ name = "double";
+ break;
+
+@@ -305,7 +308,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;
+
+@@ -563,6 +566,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;
+@@ -578,9 +583,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;
+
+@@ -594,9 +599,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;
+
+@@ -646,6 +651,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. */
+
+@@ -672,6 +699,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;
+@@ -732,7 +770,6 @@
+ switch (syment.n_sclass)
+ {
+ case C_EFCN:
+- case C_EXTDEF:
+ case C_ULABEL:
+ case C_USTATIC:
+ case C_LINE:
+@@ -755,6 +792,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;
+--- ./binutils/wrcoff.c.orig Tue Sep 26 00:25:05 2006
++++ ./binutils/wrcoff.c Tue Sep 26 00:25:05 2006
+@@ -0,0 +1,3409 @@
++/* 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 "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;
++}
+--- ./bfd/Makefile.am.orig Fri Jun 23 20:17:17 2006
++++ ./bfd/Makefile.am Tue Sep 26 00:25:05 2006
+@@ -199,6 +199,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 \
+@@ -371,6 +373,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 \
+@@ -934,10 +938,10 @@
+ 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)\"" ;\
+ 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)\"" ;\
+ fi ;\
+ sed -e "s/@bfd_version@/$$bfd_version/" -e "s/@bfd_version_string@/$$bfd_version_string/" < $(srcdir)/version.h > $@
+
+@@ -1129,6 +1133,12 @@
+ $(INCDIR)/coff/internal.h $(INCDIR)/coff/m68k.h $(INCDIR)/coff/external.h \
+ coff-m68k.c $(INCDIR)/hashtab.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 \
+--- ./bfd/Makefile.in.orig Fri Jun 23 20:17:19 2006
++++ ./bfd/Makefile.in Tue Sep 26 00:25:05 2006
+@@ -436,6 +436,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 \
+@@ -608,6 +610,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 \
+@@ -1500,10 +1504,10 @@
+ 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)\"" ;\
+ 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)\"" ;\
+ fi ;\
+ sed -e "s/@bfd_version@/$$bfd_version/" -e "s/@bfd_version_string@/$$bfd_version_string/" < $(srcdir)/version.h > $@
+
+@@ -1695,6 +1699,12 @@
+ $(INCDIR)/coff/internal.h $(INCDIR)/coff/m68k.h $(INCDIR)/coff/external.h \
+ coff-m68k.c $(INCDIR)/hashtab.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 \
+--- ./bfd/coff-avr.c.orig Tue Sep 26 00:25:05 2006
++++ ./bfd/coff-avr.c Tue Sep 26 00:25:05 2006
+@@ -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
++};
+--- ./bfd/coff-ext-avr.c.orig Tue Sep 26 00:25:05 2006
++++ ./bfd/coff-ext-avr.c Tue Sep 26 00:25:05 2006
+@@ -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
++};
+--- ./bfd/coffcode.h.orig Tue Oct 25 19:40:09 2005
++++ ./bfd/coffcode.h Tue Sep 26 00:25:05 2006
+@@ -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
+@@ -1760,6 +1761,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;
+@@ -1784,17 +1796,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) =
+@@ -1915,6 +1916,11 @@
+ }
+ break;
+ #endif
++#ifdef AVRMAGIC
++ case AVRMAGIC:
++ arch = bfd_arch_avr;
++ break;
++#endif
+ #ifdef MC68MAGIC
+ case MC68MAGIC:
+ case M68MAGIC:
+@@ -2707,6 +2713,13 @@
+ return TRUE;
+ #endif
+
++#ifdef AVRMAGIC
++ case bfd_arch_avr:
++ *magicp = AVRMAGIC;
++ return TRUE;
++ break;
++#endif
++
+ #ifdef PPCMAGIC
+ case bfd_arch_powerpc:
+ *magicp = PPCMAGIC;
+@@ -3498,6 +3511,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
+@@ -3840,6 +3858,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;
+@@ -3905,8 +3934,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;
+@@ -4092,22 +4129,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
+@@ -4388,6 +4432,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:
+@@ -4611,7 +4659,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
+--- ./bfd/coffgen.c.orig Mon May 23 19:44:52 2005
++++ ./bfd/coffgen.c Tue Sep 26 00:25:05 2006
+@@ -682,6 +682,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
+@@ -810,6 +824,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;
+@@ -1213,7 +1241,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;
+@@ -1648,14 +1680,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 =
+- ((long)
+- 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 = (long) 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 =
+ ((long)
+@@ -1761,9 +1806,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;
+--- ./bfd/coffswap.h.orig Wed May 4 17:53:05 2005
++++ ./bfd/coffswap.h Tue Sep 26 00:25:05 2006
+@@ -382,7 +382,11 @@
+ void * ext1,
+ int type,
+ int class,
+- int indx,
++ int indx
++#if defined(AVR) && __GNUC__
++ __attribute__((unused))
++#endif
++ ,
+ int numaux,
+ void * in1)
+ {
+@@ -408,9 +412,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);
+--- ./bfd/config.bfd.orig Wed Apr 5 14:41:57 2006
++++ ./bfd/config.bfd Tue Sep 26 00:25:05 2006
+@@ -309,6 +309,7 @@
+
+ avr-*-*)
+ targ_defvec=bfd_elf32_avr_vec
++ targ_selvecs="bfd_elf32_avr_vec avrcoff_vec avrextcoff_vec"
+ ;;
+
+ bfin-*-*)
+--- ./bfd/configure.orig Fri Jun 23 20:17:03 2006
++++ ./bfd/configure Tue Sep 26 00:25:05 2006
+@@ -13064,6 +13064,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" ;;
+--- ./bfd/configure.in.orig Fri Jun 23 20:17:07 2006
++++ ./bfd/configure.in Tue Sep 26 00:25:05 2006
+@@ -577,6 +577,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" ;;
+--- ./bfd/targets.c.orig Wed Apr 5 14:41:57 2006
++++ ./bfd/targets.c Tue Sep 26 00:25:05 2006
+@@ -548,6 +548,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;
+@@ -848,6 +850,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,
+--- ./include/coff/avr.h.orig Tue Sep 26 00:25:05 2006
++++ ./include/coff/avr.h Tue Sep 26 00:25:06 2006
+@@ -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
+--- ./include/coff/internal.h.orig Sun Feb 5 12:57:34 2006
++++ ./include/coff/internal.h Tue Sep 26 00:25:06 2006
+@@ -592,6 +592,8 @@
+
+ };
+
++#define NAUXENTS 10 /* number of pre-allocated aux entries */
++
+ /********************** RELOCATION DIRECTIVES **********************/
+
+ struct internal_reloc
diff --git a/50-binutils-2.17-atmega256x.patch b/50-binutils-2.17-atmega256x.patch
new file mode 100644
index 000000000000..ddc6e19c82c3
--- /dev/null
+++ b/50-binutils-2.17-atmega256x.patch
@@ -0,0 +1,2323 @@
+diff -Nur bfd/archures.c bfd/archures.c
+--- bfd/archures.c 2006-03-06 14:42:03.000000000 +0100
++++ bfd/archures.c 2006-08-28 20:01:10.714097550 +0200
+@@ -334,6 +334,7 @@
+ .#define bfd_mach_avr3 3
+ .#define bfd_mach_avr4 4
+ .#define bfd_mach_avr5 5
++.#define bfd_mach_avr6 6
+ . bfd_arch_bfin, {* ADI Blackfin *}
+ .#define bfd_mach_bfin 1
+ . bfd_arch_cr16c, {* National Semiconductor CompactRISC. *}
+diff -Nur bfd/bfd-in2.h bfd/bfd-in2.h
+--- bfd/bfd-in2.h 2006-03-26 01:38:42.000000000 +0100
++++ bfd/bfd-in2.h 2006-08-28 20:01:10.743095447 +0200
+@@ -1931,6 +1931,7 @@
+ #define bfd_mach_avr3 3
+ #define bfd_mach_avr4 4
+ #define bfd_mach_avr5 5
++#define bfd_mach_avr6 6
+ bfd_arch_bfin, /* ADI Blackfin */
+ #define bfd_mach_bfin 1
+ bfd_arch_cr16c, /* National Semiconductor CompactRISC. */
+@@ -3539,10 +3540,22 @@
+ command address) into 8 bit immediate value of LDI insn. */
+ BFD_RELOC_AVR_LO8_LDI_PM,
+
++/* This is a 16 bit reloc for the AVR that stores 8 bit value
++(command address) into 8 bit immediate value of LDI insn. If the address
++is beyond the 128k boundary, the linker inserts a jump stub for this reloc
++in the lower 128k. */
++ BFD_RELOC_AVR_LO8_LDI_GS,
++
+ /* This is a 16 bit reloc for the AVR that stores 8 bit value (high 8 bit
+ of command address) into 8 bit immediate value of LDI insn. */
+ BFD_RELOC_AVR_HI8_LDI_PM,
+
++/* This is a 16 bit reloc for the AVR that stores 8 bit value (high 8 bit
++of command address) into 8 bit immediate value of LDI insn. If the address
++is beyond the 128k boundary, the linker inserts a jump stub for this reloc
++below 128k. */
++ BFD_RELOC_AVR_HI8_LDI_GS,
++
+ /* This is a 16 bit reloc for the AVR that stores 8 bit value (most high 8 bit
+ of command address) into 8 bit immediate value of LDI insn. */
+ BFD_RELOC_AVR_HH8_LDI_PM,
+diff -Nur bfd/cpu-avr.c bfd/cpu-avr.c
+--- bfd/cpu-avr.c 2006-03-03 16:54:23.000000000 +0100
++++ bfd/cpu-avr.c 2006-08-28 20:01:10.771093417 +0200
+@@ -82,7 +82,10 @@
+ N (16, bfd_mach_avr4, "avr:4", FALSE, & arch_info_struct[4]),
+
+ /* ATmega161, ATmega163, ATmega32, AT94K. */
+- N (22, bfd_mach_avr5, "avr:5", FALSE, NULL)
++ N (22, bfd_mach_avr5, "avr:5", FALSE, & arch_info_struct[5]),
++
++ /* ATmega256x. */
++ N (22, bfd_mach_avr6, "avr:6", FALSE, NULL)
+ };
+
+ const bfd_arch_info_type bfd_avr_arch =
+diff -Nur bfd/elf32-avr.c bfd/elf32-avr.c
+--- bfd/elf32-avr.c 2006-03-03 16:54:23.000000000 +0100
++++ bfd/elf32-avr.c 2006-08-28 20:18:20.796399347 +0200
+@@ -25,6 +25,92 @@
+ #include "libbfd.h"
+ #include "elf-bfd.h"
+ #include "elf/avr.h"
++#include "elf32-avr.h"
++
++/* Enable debugging printout at stdout with this variable. */
++static bfd_boolean debug_relax = FALSE;
++
++/* Enable debugging printout at stdout with this variable. */
++static bfd_boolean debug_stubs = FALSE;
++
++/* Hash table initialization and handling. Code is taken from the hppa port
++ and adapted to the needs of AVR. */
++
++/* We use two hash tables to hold information for linking avr objects.
++
++ The first is the elf32_avr_link_hash_tablse which is derived from the
++ stanard ELF linker hash table. We use this as a place to attach the other
++ hash table and some static information.
++
++ The second is the stub hash table which is derived from the base BFD
++ hash table. The stub hash table holds the information on the linker
++ stubs. */
++
++struct elf32_avr_stub_hash_entry
++{
++ /* Base hash table entry structure. */
++ struct bfd_hash_entry bh_root;
++
++ /* Offset within stub_sec of the beginning of this stub. */
++ bfd_vma stub_offset;
++
++ /* Given the symbol's value and its section we can determine its final
++ value when building the stubs (so the stub knows where to jump). */
++ bfd_vma target_value;
++
++ /* This way we could mark stubs to be no longer necessary. */
++ bfd_boolean is_actually_needed;
++};
++
++struct elf32_avr_link_hash_table
++{
++ /* The main hash table. */
++ struct elf_link_hash_table etab;
++
++ /* The stub hash table. */
++ struct bfd_hash_table bstab;
++
++ bfd_boolean no_stubs;
++
++ /* Linker stub bfd. */
++ bfd *stub_bfd;
++
++ /* The stub section. */
++ asection *stub_sec;
++
++ /* Usually 0, unless we are generating code for a bootloader. Will
++ be initialized by elf32_avr_size_stubs to the vma offset of the
++ output section associated with the stub section. */
++ bfd_vma vector_base;
++
++ /* Assorted information used by elf32_avr_size_stubs. */
++ unsigned int bfd_count;
++ int top_index;
++ asection ** input_list;
++ Elf_Internal_Sym ** all_local_syms;
++
++ /* Tables for mapping vma beyond the 128k boundary to the address of the
++ corresponding stub. (AMT)
++ "amt_max_entry_cnt" reflects the number of entries that memory is allocated
++ for in the "amt_stub_offsets" and "amt_destination_addr" arrays.
++ "amt_entry_cnt" informs how many of these entries actually contain
++ useful data. */
++ unsigned int amt_entry_cnt;
++ unsigned int amt_max_entry_cnt;
++ bfd_vma * amt_stub_offsets;
++ bfd_vma * amt_destination_addr;
++};
++
++/* Various hash macros and functions. */
++#define avr_link_hash_table(p) \
++ ((struct elf32_avr_link_hash_table *) ((p)->hash))
++
++#define avr_stub_hash_entry(ent) \
++ ((struct elf32_avr_stub_hash_entry *)(ent))
++
++#define avr_stub_hash_lookup(table, string, create, copy) \
++ ((struct elf32_avr_stub_hash_entry *) \
++ bfd_hash_lookup ((table), (string), (create), (copy)))
+
+ static reloc_howto_type elf_avr_howto_table[] =
+ {
+@@ -101,7 +187,8 @@
+ 0xffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+- /* A 16 bit absolute relocation for command address. */
++ /* A 16 bit absolute relocation for command address
++ Will be changed when linker stubs are needed. */
+ HOWTO (R_AVR_16_PM, /* type */
+ 1, /* rightshift */
+ 1, /* size (0 = byte, 1 = short, 2 = long) */
+@@ -207,7 +294,7 @@
+ 0xffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+ /* A low 8 bit absolute relocation of 24 bit program memory address.
+- For LDI command. */
++ For LDI command. Will not be changed when linker stubs are needed. */
+ HOWTO (R_AVR_LO8_LDI_PM, /* type */
+ 1, /* rightshift */
+ 1, /* size (0 = byte, 1 = short, 2 = long) */
+@@ -221,8 +308,8 @@
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+- /* A high 8 bit absolute relocation of 16 bit program memory address.
+- For LDI command. */
++ /* A low 8 bit absolute relocation of 24 bit program memory address.
++ For LDI command. Will not be changed when linker stubs are needed. */
+ HOWTO (R_AVR_HI8_LDI_PM, /* type */
+ 9, /* rightshift */
+ 1, /* size (0 = byte, 1 = short, 2 = long) */
+@@ -236,8 +323,8 @@
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+- /* A high 8 bit absolute relocation of 24 bit program memory address.
+- For LDI command. */
++ /* A low 8 bit absolute relocation of 24 bit program memory address.
++ For LDI command. Will not be changed when linker stubs are needed. */
+ HOWTO (R_AVR_HH8_LDI_PM, /* type */
+ 17, /* rightshift */
+ 1, /* size (0 = byte, 1 = short, 2 = long) */
+@@ -251,8 +338,8 @@
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+- /* A low 8 bit absolute relocation of a negative 24 bit
+- program memory address. For LDI command. */
++ /* A low 8 bit absolute relocation of 24 bit program memory address.
++ For LDI command. Will not be changed when linker stubs are needed. */
+ HOWTO (R_AVR_LO8_LDI_PM_NEG, /* type */
+ 1, /* rightshift */
+ 1, /* size (0 = byte, 1 = short, 2 = long) */
+@@ -266,8 +353,8 @@
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+- /* A high 8 bit absolute relocation of a negative 16 bit
+- program memory address. For LDI command. */
++ /* A low 8 bit absolute relocation of 24 bit program memory address.
++ For LDI command. Will not be changed when linker stubs are needed. */
+ HOWTO (R_AVR_HI8_LDI_PM_NEG, /* type */
+ 9, /* rightshift */
+ 1, /* size (0 = byte, 1 = short, 2 = long) */
+@@ -281,8 +368,8 @@
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+- /* A high 8 bit absolute relocation of a negative 24 bit
+- program memory address. For LDI command. */
++ /* A low 8 bit absolute relocation of 24 bit program memory address.
++ For LDI command. Will not be changed when linker stubs are needed. */
+ HOWTO (R_AVR_HH8_LDI_PM_NEG, /* type */
+ 17, /* rightshift */
+ 1, /* size (0 = byte, 1 = short, 2 = long) */
+@@ -382,7 +469,37 @@
+ FALSE, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+- FALSE) /* pcrel_offset */
++ FALSE), /* pcrel_offset */
++ /* A low 8 bit absolute relocation of 24 bit program memory address.
++ For LDI command. Will be changed when linker stubs are needed. */
++ HOWTO (R_AVR_LO8_LDI_GS, /* type */
++ 1, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 8, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_AVR_LO8_LDI_GS", /* name */
++ FALSE, /* partial_inplace */
++ 0xffff, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE), /* pcrel_offset */
++ /* A low 8 bit absolute relocation of 24 bit program memory address.
++ For LDI command. Will be changed when linker stubs are needed. */
++ HOWTO (R_AVR_HI8_LDI_GS, /* type */
++ 9, /* rightshift */
++ 1, /* size (0 = byte, 1 = short, 2 = long) */
++ 8, /* bitsize */
++ FALSE, /* pc_relative */
++ 0, /* bitpos */
++ complain_overflow_dont, /* complain_on_overflow */
++ bfd_elf_generic_reloc, /* special_function */
++ "R_AVR_HI8_LDI_GS", /* name */
++ FALSE, /* partial_inplace */
++ 0xffff, /* src_mask */
++ 0xffff, /* dst_mask */
++ FALSE) /* pcrel_offset */
+ };
+
+ /* Map BFD reloc types to AVR ELF reloc types. */
+@@ -393,7 +510,7 @@
+ unsigned int elf_reloc_val;
+ };
+
+- static const struct avr_reloc_map avr_reloc_map[] =
++static const struct avr_reloc_map avr_reloc_map[] =
+ {
+ { BFD_RELOC_NONE, R_AVR_NONE },
+ { BFD_RELOC_32, R_AVR_32 },
+@@ -410,7 +527,9 @@
+ { BFD_RELOC_AVR_HH8_LDI_NEG, R_AVR_HH8_LDI_NEG },
+ { BFD_RELOC_AVR_MS8_LDI_NEG, R_AVR_MS8_LDI_NEG },
+ { BFD_RELOC_AVR_LO8_LDI_PM, R_AVR_LO8_LDI_PM },
++ { BFD_RELOC_AVR_LO8_LDI_GS, R_AVR_LO8_LDI_GS },
+ { BFD_RELOC_AVR_HI8_LDI_PM, R_AVR_HI8_LDI_PM },
++ { BFD_RELOC_AVR_HI8_LDI_GS, R_AVR_HI8_LDI_GS },
+ { BFD_RELOC_AVR_HH8_LDI_PM, R_AVR_HH8_LDI_PM },
+ { BFD_RELOC_AVR_LO8_LDI_PM_NEG, R_AVR_LO8_LDI_PM_NEG },
+ { BFD_RELOC_AVR_HI8_LDI_PM_NEG, R_AVR_HI8_LDI_PM_NEG },
+@@ -429,8 +548,101 @@
+ that we will never suggest a wrap-around jump during relaxation.
+ The logic of the source code later on assumes that in
+ avr_pc_wrap_around one single bit is set. */
++static bfd_vma avr_pc_wrap_around = 0x10000000;
++
++/* If this variable holds a value different from zero, the linker relaxation
++ machine will try to optimize call/ret sequences by a single jump
++ instruction. This option could be switched off by a linker switch. */
++static int avr_replace_call_ret_sequences = 1;
++
++/* Initialize an entry in the stub hash table. */
++
++static struct bfd_hash_entry *
++stub_hash_newfunc (struct bfd_hash_entry *entry,
++ struct bfd_hash_table *table,
++ const char *string)
++{
++ /* Allocate the structure if it has not already been allocated by a
++ subclass. */
++ if (entry == NULL)
++ {
++ entry = bfd_hash_allocate (table,
++ sizeof (struct elf32_avr_stub_hash_entry));
++ if (entry == NULL)
++ return entry;
++ }
++
++ /* Call the allocation method of the superclass. */
++ entry = bfd_hash_newfunc (entry, table, string);
++ if (entry != NULL)
++ {
++ struct elf32_avr_stub_hash_entry *hsh;
+
+-unsigned int avr_pc_wrap_around = 0x10000000;
++ /* Initialize the local fields. */
++ hsh = avr_stub_hash_entry (entry);
++ hsh->stub_offset = 0;
++ hsh->target_value = 0;
++ }
++
++ return entry;
++}
++
++/* Create the derived linker hash table. The AVR ELF port uses the derived
++ hash table to keep information specific to the AVR ELF linker (without
++ using static variables). */
++
++static struct bfd_link_hash_table *
++elf32_avr_link_hash_table_create (bfd *abfd)
++{
++ struct elf32_avr_link_hash_table *htab;
++ bfd_size_type amt = sizeof (*htab);
++
++ htab = bfd_malloc (amt);
++ if (htab == NULL)
++ return NULL;
++
++ if (!_bfd_elf_link_hash_table_init (&htab->etab, abfd,
++ _bfd_elf_link_hash_newfunc,
++ sizeof (struct elf_link_hash_entry)))
++ {
++ free (htab);
++ return NULL;
++ }
++
++ /* Init the stub hash table too. */
++ if (!bfd_hash_table_init (&htab->bstab, stub_hash_newfunc,
++ sizeof (struct elf32_avr_stub_hash_entry)))
++ return NULL;
++
++ htab->stub_bfd = NULL;
++ htab->stub_sec = NULL;
++
++ /* Initialize the address mapping table. */
++ htab->amt_stub_offsets = NULL;
++ htab->amt_destination_addr = NULL;
++ htab->amt_entry_cnt = 0;
++ htab->amt_max_entry_cnt = 0;
++
++ return &htab->etab.root;
++}
++
++/* Free the derived linker hash table. */
++
++static void
++elf32_avr_link_hash_table_free (struct bfd_link_hash_table *btab)
++{
++ struct elf32_avr_link_hash_table *htab
++ = (struct elf32_avr_link_hash_table *) btab;
++
++ /* Free the address mapping table. */
++ if (htab->amt_stub_offsets != NULL)
++ free (htab->amt_stub_offsets);
++ if (htab->amt_destination_addr != NULL)
++ free (htab->amt_destination_addr);
++
++ bfd_hash_table_free (&htab->bstab);
++ _bfd_generic_link_hash_table_free (btab);
++}
+
+ /* Calculates the effective distance of a pc relative jump/call. */
+ static int
+@@ -564,20 +776,57 @@
+ return TRUE;
+ }
+
++static bfd_boolean
++avr_stub_is_required_for_16_bit_reloc (bfd_vma relocation)
++{
++ return (relocation >= 0x020000);
++}
++
++/* Returns the address of the corresponding stub if there is one.
++ Returns otherwise an address above 0x020000. This function
++ could also be used, if there is no knowledge on the section where
++ the destination is found. */
++
++static bfd_vma
++avr_get_stub_addr (bfd_vma srel,
++ struct elf32_avr_link_hash_table *htab)
++{
++ unsigned int index;
++ bfd_vma stub_sec_addr =
++ (htab->stub_sec->output_section->vma +
++ htab->stub_sec->output_offset);
++
++ for (index = 0; index < htab->amt_max_entry_cnt; index ++)
++ if (htab->amt_destination_addr[index] == srel)
++ return htab->amt_stub_offsets[index] + stub_sec_addr;
++
++ /* Return an address that could not be reached by 16 bit relocs. */
++ return 0x020000;
++}
++
+ /* Perform a single relocation. By default we use the standard BFD
+ routines, but a few relocs, we have to do them ourselves. */
+
+ static bfd_reloc_status_type
+-avr_final_link_relocate (reloc_howto_type * howto,
+- bfd * input_bfd,
+- asection * input_section,
+- bfd_byte * contents,
+- Elf_Internal_Rela * rel,
+- bfd_vma relocation)
++avr_final_link_relocate (reloc_howto_type * howto,
++ bfd * input_bfd,
++ asection * input_section,
++ bfd_byte * contents,
++ Elf_Internal_Rela * rel,
++ bfd_vma relocation,
++ struct elf32_avr_link_hash_table * htab)
+ {
+ bfd_reloc_status_type r = bfd_reloc_ok;
+ bfd_vma x;
+ bfd_signed_vma srel;
++ bfd_signed_vma reloc_addr;
++ bfd_boolean use_stubs = FALSE;
++ /* Usually is 0, unless we are generating code for a bootloader. */
++ bfd_signed_vma base_addr = htab->vector_base;
++
++ /* Absolute addr of the reloc in the final excecutable. */
++ reloc_addr = rel->r_offset + input_section->output_section->vma
++ + input_section->output_offset;
+
+ switch (howto->type)
+ {
+@@ -748,9 +997,31 @@
+ bfd_put_16 (input_bfd, x, contents);
+ break;
+
++ case R_AVR_LO8_LDI_GS:
++ use_stubs = (!htab->no_stubs);
++ /* Fall through. */
+ case R_AVR_LO8_LDI_PM:
+ contents += rel->r_offset;
+ srel = (bfd_signed_vma) relocation + rel->r_addend;
++
++ if (use_stubs
++ && avr_stub_is_required_for_16_bit_reloc (srel - base_addr))
++ {
++ bfd_vma old_srel = srel;
++
++ /* We need to use the address of the stub instead. */
++ srel = avr_get_stub_addr (srel, htab);
++ if (debug_stubs)
++ printf ("LD: Using jump stub (at 0x%x) with destination 0x%x for "
++ "reloc at address 0x%x.\n",
++ (unsigned int) srel,
++ (unsigned int) old_srel,
++ (unsigned int) reloc_addr);
++
++ if (avr_stub_is_required_for_16_bit_reloc (srel - base_addr))
++ return bfd_reloc_outofrange;
++ }
++
+ if (srel & 1)
+ return bfd_reloc_outofrange;
+ srel = srel >> 1;
+@@ -759,9 +1030,31 @@
+ bfd_put_16 (input_bfd, x, contents);
+ break;
+
++ case R_AVR_HI8_LDI_GS:
++ use_stubs = (!htab->no_stubs);
++ /* Fall through. */
+ case R_AVR_HI8_LDI_PM:
+ contents += rel->r_offset;
+ srel = (bfd_signed_vma) relocation + rel->r_addend;
++
++ if (use_stubs
++ && avr_stub_is_required_for_16_bit_reloc (srel - base_addr))
++ {
++ bfd_vma old_srel = srel;
++
++ /* We need to use the address of the stub instead. */
++ srel = avr_get_stub_addr (srel, htab);
++ if (debug_stubs)
++ printf ("LD: Using jump stub (at 0x%x) with destination 0x%x for "
++ "reloc at address 0x%x.\n",
++ (unsigned int) srel,
++ (unsigned int) old_srel,
++ (unsigned int) reloc_addr);
++
++ if (avr_stub_is_required_for_16_bit_reloc (srel - base_addr))
++ return bfd_reloc_outofrange;
++ }
++
+ if (srel & 1)
+ return bfd_reloc_outofrange;
+ srel = srel >> 1;
+@@ -833,6 +1126,35 @@
+ bfd_put_16 (input_bfd, (bfd_vma) srel & 0xffff, contents+2);
+ break;
+
++ case R_AVR_16_PM:
++ use_stubs = (!htab->no_stubs);
++ contents += rel->r_offset;
++ srel = (bfd_signed_vma) relocation + rel->r_addend;
++
++ if (use_stubs
++ && avr_stub_is_required_for_16_bit_reloc (srel - base_addr))
++ {
++ bfd_vma old_srel = srel;
++
++ /* We need to use the address of the stub instead. */
++ srel = avr_get_stub_addr (srel,htab);
++ if (debug_stubs)
++ printf ("LD: Using jump stub (at 0x%x) with destination 0x%x for "
++ "reloc at address 0x%x.\n",
++ (unsigned int) srel,
++ (unsigned int) old_srel,
++ (unsigned int) reloc_addr);
++
++ if (avr_stub_is_required_for_16_bit_reloc (srel - base_addr))
++ return bfd_reloc_outofrange;
++ }
++
++ if (srel & 1)
++ return bfd_reloc_outofrange;
++ srel = srel >> 1;
++ bfd_put_16 (input_bfd, (bfd_vma) srel &0x00ffff, contents);
++ break;
++
+ default:
+ r = _bfd_final_link_relocate (howto, input_bfd, input_section,
+ contents, rel->r_offset,
+@@ -858,6 +1180,7 @@
+ struct elf_link_hash_entry ** sym_hashes;
+ Elf_Internal_Rela * rel;
+ Elf_Internal_Rela * relend;
++ struct elf32_avr_link_hash_table * htab = avr_link_hash_table (info);
+
+ if (info->relocatable)
+ return TRUE;
+@@ -909,7 +1232,7 @@
+ }
+
+ r = avr_final_link_relocate (howto, input_bfd, input_section,
+- contents, rel, relocation);
++ contents, rel, relocation, htab);
+
+ if (r != bfd_reloc_ok)
+ {
+@@ -990,6 +1313,10 @@
+ case bfd_mach_avr5:
+ val = E_AVR_MACH_AVR5;
+ break;
++
++ case bfd_mach_avr6:
++ val = E_AVR_MACH_AVR6;
++ break;
+ }
+
+ elf_elfheader (abfd)->e_machine = EM_AVR;
+@@ -1032,6 +1359,10 @@
+ case E_AVR_MACH_AVR5:
+ e_set = bfd_mach_avr5;
+ break;
++
++ case E_AVR_MACH_AVR6:
++ e_set = bfd_mach_avr6;
++ break;
+ }
+ }
+ return bfd_default_set_arch_mach (abfd, bfd_arch_avr,
+@@ -1039,9 +1370,6 @@
+ }
+
+
+-/* Enable debugging printout at stdout with a value of 1. */
+-#define DEBUG_RELAX 0
+-
+ /* Delete some bytes from a section while changing the size of an instruction.
+ The parameter "addr" denotes the section-relative offset pointing just
+ behind the shrinked instruction. "addr+count" point at the first
+@@ -1101,7 +1429,7 @@
+ if ((irel->r_offset > addr
+ && irel->r_offset < toaddr))
+ {
+- if (DEBUG_RELAX)
++ if (debug_relax)
+ printf ("Relocation at address 0x%x needs to be moved.\n"
+ "Old section offset: 0x%x, New section offset: 0x%x \n",
+ (unsigned int) old_reloc_address,
+@@ -1148,7 +1476,7 @@
+ symval += sym_sec->output_section->vma
+ + sym_sec->output_offset;
+
+- if (DEBUG_RELAX)
++ if (debug_relax)
+ printf ("Checking if the relocation's "
+ "addend needs corrections.\n"
+ "Address of anchor symbol: 0x%x \n"
+@@ -1163,7 +1491,7 @@
+ {
+ irel->r_addend -= count;
+
+- if (DEBUG_RELAX)
++ if (debug_relax)
+ printf ("Anchor symbol and relocation target bracket "
+ "shrinked insn address.\n"
+ "Need for new addend : 0x%x\n",
+@@ -1238,7 +1566,7 @@
+ contains 4-byte jump instructions whose relative offset must not
+ be changed. */
+
+-static bfd_boolean
++static bfd_boolean
+ elf32_avr_relax_section (bfd *abfd,
+ asection *sec,
+ struct bfd_link_info *link_info,
+@@ -1251,10 +1579,37 @@
+ Elf_Internal_Sym *isymbuf = NULL;
+ static asection *last_input_section = NULL;
+ static Elf_Internal_Rela *last_reloc = NULL;
++ struct elf32_avr_link_hash_table *htab;
++
++ htab = avr_link_hash_table (link_info);
+
+ /* Assume nothing changes. */
+ *again = FALSE;
+
++ if ((!htab->no_stubs) && (sec == htab->stub_sec))
++ {
++ /* We are just relaxing the stub section.
++ Let's calculate the size needed again. */
++ bfd_size_type last_estimated_stub_section_size = htab->stub_sec->size;
++
++ if (debug_relax)
++ printf ("Relaxing the stub section. Size prior to this pass: %i\n",
++ (int) last_estimated_stub_section_size);
++
++ elf32_avr_size_stubs (htab->stub_sec->output_section->owner,
++ link_info, FALSE);
++
++ /* Check if the number of trampolines changed. */
++ if (last_estimated_stub_section_size != htab->stub_sec->size)
++ *again = TRUE;
++
++ if (debug_relax)
++ printf ("Size of stub section after this pass: %i\n",
++ (int) htab->stub_sec->size);
++
++ return TRUE;
++ }
++
+ /* We don't have to do anything for a relocatable link, if
+ this section does not have relocs, or if this is not a
+ code section. */
+@@ -1421,7 +1776,7 @@
+ unsigned char code_msb;
+ unsigned char code_lsb;
+
+- if (DEBUG_RELAX)
++ if (debug_relax)
+ printf ("shrinking jump/call instruction at address 0x%x"
+ " in section %s\n\n",
+ (int) dot, sec->name);
+@@ -1496,8 +1851,9 @@
+ + sec->output_offset + irel->r_offset);
+
+ /* Here we look for rcall/ret or call/ret sequences that could be
+- safely replaced by rjmp/ret or jmp/ret */
+- if (0xd0 == (code_msb & 0xf0))
++ safely replaced by rjmp/ret or jmp/ret. */
++ if (((code_msb & 0xf0) == 0xd0)
++ && avr_replace_call_ret_sequences)
+ {
+ /* This insn is a rcall. */
+ unsigned char next_insn_msb = 0;
+@@ -1517,7 +1873,7 @@
+ into a rjmp instruction. */
+ code_msb &= 0xef;
+ bfd_put_8 (abfd, code_msb, contents + irel->r_offset + 1);
+- if (DEBUG_RELAX)
++ if (debug_relax)
+ printf ("converted rcall/ret sequence at address 0x%x"
+ " into rjmp/ret sequence. Section is %s\n\n",
+ (int) dot, sec->name);
+@@ -1526,7 +1882,8 @@
+ }
+ }
+ else if ((0x94 == (code_msb & 0xfe))
+- && (0x0e == (code_lsb & 0x0e)))
++ && (0x0e == (code_lsb & 0x0e))
++ && avr_replace_call_ret_sequences)
+ {
+ /* This insn is a call. */
+ unsigned char next_insn_msb = 0;
+@@ -1547,7 +1904,7 @@
+
+ code_lsb &= 0xfd;
+ bfd_put_8 (abfd, code_lsb, contents + irel->r_offset);
+- if (DEBUG_RELAX)
++ if (debug_relax)
+ printf ("converted call/ret sequence at address 0x%x"
+ " into jmp/ret sequence. Section is %s\n\n",
+ (int) dot, sec->name);
+@@ -1590,10 +1947,10 @@
+
+ address_of_ret = dot + insn_size;
+
+- if (DEBUG_RELAX && (insn_size == 2))
++ if (debug_relax && (insn_size == 2))
+ printf ("found rjmp / ret sequence at address 0x%x\n",
+ (int) dot);
+- if (DEBUG_RELAX && (insn_size == 4))
++ if (debug_relax && (insn_size == 4))
+ printf ("found jmp / ret sequence at address 0x%x\n",
+ (int) dot);
+
+@@ -1630,7 +1987,7 @@
+ there_is_preceeding_non_skip_insn = 0;
+
+ if (there_is_preceeding_non_skip_insn == 0)
+- if (DEBUG_RELAX)
++ if (debug_relax)
+ printf ("preceeding skip insn prevents deletion of"
+ " ret insn at addr 0x%x in section %s\n",
+ (int) dot + 2, sec->name);
+@@ -1666,7 +2023,7 @@
+ && isym->st_shndx == sec_shndx)
+ {
+ deleting_ret_is_safe = 0;
+- if (DEBUG_RELAX)
++ if (debug_relax)
+ printf ("local label prevents deletion of ret "
+ "insn at address 0x%x\n",
+ (int) dot + insn_size);
+@@ -1695,7 +2052,7 @@
+ && sym_hash->root.u.def.value == section_offset_of_ret_insn)
+ {
+ deleting_ret_is_safe = 0;
+- if (DEBUG_RELAX)
++ if (debug_relax)
+ printf ("global label prevents deletion of "
+ "ret insn at address 0x%x\n",
+ (int) dot + insn_size);
+@@ -1772,7 +2129,7 @@
+ if (address_of_ret == reloc_target)
+ {
+ deleting_ret_is_safe = 0;
+- if (DEBUG_RELAX)
++ if (debug_relax)
+ printf ("ret from "
+ "rjmp/jmp ret sequence at address"
+ " 0x%x could not be deleted. ret"
+@@ -1784,7 +2141,7 @@
+
+ if (deleting_ret_is_safe)
+ {
+- if (DEBUG_RELAX)
++ if (debug_relax)
+ printf ("unreachable ret instruction "
+ "at address 0x%x deleted.\n",
+ (int) dot + insn_size);
+@@ -1952,6 +2309,614 @@
+ }
+
+
++/* Determines the hash entry name for a particular reloc. It consists of
++ the identifier of the symbol section and the added reloc addend and
++ symbol offset relative to the section the symbol is attached to. */
++
++static char *
++avr_stub_name (const asection *symbol_section,
++ const bfd_vma symbol_offset,
++ const Elf_Internal_Rela *rela)
++{
++ char *stub_name;
++ bfd_size_type len;
++
++ len = 8 + 1 + 8 + 1 + 1;
++ stub_name = bfd_malloc (len);
++
++ sprintf (stub_name, "%08x+%08x",
++ symbol_section->id & 0xffffffff,
++ (unsigned int) ((rela->r_addend & 0xffffffff) + symbol_offset));
++
++ return stub_name;
++}
++
++
++/* Add a new stub entry to the stub hash. Not all fields of the new
++ stub entry are initialised. */
++
++static struct elf32_avr_stub_hash_entry *
++avr_add_stub (const char *stub_name,
++ struct elf32_avr_link_hash_table *htab)
++{
++ struct elf32_avr_stub_hash_entry *hsh;
++
++ /* Enter this entry into the linker stub hash table. */
++ hsh = avr_stub_hash_lookup (&htab->bstab, stub_name, TRUE, FALSE);
++
++ if (hsh == NULL)
++ {
++ (*_bfd_error_handler) (_("%B: cannot create stub entry %s"),
++ NULL, stub_name);
++ return NULL;
++ }
++
++ hsh->stub_offset = 0;
++ return hsh;
++}
++
++/* We assume that there is already space allocated for the stub section
++ contents and that before building the stubs the section size is
++ initialized to 0. We assume that within the stub hash table entry,
++ the absolute position of the jmp target has been written in the
++ target_value field. We write here the offset of the generated jmp insn
++ relative to the trampoline section start to the stub_offset entry in
++ the stub hash table entry. */
++
++static bfd_boolean
++avr_build_one_stub (struct bfd_hash_entry *bh, void *in_arg)
++{
++ struct elf32_avr_stub_hash_entry *hsh;
++ struct bfd_link_info *info;
++ struct elf32_avr_link_hash_table *htab;
++ bfd *stub_bfd;
++ bfd_byte *loc;
++ bfd_vma target;
++ bfd_vma starget;
++
++ /* Basic opcode */
++ bfd_vma jmp_insn = 0x0000940c;
++
++ /* Massage our args to the form they really have. */
++ hsh = avr_stub_hash_entry (bh);
++
++ if (!hsh->is_actually_needed)
++ return TRUE;
++
++ info = (struct bfd_link_info *) in_arg;
++
++ htab = avr_link_hash_table (info);
++
++ target = hsh->target_value;
++
++ /* Make a note of the offset within the stubs for this entry. */
++ hsh->stub_offset = htab->stub_sec->size;
++ loc = htab->stub_sec->contents + hsh->stub_offset;
++
++ stub_bfd = htab->stub_sec->owner;
++
++ if (debug_stubs)
++ printf ("Building one Stub. Address: 0x%x, Offset: 0x%x\n",
++ (unsigned int) target,
++ (unsigned int) hsh->stub_offset);
++
++ /* We now have to add the information on the jump target to the bare
++ opcode bits already set in jmp_insn. */
++
++ /* Check for the alignment of the address. */
++ if (target & 1)
++ return FALSE;
++
++ starget = target >> 1;
++ jmp_insn |= ((starget & 0x10000) | ((starget << 3) & 0x1f00000)) >> 16;
++ bfd_put_16 (stub_bfd, jmp_insn, loc);
++ bfd_put_16 (stub_bfd, (bfd_vma) starget & 0xffff, loc + 2);
++
++ htab->stub_sec->size += 4;
++
++ /* Now add the entries in the address mapping table if there is still
++ space left. */
++ {
++ unsigned int nr;
++
++ nr = htab->amt_entry_cnt + 1;
++ if (nr <= htab->amt_max_entry_cnt)
++ {
++ htab->amt_entry_cnt = nr;
++
++ htab->amt_stub_offsets[nr - 1] = hsh->stub_offset;
++ htab->amt_destination_addr[nr - 1] = target;
++ }
++ }
++
++ return TRUE;
++}
++
++static bfd_boolean
++avr_mark_stub_not_to_be_necessary (struct bfd_hash_entry *bh,
++ void *in_arg)
++{
++ struct elf32_avr_stub_hash_entry *hsh;
++ struct elf32_avr_link_hash_table *htab;
++
++ htab = in_arg;
++ hsh = avr_stub_hash_entry (bh);
++ hsh->is_actually_needed = FALSE;
++
++ return TRUE;
++}
++
++static bfd_boolean
++avr_size_one_stub (struct bfd_hash_entry *bh, void *in_arg)
++{
++ struct elf32_avr_stub_hash_entry *hsh;
++ struct elf32_avr_link_hash_table *htab;
++ int size;
++
++ /* Massage our args to the form they really have. */
++ hsh = avr_stub_hash_entry (bh);
++ htab = in_arg;
++
++ if (hsh->is_actually_needed)
++ size = 4;
++ else
++ size = 0;
++
++ htab->stub_sec->size += size;
++ return TRUE;
++}
++
++void
++elf32_avr_setup_params (struct bfd_link_info *info,
++ bfd *avr_stub_bfd,
++ asection *avr_stub_section,
++ bfd_boolean no_stubs,
++ bfd_boolean deb_stubs,
++ bfd_boolean deb_relax,
++ bfd_vma pc_wrap_around,
++ bfd_boolean call_ret_replacement)
++{
++ struct elf32_avr_link_hash_table *htab = avr_link_hash_table(info);
++
++ htab->stub_sec = avr_stub_section;
++ htab->stub_bfd = avr_stub_bfd;
++ htab->no_stubs = no_stubs;
++
++ debug_relax = deb_relax;
++ debug_stubs = deb_stubs;
++ avr_pc_wrap_around = pc_wrap_around;
++ avr_replace_call_ret_sequences = call_ret_replacement;
++}
++
++
++/* Set up various things so that we can make a list of input sections
++ for each output section included in the link. Returns -1 on error,
++ 0 when no stubs will be needed, and 1 on success. It also sets
++ information on the stubs bfd and the stub section in the info
++ struct. */
++
++int
++elf32_avr_setup_section_lists (bfd *output_bfd,
++ struct bfd_link_info *info)
++{
++ bfd *input_bfd;
++ unsigned int bfd_count;
++ int top_id, top_index;
++ asection *section;
++ asection **input_list, **list;
++ bfd_size_type amt;
++ struct elf32_avr_link_hash_table *htab = avr_link_hash_table(info);
++
++ if (htab->no_stubs)
++ return 0;
++
++ /* Count the number of input BFDs and find the top input section id. */
++ for (input_bfd = info->input_bfds, bfd_count = 0, top_id = 0;
++ input_bfd != NULL;
++ input_bfd = input_bfd->link_next)
++ {
++ bfd_count += 1;
++ for (section = input_bfd->sections;
++ section != NULL;
++ section = section->next)
++ if (top_id < section->id)
++ top_id = section->id;
++ }
++
++ htab->bfd_count = bfd_count;
++
++ /* We can't use output_bfd->section_count here to find the top output
++ section index as some sections may have been removed, and
++ strip_excluded_output_sections doesn't renumber the indices. */
++ for (section = output_bfd->sections, top_index = 0;
++ section != NULL;
++ section = section->next)
++ if (top_index < section->index)
++ top_index = section->index;
++
++ htab->top_index = top_index;
++ amt = sizeof (asection *) * (top_index + 1);
++ input_list = bfd_malloc (amt);
++ htab->input_list = input_list;
++ if (input_list == NULL)
++ return -1;
++
++ /* For sections we aren't interested in, mark their entries with a
++ value we can check later. */
++ list = input_list + top_index;
++ do
++ *list = bfd_abs_section_ptr;
++ while (list-- != input_list);
++
++ for (section = output_bfd->sections;
++ section != NULL;
++ section = section->next)
++ if ((section->flags & SEC_CODE) != 0)
++ input_list[section->index] = NULL;
++
++ return 1;
++}
++
++
++/* Read in all local syms for all input bfds, and create hash entries
++ for export stubs if we are building a multi-subspace shared lib.
++ Returns -1 on error, 0 otherwise. */
++
++static int
++get_local_syms (bfd *input_bfd, struct bfd_link_info *info)
++{
++ unsigned int bfd_indx;
++ Elf_Internal_Sym *local_syms, **all_local_syms;
++ struct elf32_avr_link_hash_table *htab = avr_link_hash_table (info);
++
++ /* We want to read in symbol extension records only once. To do this
++ we need to read in the local symbols in parallel and save them for
++ later use; so hold pointers to the local symbols in an array. */
++ bfd_size_type amt = sizeof (Elf_Internal_Sym *) * htab->bfd_count;
++ all_local_syms = bfd_zmalloc (amt);
++ htab->all_local_syms = all_local_syms;
++ if (all_local_syms == NULL)
++ return -1;
++
++ /* Walk over all the input BFDs, swapping in local symbols.
++ If we are creating a shared library, create hash entries for the
++ export stubs. */
++ for (bfd_indx = 0;
++ input_bfd != NULL;
++ input_bfd = input_bfd->link_next, bfd_indx++)
++ {
++ Elf_Internal_Shdr *symtab_hdr;
++
++ /* We'll need the symbol table in a second. */
++ symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
++ if (symtab_hdr->sh_info == 0)
++ continue;
++
++ /* We need an array of the local symbols attached to the input bfd. */
++ local_syms = (Elf_Internal_Sym *) symtab_hdr->contents;
++ if (local_syms == NULL)
++ {
++ local_syms = bfd_elf_get_elf_syms (input_bfd, symtab_hdr,
++ symtab_hdr->sh_info, 0,
++ NULL, NULL, NULL);
++ /* Cache them for elf_link_input_bfd. */
++ symtab_hdr->contents = (unsigned char *) local_syms;
++ }
++ if (local_syms == NULL)
++ return -1;
++
++ all_local_syms[bfd_indx] = local_syms;
++ }
++
++ return 0;
++}
++
++#define ADD_DUMMY_STUBS_FOR_DEBUGGING 0
++
++bfd_boolean
++elf32_avr_size_stubs (bfd *output_bfd,
++ struct bfd_link_info *info,
++ bfd_boolean is_prealloc_run)
++{
++ struct elf32_avr_link_hash_table *htab;
++ int stub_changed = 0;
++
++ htab = avr_link_hash_table (info);
++
++ /* At this point we initialize htab->vector_base
++ To the start of the text output section. */
++ htab->vector_base = htab->stub_sec->output_section->vma;
++
++ if (get_local_syms (info->input_bfds, info))
++ {
++ if (htab->all_local_syms)
++ goto error_ret_free_local;
++ return FALSE;
++ }
++
++ if (ADD_DUMMY_STUBS_FOR_DEBUGGING)
++ {
++ struct elf32_avr_stub_hash_entry *test;
++
++ test = avr_add_stub ("Hugo",htab);
++ test->target_value = 0x123456;
++ test->stub_offset = 13;
++
++ test = avr_add_stub ("Hugo2",htab);
++ test->target_value = 0x84210;
++ test->stub_offset = 14;
++ }
++
++ while (1)
++ {
++ bfd *input_bfd;
++ unsigned int bfd_indx;
++
++ /* We will have to re-generate the stub hash table each time anything
++ in memory has changed. */
++
++ bfd_hash_traverse (&htab->bstab, avr_mark_stub_not_to_be_necessary, htab);
++ for (input_bfd = info->input_bfds, bfd_indx = 0;
++ input_bfd != NULL;
++ input_bfd = input_bfd->link_next, bfd_indx++)
++ {
++ Elf_Internal_Shdr *symtab_hdr;
++ asection *section;
++ Elf_Internal_Sym *local_syms;
++
++ /* We'll need the symbol table in a second. */
++ symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
++ if (symtab_hdr->sh_info == 0)
++ continue;
++
++ local_syms = htab->all_local_syms[bfd_indx];
++
++ /* Walk over each section attached to the input bfd. */
++ for (section = input_bfd->sections;
++ section != NULL;
++ section = section->next)
++ {
++ Elf_Internal_Rela *internal_relocs, *irelaend, *irela;
++
++ /* If there aren't any relocs, then there's nothing more
++ to do. */
++ if ((section->flags & SEC_RELOC) == 0
++ || section->reloc_count == 0)
++ continue;
++
++ /* If this section is a link-once section that will be
++ discarded, then don't create any stubs. */
++ if (section->output_section == NULL
++ || section->output_section->owner != output_bfd)
++ continue;
++
++ /* Get the relocs. */
++ internal_relocs
++ = _bfd_elf_link_read_relocs (input_bfd, section, NULL, NULL,
++ info->keep_memory);
++ if (internal_relocs == NULL)
++ goto error_ret_free_local;
++
++ /* Now examine each relocation. */
++ irela = internal_relocs;
++ irelaend = irela + section->reloc_count;
++ for (; irela < irelaend; irela++)
++ {
++ unsigned int r_type, r_indx;
++ struct elf32_avr_stub_hash_entry *hsh;
++ asection *sym_sec;
++ bfd_vma sym_value;
++ bfd_vma destination;
++ struct elf_link_hash_entry *hh;
++ char *stub_name;
++
++ r_type = ELF32_R_TYPE (irela->r_info);
++ r_indx = ELF32_R_SYM (irela->r_info);
++
++ /* Only look for 16 bit GS relocs. No other reloc will need a
++ stub. */
++ if (!((r_type == R_AVR_16_PM)
++ || (r_type == R_AVR_LO8_LDI_GS)
++ || (r_type == R_AVR_HI8_LDI_GS)))
++ continue;
++
++ /* Now determine the call target, its name, value,
++ section. */
++ sym_sec = NULL;
++ sym_value = 0;
++ destination = 0;
++ hh = NULL;
++ if (r_indx < symtab_hdr->sh_info)
++ {
++ /* It's a local symbol. */
++ Elf_Internal_Sym *sym;
++ Elf_Internal_Shdr *hdr;
++
++ sym = local_syms + r_indx;
++ hdr = elf_elfsections (input_bfd)[sym->st_shndx];
++ sym_sec = hdr->bfd_section;
++ if (ELF_ST_TYPE (sym->st_info) != STT_SECTION)
++ sym_value = sym->st_value;
++ destination = (sym_value + irela->r_addend
++ + sym_sec->output_offset
++ + sym_sec->output_section->vma);
++ }
++ else
++ {
++ /* It's an external symbol. */
++ int e_indx;
++
++ e_indx = r_indx - symtab_hdr->sh_info;
++ hh = elf_sym_hashes (input_bfd)[e_indx];
++
++ while (hh->root.type == bfd_link_hash_indirect
++ || hh->root.type == bfd_link_hash_warning)
++ hh = (struct elf_link_hash_entry *)
++ (hh->root.u.i.link);
++
++ if (hh->root.type == bfd_link_hash_defined
++ || hh->root.type == bfd_link_hash_defweak)
++ {
++ sym_sec = hh->root.u.def.section;
++ sym_value = hh->root.u.def.value;
++ if (sym_sec->output_section != NULL)
++ destination = (sym_value + irela->r_addend
++ + sym_sec->output_offset
++ + sym_sec->output_section->vma);
++ }
++ else if (hh->root.type == bfd_link_hash_undefweak)
++ {
++ if (! info->shared)
++ continue;
++ }
++ else if (hh->root.type == bfd_link_hash_undefined)
++ {
++ if (! (info->unresolved_syms_in_objects == RM_IGNORE
++ && (ELF_ST_VISIBILITY (hh->other)
++ == STV_DEFAULT)))
++ continue;
++ }
++ else
++ {
++ bfd_set_error (bfd_error_bad_value);
++
++ error_ret_free_internal:
++ if (elf_section_data (section)->relocs == NULL)
++ free (internal_relocs);
++ goto error_ret_free_local;
++ }
++ }
++
++ if (! avr_stub_is_required_for_16_bit_reloc
++ (destination - htab->vector_base))
++ {
++ if (!is_prealloc_run)
++ /* We are having a reloc that does't need a stub. */
++ continue;
++
++ /* We don't right now know if a stub will be needed.
++ Let's rather be on the safe side. */
++ }
++
++ /* Get the name of this stub. */
++ stub_name = avr_stub_name (sym_sec, sym_value, irela);
++
++ if (!stub_name)
++ goto error_ret_free_internal;
++
++
++ hsh = avr_stub_hash_lookup (&htab->bstab,
++ stub_name,
++ FALSE, FALSE);
++ if (hsh != NULL)
++ {
++ /* The proper stub has already been created. Mark it
++ to be used and write the possibly changed destination
++ value. */
++ hsh->is_actually_needed = TRUE;
++ hsh->target_value = destination;
++ free (stub_name);
++ continue;
++ }
++
++ hsh = avr_add_stub (stub_name, htab);
++ if (hsh == NULL)
++ {
++ free (stub_name);
++ goto error_ret_free_internal;
++ }
++
++ hsh->is_actually_needed = TRUE;
++ hsh->target_value = destination;
++
++ if (debug_stubs)
++ printf ("Adding stub with destination 0x%x to the"
++ " hash table.\n", (unsigned int) destination);
++ if (debug_stubs)
++ printf ("(Pre-Alloc run: %i)\n", is_prealloc_run);
++
++ stub_changed = TRUE;
++ }
++
++ /* We're done with the internal relocs, free them. */
++ if (elf_section_data (section)->relocs == NULL)
++ free (internal_relocs);
++ }
++ }
++
++ /* Re-Calculate the number of needed stubs. */
++ htab->stub_sec->size = 0;
++ bfd_hash_traverse (&htab->bstab, avr_size_one_stub, htab);
++
++ if (!stub_changed)
++ break;
++
++ stub_changed = FALSE;
++ }
++
++ free (htab->all_local_syms);
++ return TRUE;
++
++ error_ret_free_local:
++ free (htab->all_local_syms);
++ return FALSE;
++}
++
++
++/* Build all the stubs associated with the current output file. The
++ stubs are kept in a hash table attached to the main linker hash
++ table. We also set up the .plt entries for statically linked PIC
++ functions here. This function is called via hppaelf_finish in the
++ linker. */
++
++bfd_boolean
++elf32_avr_build_stubs (struct bfd_link_info *info)
++{
++ asection *stub_sec;
++ struct bfd_hash_table *table;
++ struct elf32_avr_link_hash_table *htab;
++ bfd_size_type total_size = 0;
++
++ htab = avr_link_hash_table (info);
++
++ /* In case that there were several stub sections: */
++ for (stub_sec = htab->stub_bfd->sections;
++ stub_sec != NULL;
++ stub_sec = stub_sec->next)
++ {
++ bfd_size_type size;
++
++ /* Allocate memory to hold the linker stubs. */
++ size = stub_sec->size;
++ total_size += size;
++
++ stub_sec->contents = bfd_zalloc (htab->stub_bfd, size);
++ if (stub_sec->contents == NULL && size != 0)
++ return FALSE;
++ stub_sec->size = 0;
++ }
++
++ /* Allocate memory for the adress mapping table. */
++ htab->amt_entry_cnt = 0;
++ htab->amt_max_entry_cnt = total_size / 4;
++ htab->amt_stub_offsets = bfd_malloc (sizeof (bfd_vma)
++ * htab->amt_max_entry_cnt);
++ htab->amt_destination_addr = bfd_malloc (sizeof (bfd_vma)
++ * htab->amt_max_entry_cnt );
++
++ if (debug_stubs)
++ printf ("Allocating %i entries in the AMT\n", htab->amt_max_entry_cnt);
++
++ /* Build the stubs as directed by the stub hash table. */
++ table = &htab->bstab;
++ bfd_hash_traverse (table, avr_build_one_stub, info);
++
++ if (debug_stubs)
++ printf ("Final Stub section Size: %i\n", (int) htab->stub_sec->size);
++
++ return TRUE;
++}
++
+ #define ELF_ARCH bfd_arch_avr
+ #define ELF_MACHINE_CODE EM_AVR
+ #define ELF_MACHINE_ALT1 EM_AVR_OLD
+@@ -1960,6 +2925,9 @@
+ #define TARGET_LITTLE_SYM bfd_elf32_avr_vec
+ #define TARGET_LITTLE_NAME "elf32-avr"
+
++#define bfd_elf32_bfd_link_hash_table_create elf32_avr_link_hash_table_create
++#define bfd_elf32_bfd_link_hash_table_free elf32_avr_link_hash_table_free
++
+ #define elf_info_to_howto avr_info_to_howto_rela
+ #define elf_info_to_howto_rel NULL
+ #define elf_backend_relocate_section elf32_avr_relocate_section
+diff -Nur bfd/elf32-avr.h bfd/elf32-avr.h
+--- bfd/elf32-avr.h 1970-01-01 01:00:00.000000000 +0100
++++ bfd/elf32-avr.h 2006-08-28 20:01:10.805090951 +0200
+@@ -0,0 +1,38 @@
++/* AVR-specific support for 32-bit ELF.
++ Copyright 2006 Free Software Foundation, Inc.
++
++ Written by Bjoern Haase <bjoern.m.haase@web.de>
++
++ 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., 51 Franklin Street - Fifth Floor,
++ Boston, MA 02110-1301, USA. */
++
++
++/* These four functions will be called from the ld back-end. */
++
++extern void
++elf32_avr_setup_params (struct bfd_link_info *, bfd *, asection *,
++ bfd_boolean, bfd_boolean, bfd_boolean,
++ bfd_vma, bfd_boolean);
++
++extern int
++elf32_avr_setup_section_lists (bfd *, struct bfd_link_info *);
++
++extern bfd_boolean
++elf32_avr_size_stubs (bfd *, struct bfd_link_info *, bfd_boolean);
++
++extern bfd_boolean
++elf32_avr_build_stubs (struct bfd_link_info *);
+diff -Nur bfd/libbfd.h bfd/libbfd.h
+--- bfd/libbfd.h 2006-03-26 01:38:42.000000000 +0100
++++ bfd/libbfd.h 2006-08-28 20:02:16.912297073 +0200
+@@ -1509,7 +1509,9 @@
+ "BFD_RELOC_AVR_HH8_LDI_NEG",
+ "BFD_RELOC_AVR_MS8_LDI_NEG",
+ "BFD_RELOC_AVR_LO8_LDI_PM",
++ "BFD_RELOC_AVR_LO8_LDI_GS",
+ "BFD_RELOC_AVR_HI8_LDI_PM",
++ "BFD_RELOC_AVR_HI8_LDI_GS",
+ "BFD_RELOC_AVR_HH8_LDI_PM",
+ "BFD_RELOC_AVR_LO8_LDI_PM_NEG",
+ "BFD_RELOC_AVR_HI8_LDI_PM_NEG",
+diff -Nur bfd/reloc.c bfd/reloc.c
+--- bfd/reloc.c 2006-03-26 01:38:42.000000000 +0100
++++ bfd/reloc.c 2006-08-28 20:02:16.936295332 +0200
+@@ -3666,11 +3666,25 @@
+ This is a 16 bit reloc for the AVR that stores 8 bit value (usually
+ command address) into 8 bit immediate value of LDI insn.
+ ENUM
++ BFD_RELOC_AVR_LO8_LDI_GS
++ENUMDOC
++ This is a 16 bit reloc for the AVR that stores 8 bit value
++ (command address) into 8 bit immediate value of LDI insn. If the address
++ is beyond the 128k boundary, the linker inserts a jump stub for this reloc
++ in the lower 128k.
++ENUM
+ BFD_RELOC_AVR_HI8_LDI_PM
+ ENUMDOC
+ This is a 16 bit reloc for the AVR that stores 8 bit value (high 8 bit
+ of command address) into 8 bit immediate value of LDI insn.
+ ENUM
++ BFD_RELOC_AVR_HI8_LDI_GS
++ENUMDOC
++ This is a 16 bit reloc for the AVR that stores 8 bit value (high 8 bit
++ of command address) into 8 bit immediate value of LDI insn. If the address
++ is beyond the 128k boundary, the linker inserts a jump stub for this reloc
++ below 128k.
++ENUM
+ BFD_RELOC_AVR_HH8_LDI_PM
+ ENUMDOC
+ This is a 16 bit reloc for the AVR that stores 8 bit value (most high 8 bit
+diff -Nur gas/config/tc-avr.c gas/config/tc-avr.c
+--- gas/config/tc-avr.c 2006-04-07 17:18:08.000000000 +0200
++++ gas/config/tc-avr.c 2006-08-28 20:02:16.948294462 +0200
+@@ -63,89 +63,92 @@
+
+ static struct mcu_type_s mcu_types[] =
+ {
+- {"avr1", AVR_ISA_TINY1, bfd_mach_avr1},
+- {"avr2", AVR_ISA_TINY2, bfd_mach_avr2},
+- {"avr3", AVR_ISA_M103, bfd_mach_avr3},
+- {"avr4", AVR_ISA_M8, bfd_mach_avr4},
+- {"avr5", AVR_ISA_ALL, bfd_mach_avr5},
+- {"at90s1200", AVR_ISA_1200, bfd_mach_avr1},
+- {"attiny10", AVR_ISA_TINY1, bfd_mach_avr1}, /* XXX -> tn11 */
+- {"attiny11", AVR_ISA_TINY1, bfd_mach_avr1},
+- {"attiny12", AVR_ISA_TINY1, bfd_mach_avr1},
+- {"attiny15", AVR_ISA_TINY1, bfd_mach_avr1},
+- {"attiny28", AVR_ISA_TINY1, bfd_mach_avr1},
+- {"at90s2313", AVR_ISA_2xxx, bfd_mach_avr2},
+- {"at90s2323", AVR_ISA_2xxx, bfd_mach_avr2},
+- {"at90s2333", AVR_ISA_2xxx, bfd_mach_avr2}, /* XXX -> 4433 */
+- {"at90s2343", AVR_ISA_2xxx, bfd_mach_avr2},
+- {"attiny22", AVR_ISA_2xxx, bfd_mach_avr2}, /* XXX -> 2343 */
+- {"attiny26", AVR_ISA_2xxx, bfd_mach_avr2},
+- {"at90s4433", AVR_ISA_2xxx, bfd_mach_avr2},
+- {"at90s4414", AVR_ISA_2xxx, bfd_mach_avr2}, /* XXX -> 8515 */
+- {"at90s4434", AVR_ISA_2xxx, bfd_mach_avr2}, /* XXX -> 8535 */
+- {"at90s8515", AVR_ISA_2xxx, bfd_mach_avr2},
+- {"at90s8535", AVR_ISA_2xxx, bfd_mach_avr2},
+- {"at90c8534", AVR_ISA_2xxx, bfd_mach_avr2},
+- {"at86rf401", AVR_ISA_2xxx, bfd_mach_avr2},
+- {"attiny13", AVR_ISA_TINY2, bfd_mach_avr2},
+- {"attiny2313",AVR_ISA_TINY2, bfd_mach_avr2},
+- {"attiny261", AVR_ISA_TINY2, bfd_mach_avr2},
+- {"attiny461", AVR_ISA_TINY2, bfd_mach_avr2},
+- {"attiny861", AVR_ISA_TINY2, bfd_mach_avr2},
+- {"attiny24", AVR_ISA_TINY2, bfd_mach_avr2},
+- {"attiny44", AVR_ISA_TINY2, bfd_mach_avr2},
+- {"attiny84", AVR_ISA_TINY2, bfd_mach_avr2},
+- {"attiny25", AVR_ISA_TINY2, bfd_mach_avr2},
+- {"attiny45", AVR_ISA_TINY2, bfd_mach_avr2},
+- {"attiny85", AVR_ISA_TINY2, bfd_mach_avr2},
+- {"atmega603", AVR_ISA_M603, bfd_mach_avr3}, /* XXX -> m103 */
+- {"atmega103", AVR_ISA_M103, bfd_mach_avr3},
+- {"at43usb320",AVR_ISA_M103, bfd_mach_avr3},
+- {"at43usb355",AVR_ISA_M603, bfd_mach_avr3},
+- {"at76c711", AVR_ISA_M603, bfd_mach_avr3},
+- {"atmega48", AVR_ISA_PWMx, bfd_mach_avr4},
+- {"atmega8", AVR_ISA_M8, bfd_mach_avr4},
+- {"atmega83", AVR_ISA_M8, bfd_mach_avr4}, /* XXX -> m8535 */
+- {"atmega85", AVR_ISA_M8, bfd_mach_avr4}, /* XXX -> m8 */
+- {"atmega88", AVR_ISA_PWMx, bfd_mach_avr4},
+- {"atmega8515",AVR_ISA_M8, bfd_mach_avr4},
+- {"atmega8535",AVR_ISA_M8, bfd_mach_avr4},
+- {"at90pwm2", AVR_ISA_PWMx, bfd_mach_avr4},
+- {"at90pwm3", AVR_ISA_PWMx, bfd_mach_avr4},
+- {"atmega16", AVR_ISA_M323, bfd_mach_avr5},
+- {"atmega161", AVR_ISA_M161, bfd_mach_avr5},
+- {"atmega162", AVR_ISA_M323, bfd_mach_avr5},
+- {"atmega163", AVR_ISA_M161, bfd_mach_avr5},
+- {"atmega164", AVR_ISA_M323, bfd_mach_avr5},
+- {"atmega165", AVR_ISA_M323, bfd_mach_avr5},
+- {"atmega168", AVR_ISA_M323, bfd_mach_avr5},
+- {"atmega169", AVR_ISA_M323, bfd_mach_avr5},
+- {"atmega32", AVR_ISA_M323, bfd_mach_avr5},
+- {"atmega323", AVR_ISA_M323, bfd_mach_avr5},
+- {"atmega324", AVR_ISA_M323, bfd_mach_avr5},
+- {"atmega325", AVR_ISA_M323, bfd_mach_avr5},
+- {"atmega329", AVR_ISA_M323, bfd_mach_avr5},
+- {"atmega3250",AVR_ISA_M323, bfd_mach_avr5},
+- {"atmega3290",AVR_ISA_M323, bfd_mach_avr5},
+- {"atmega406", AVR_ISA_M323, bfd_mach_avr5},
+- {"atmega64", AVR_ISA_M323, bfd_mach_avr5},
+- {"atmega640", AVR_ISA_M323, bfd_mach_avr5},
+- {"atmega644", AVR_ISA_M323, bfd_mach_avr5},
+- {"atmega128", AVR_ISA_M128, bfd_mach_avr5},
+- {"atmega1280",AVR_ISA_M128, bfd_mach_avr5},
+- {"atmega1281",AVR_ISA_M128, bfd_mach_avr5},
+- {"atmega645", AVR_ISA_M323, bfd_mach_avr5},
+- {"atmega649", AVR_ISA_M323, bfd_mach_avr5},
+- {"atmega6450",AVR_ISA_M323, bfd_mach_avr5},
+- {"atmega6490",AVR_ISA_M323, bfd_mach_avr5},
+- {"at90can32" ,AVR_ISA_M323, bfd_mach_avr5},
+- {"at90can64" ,AVR_ISA_M323, bfd_mach_avr5},
+- {"at90can128",AVR_ISA_M128, bfd_mach_avr5},
++ {"avr1", AVR_ISA_TINY1, bfd_mach_avr1},
++ {"avr2", AVR_ISA_TINY2, bfd_mach_avr2},
++ {"avr3", AVR_ISA_M103, bfd_mach_avr3},
++ {"avr4", AVR_ISA_M8, bfd_mach_avr4},
++ {"avr5", AVR_ISA_ALL, bfd_mach_avr5},
++ {"avr6", AVR_ISA_ALL, bfd_mach_avr6},
++ {"at90s1200", AVR_ISA_1200, bfd_mach_avr1},
++ {"attiny10", AVR_ISA_TINY1, bfd_mach_avr1}, /* XXX -> tn11 */
++ {"attiny11", AVR_ISA_TINY1, bfd_mach_avr1},
++ {"attiny12", AVR_ISA_TINY1, bfd_mach_avr1},
++ {"attiny15", AVR_ISA_TINY1, bfd_mach_avr1},
++ {"attiny28", AVR_ISA_TINY1, bfd_mach_avr1},
++ {"at90s2313", AVR_ISA_2xxx, bfd_mach_avr2},
++ {"at90s2323", AVR_ISA_2xxx, bfd_mach_avr2},
++ {"at90s2333", AVR_ISA_2xxx, bfd_mach_avr2}, /* XXX -> 4433 */
++ {"at90s2343", AVR_ISA_2xxx, bfd_mach_avr2},
++ {"attiny22", AVR_ISA_2xxx, bfd_mach_avr2}, /* XXX -> 2343 */
++ {"attiny26", AVR_ISA_2xxx, bfd_mach_avr2},
++ {"at90s4433", AVR_ISA_2xxx, bfd_mach_avr2},
++ {"at90s4414", AVR_ISA_2xxx, bfd_mach_avr2}, /* XXX -> 8515 */
++ {"at90s4434", AVR_ISA_2xxx, bfd_mach_avr2}, /* XXX -> 8535 */
++ {"at90s8515", AVR_ISA_2xxx, bfd_mach_avr2},
++ {"at90s8535", AVR_ISA_2xxx, bfd_mach_avr2},
++ {"at90c8534", AVR_ISA_2xxx, bfd_mach_avr2},
++ {"at86rf401", AVR_ISA_2xxx, bfd_mach_avr2},
++ {"attiny13", AVR_ISA_TINY2, bfd_mach_avr2},
++ {"attiny2313", AVR_ISA_TINY2, bfd_mach_avr2},
++ {"attiny261", AVR_ISA_TINY2, bfd_mach_avr2},
++ {"attiny461", AVR_ISA_TINY2, bfd_mach_avr2},
++ {"attiny861", AVR_ISA_TINY2, bfd_mach_avr2},
++ {"attiny24", AVR_ISA_TINY2, bfd_mach_avr2},
++ {"attiny44", AVR_ISA_TINY2, bfd_mach_avr2},
++ {"attiny84", AVR_ISA_TINY2, bfd_mach_avr2},
++ {"attiny25", AVR_ISA_TINY2, bfd_mach_avr2},
++ {"attiny45", AVR_ISA_TINY2, bfd_mach_avr2},
++ {"attiny85", AVR_ISA_TINY2, bfd_mach_avr2},
++ {"atmega603", AVR_ISA_M603, bfd_mach_avr3}, /* XXX -> m103 */
++ {"atmega103", AVR_ISA_M103, bfd_mach_avr3},
++ {"at43usb320", AVR_ISA_M103, bfd_mach_avr3},
++ {"at43usb355", AVR_ISA_M603, bfd_mach_avr3},
++ {"at76c711", AVR_ISA_M603, bfd_mach_avr3},
++ {"atmega48", AVR_ISA_PWMx, bfd_mach_avr4},
++ {"atmega8", AVR_ISA_M8, bfd_mach_avr4},
++ {"atmega83", AVR_ISA_M8, bfd_mach_avr4}, /* XXX -> m8535 */
++ {"atmega85", AVR_ISA_M8, bfd_mach_avr4}, /* XXX -> m8 */
++ {"atmega88", AVR_ISA_PWMx, bfd_mach_avr4},
++ {"atmega8515", AVR_ISA_M8, bfd_mach_avr4},
++ {"atmega8535", AVR_ISA_M8, bfd_mach_avr4},
++ {"at90pwm2", AVR_ISA_PWMx, bfd_mach_avr4},
++ {"at90pwm3", AVR_ISA_PWMx, bfd_mach_avr4},
++ {"atmega16", AVR_ISA_M323, bfd_mach_avr5},
++ {"atmega161", AVR_ISA_M161, bfd_mach_avr5},
++ {"atmega162", AVR_ISA_M323, bfd_mach_avr5},
++ {"atmega163", AVR_ISA_M161, bfd_mach_avr5},
++ {"atmega164", AVR_ISA_M323, bfd_mach_avr5},
++ {"atmega165", AVR_ISA_M323, bfd_mach_avr5},
++ {"atmega168", AVR_ISA_M323, bfd_mach_avr5},
++ {"atmega169", AVR_ISA_M323, bfd_mach_avr5},
++ {"atmega32", AVR_ISA_M323, bfd_mach_avr5},
++ {"atmega323", AVR_ISA_M323, bfd_mach_avr5},
++ {"atmega324", AVR_ISA_M323, bfd_mach_avr5},
++ {"atmega325", AVR_ISA_M323, bfd_mach_avr5},
++ {"atmega329", AVR_ISA_M323, bfd_mach_avr5},
++ {"atmega3250", AVR_ISA_M323, bfd_mach_avr5},
++ {"atmega3290", AVR_ISA_M323, bfd_mach_avr5},
++ {"atmega406", AVR_ISA_M323, bfd_mach_avr5},
++ {"atmega64", AVR_ISA_M323, bfd_mach_avr5},
++ {"atmega640", AVR_ISA_M323, bfd_mach_avr5},
++ {"atmega644", AVR_ISA_M323, bfd_mach_avr5},
++ {"atmega128", AVR_ISA_M128, bfd_mach_avr5},
++ {"atmega1280", AVR_ISA_M128, bfd_mach_avr5},
++ {"atmega1281", AVR_ISA_M128, bfd_mach_avr5},
++ {"atmega645", AVR_ISA_M323, bfd_mach_avr5},
++ {"atmega649", AVR_ISA_M323, bfd_mach_avr5},
++ {"atmega6450", AVR_ISA_M323, bfd_mach_avr5},
++ {"atmega6490", AVR_ISA_M323, bfd_mach_avr5},
++ {"at90can32" , AVR_ISA_M323, bfd_mach_avr5},
++ {"at90can64" , AVR_ISA_M323, bfd_mach_avr5},
++ {"at90can128", AVR_ISA_M128, bfd_mach_avr5},
+ {"at90usb646", AVR_ISA_M323, bfd_mach_avr5},
+ {"at90usb647", AVR_ISA_M323, bfd_mach_avr5},
+ {"at90usb1286",AVR_ISA_M128, bfd_mach_avr5},
+ {"at90usb1287",AVR_ISA_M128, bfd_mach_avr5},
+- {"at94k", AVR_ISA_94K, bfd_mach_avr5},
++ {"at94k", AVR_ISA_94K, bfd_mach_avr5},
++ {"atmega2560", AVR_ISA_ALL, bfd_mach_avr6},
++ {"atmega2561", AVR_ISA_ALL, bfd_mach_avr6},
+ {NULL, 0, 0}
+ };
+
+@@ -512,7 +515,7 @@
+ if (exp->X_op == O_constant)
+ {
+ int x = exp->X_add_number;
+-
++
+ if (x < -255 || x > 255)
+ as_warn (_("constant out of 8-bit range: %d"), x);
+ }
+@@ -544,6 +547,8 @@
+ char *tmp;
+ char op[8];
+ int mod;
++ int linker_stubs_should_be_generated = 0;
++
+ tmp = str;
+
+ str = extract_word (str, op, sizeof (op));
+@@ -551,7 +556,7 @@
+ if (op[0])
+ {
+ mod_index m;
+-
++
+ m.ptr = hash_find (avr_mod_hash, op);
+ mod = m.index;
+
+@@ -564,11 +569,14 @@
+
+ if (*str == '(')
+ {
++ bfd_reloc_code_real_type reloc_to_return;
+ int neg_p = 0;
+
+ ++str;
+
+ if (strncmp ("pm(", str, 3) == 0
++ || strncmp ("gs(",str,3) == 0
++ || strncmp ("-(gs(",str,5) == 0
+ || strncmp ("-(pm(", str, 5) == 0)
+ {
+ if (HAVE_PM_P (mod))
+@@ -579,6 +587,9 @@
+ else
+ as_bad (_("illegal expression"));
+
++ if (str[0] == 'g' || str[2] == 'g')
++ linker_stubs_should_be_generated = 1;
++
+ if (*str == '-')
+ {
+ neg_p = 1;
+@@ -610,7 +621,24 @@
+ }
+ while (closes--);
+
+- return neg_p ? EXP_MOD_NEG_RELOC (mod) : EXP_MOD_RELOC (mod);
++ reloc_to_return =
++ neg_p ? EXP_MOD_NEG_RELOC (mod) : EXP_MOD_RELOC (mod);
++ if (linker_stubs_should_be_generated)
++ {
++ switch (reloc_to_return)
++ {
++ case BFD_RELOC_AVR_LO8_LDI_PM:
++ reloc_to_return = BFD_RELOC_AVR_LO8_LDI_GS;
++ break;
++ case BFD_RELOC_AVR_HI8_LDI_PM:
++ reloc_to_return = BFD_RELOC_AVR_HI8_LDI_GS;
++ break;
++
++ default:
++ break; /* as_warn (_("expression dangerous with linker stubs")); *//* Bjoern agreed. :) */
++ }
++ }
++ return reloc_to_return;
+ }
+ }
+ }
+@@ -1227,7 +1255,7 @@
+ return NULL;
+ }
+
+- /* We are dealing with two symbols defined in the same section.
++ /* We are dealing with two symbols defined in the same section.
+ Let us fix-up them here. */
+ value += S_GET_VALUE (fixp->fx_addsy);
+ value -= S_GET_VALUE (fixp->fx_subsy);
+@@ -1310,7 +1338,8 @@
+ static int exp_mod_pm = 0;
+
+ /* Parse special CONS expression: pm (expression)
+- which is used for addressing to a program memory.
++ or alternatively: gs (expression).
++ These are used for addressing program memory.
+ Relocation: BFD_RELOC_AVR_16_PM. */
+
+ void
+@@ -1324,10 +1353,13 @@
+
+ if (nbytes == 2)
+ {
+- char *pm_name = "pm";
+- int len = strlen (pm_name);
++ char *pm_name1 = "pm";
++ char *pm_name2 = "gs";
++ int len = strlen (pm_name1);
++ /* len must be the same for both pm identifiers. */
+
+- if (strncasecmp (input_line_pointer, pm_name, len) == 0)
++ if (strncasecmp (input_line_pointer, pm_name1, len) == 0
++ || strncasecmp (input_line_pointer, pm_name2, len) == 0)
+ {
+ input_line_pointer = skip_space (input_line_pointer + len);
+
+diff -Nur gas/config/tc-avr.h gas/config/tc-avr.h
+--- gas/config/tc-avr.h 2006-05-17 18:04:30.000000000 +0200
++++ gas/config/tc-avr.h 2006-08-28 20:02:16.952294172 +0200
+@@ -125,16 +125,21 @@
+ We will need them in case that we want to do linker relaxation.
+ We could in principle keep these fixups in gas when not relaxing.
+ However, there is no serious performance penilty when making the linker
+- make the fixup work. */
+-#define TC_VALIDATE_FIX(FIXP,SEG,SKIP) \
+- if ( (FIXP->fx_r_type == BFD_RELOC_AVR_7_PCREL \
+- || FIXP->fx_r_type == BFD_RELOC_AVR_13_PCREL \
+- || FIXP->fx_r_type == BFD_RELOC_AVR_LO8_LDI_PM \
+- || FIXP->fx_r_type == BFD_RELOC_AVR_HI8_LDI_PM \
+- || FIXP->fx_r_type == BFD_RELOC_AVR_HH8_LDI_PM \
+- || FIXP->fx_r_type == BFD_RELOC_AVR_16_PM) \
+- && (FIXP->fx_addsy)) \
+- { \
+- goto SKIP; \
++ make the fixup work. Check also that fx_addsy is not NULL, in order to make
++ sure that the fixup refers to some sort of lable. */
++#define TC_VALIDATE_FIX(FIXP,SEG,SKIP) \
++ if ( (FIXP->fx_r_type == BFD_RELOC_AVR_7_PCREL \
++ || FIXP->fx_r_type == BFD_RELOC_AVR_13_PCREL \
++ || FIXP->fx_r_type == BFD_RELOC_AVR_LO8_LDI_PM \
++ || FIXP->fx_r_type == BFD_RELOC_AVR_LO8_LDI_GS \
++ || FIXP->fx_r_type == BFD_RELOC_AVR_HI8_LDI_PM \
++ || FIXP->fx_r_type == BFD_RELOC_AVR_HI8_LDI_GS \
++ || FIXP->fx_r_type == BFD_RELOC_AVR_HH8_LDI_PM \
++ || FIXP->fx_r_type == BFD_RELOC_AVR_LO8_LDI_PM_NEG \
++ || FIXP->fx_r_type == BFD_RELOC_AVR_HI8_LDI_PM_NEG \
++ || FIXP->fx_r_type == BFD_RELOC_AVR_HH8_LDI_PM_NEG \
++ || FIXP->fx_r_type == BFD_RELOC_AVR_16_PM) \
++ && (FIXP->fx_addsy)) \
++ { \
++ goto SKIP; \
+ }
+-
+diff -Nur include/elf/avr.h include/elf/avr.h
+--- include/elf/avr.h 2006-03-03 16:25:30.000000000 +0100
++++ include/elf/avr.h 2006-08-28 20:02:16.998290837 +0200
+@@ -1,5 +1,5 @@
+ /* AVR ELF support for BFD.
+- Copyright 1999, 2000, 2004 Free Software Foundation, Inc.
++ Copyright 1999, 2000, 2004, 2006 Free Software Foundation, Inc.
+ Contributed by Denis Chertykov <denisc@overta.ru>
+
+ This file is part of BFD, the Binary File Descriptor library.
+@@ -35,6 +35,7 @@
+ #define E_AVR_MACH_AVR3 3
+ #define E_AVR_MACH_AVR4 4
+ #define E_AVR_MACH_AVR5 5
++#define E_AVR_MACH_AVR6 6
+
+ /* Relocations. */
+ START_RELOC_NUMBERS (elf_avr_reloc_type)
+@@ -62,6 +63,8 @@
+ RELOC_NUMBER (R_AVR_6_ADIW, 21)
+ RELOC_NUMBER (R_AVR_MS8_LDI, 22)
+ RELOC_NUMBER (R_AVR_MS8_LDI_NEG, 23)
++ RELOC_NUMBER (R_AVR_LO8_LDI_GS, 24)
++ RELOC_NUMBER (R_AVR_HI8_LDI_GS, 25)
+ END_RELOC_NUMBERS (R_AVR_max)
+
+ #endif /* _ELF_AVR_H */
+diff -Nur include/elf/ChangeLog include/elf/ChangeLog
+--- include/elf/ChangeLog 2006-03-22 10:28:12.000000000 +0100
++++ include/elf/ChangeLog 2006-08-28 20:02:17.001290619 +0200
+@@ -1,3 +1,7 @@
++2006-05-24 Bjoern Haase <bjoern.m.haase@web.de>
++
++ * avr.h: Add E_AVR_MACH_AVR6, R_AVR_LO8_LDI_GS and R_AVR_HI8_LDI_GS.
++
+ 2006-03-22 Richard Sandiford <richard@codesourcery.com>
+ Daniel Jacobowitz <dan@codesourcery.com>
+ Phil Edwards <phil@codesourcery.com>
+diff -Nur ld/configure.tgt ld/configure.tgt
+--- ld/configure.tgt 2006-04-05 14:41:57.000000000 +0200
++++ ld/configure.tgt 2006-08-28 20:02:17.029288589 +0200
+@@ -81,7 +81,7 @@
+ xscale-*-elf) targ_emul=armelf
+ ;;
+ avr-*-*) targ_emul=avr2
+- targ_extra_emuls="avr1 avr3 avr4 avr5"
++ targ_extra_emuls="avr1 avr3 avr4 avr5 avr6"
+ ;;
+ bfin-*-elf) targ_emul=elf32bfin; targ_extra_emuls="elf32bfinfd" ;;
+ bfin-*-uclinux*) targ_emul=elf32bfin; targ_extra_emuls="elf32bfinfd" ;;
+diff -Nur ld/emulparams/avr1.sh ld/emulparams/avr1.sh
+--- ld/emulparams/avr1.sh 2002-05-16 21:51:08.000000000 +0200
++++ ld/emulparams/avr1.sh 2006-08-28 20:02:17.031288444 +0200
+@@ -4,7 +4,8 @@
+ OUTPUT_FORMAT="elf32-avr"
+ MAXPAGESIZE=1
+ EMBEDDED=yes
+-TEMPLATE_NAME=generic
++TEMPLATE_NAME=elf32
+
+ TEXT_LENGTH=8K
+ DATA_LENGTH=0
++EXTRA_EM_FILE=avrelf
+diff -Nur ld/emulparams/avr2.sh ld/emulparams/avr2.sh
+--- ld/emulparams/avr2.sh 2002-05-16 21:51:08.000000000 +0200
++++ ld/emulparams/avr2.sh 2006-08-28 20:02:17.033288299 +0200
+@@ -4,7 +4,8 @@
+ OUTPUT_FORMAT="elf32-avr"
+ MAXPAGESIZE=1
+ EMBEDDED=yes
+-TEMPLATE_NAME=generic
++TEMPLATE_NAME=elf32
+
+ TEXT_LENGTH=8K
+ DATA_LENGTH=0xffa0
++EXTRA_EM_FILE=avrelf
+diff -Nur ld/emulparams/avr3.sh ld/emulparams/avr3.sh
+--- ld/emulparams/avr3.sh 2002-05-16 21:51:08.000000000 +0200
++++ ld/emulparams/avr3.sh 2006-08-28 20:02:17.036288081 +0200
+@@ -4,7 +4,8 @@
+ OUTPUT_FORMAT="elf32-avr"
+ MAXPAGESIZE=1
+ EMBEDDED=yes
+-TEMPLATE_NAME=generic
++TEMPLATE_NAME=elf32
+
+ TEXT_LENGTH=128K
+ DATA_LENGTH=0xffa0
++EXTRA_EM_FILE=avrelf
+diff -Nur ld/emulparams/avr4.sh ld/emulparams/avr4.sh
+--- ld/emulparams/avr4.sh 2002-05-16 21:51:08.000000000 +0200
++++ ld/emulparams/avr4.sh 2006-08-28 20:02:17.038287936 +0200
+@@ -4,7 +4,8 @@
+ OUTPUT_FORMAT="elf32-avr"
+ MAXPAGESIZE=1
+ EMBEDDED=yes
+-TEMPLATE_NAME=generic
++TEMPLATE_NAME=elf32
+
+ TEXT_LENGTH=8K
+ DATA_LENGTH=0xffa0
++EXTRA_EM_FILE=avrelf
+diff -Nur ld/emulparams/avr5.sh ld/emulparams/avr5.sh
+--- ld/emulparams/avr5.sh 2002-05-16 21:51:08.000000000 +0200
++++ ld/emulparams/avr5.sh 2006-08-28 20:02:17.040287791 +0200
+@@ -4,7 +4,8 @@
+ OUTPUT_FORMAT="elf32-avr"
+ MAXPAGESIZE=1
+ EMBEDDED=yes
+-TEMPLATE_NAME=generic
++TEMPLATE_NAME=elf32
+
+ TEXT_LENGTH=128K
+ DATA_LENGTH=0xffa0
++EXTRA_EM_FILE=avrelf
+diff -Nur ld/emulparams/avr6.sh ld/emulparams/avr6.sh
+--- ld/emulparams/avr6.sh 1970-01-01 01:00:00.000000000 +0100
++++ ld/emulparams/avr6.sh 2006-08-28 20:02:17.043287574 +0200
+@@ -0,0 +1,11 @@
++ARCH=avr:6
++MACHINE=
++SCRIPT_NAME=avr
++OUTPUT_FORMAT="elf32-avr"
++MAXPAGESIZE=1
++EMBEDDED=yes
++TEMPLATE_NAME=elf32
++
++TEXT_LENGTH=1024K
++DATA_LENGTH=0xffa0
++EXTRA_EM_FILE=avrelf
+diff -Nur ld/emultempl/avrelf.em ld/emultempl/avrelf.em
+--- ld/emultempl/avrelf.em 1970-01-01 01:00:00.000000000 +0100
++++ ld/emultempl/avrelf.em 2006-08-28 20:02:17.047287284 +0200
+@@ -0,0 +1,267 @@
++# This shell script emits a C file. -*- C -*-
++# Copyright 2006
++# Free Software Foundation, Inc.
++#
++# This file is part of GLD, the Gnu Linker.
++#
++# 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., 51 Franklin Street - Fifth Floor, Boston,
++# MA 02110-1301 USA.
++
++# This file is sourced from elf32.em, and defines extra avr-elf
++# specific routines. It is used to generate the trampolines for the avr6
++# family devices where one needs to address the issue that it is not possible
++# to reach the whole program memory by using 16 bit pointers.
++
++cat >>e${EMULATION_NAME}.c <<EOF
++
++#include "elf32-avr.h"
++#include "ldctor.h"
++
++/* The fake file and it's corresponding section meant to hold
++ the linker stubs if needed. */
++
++static lang_input_statement_type *stub_file;
++static asection *avr_stub_section;
++
++/* Variables set by the command-line parameters and transfered
++ to the bfd without use of global shared variables. */
++
++static bfd_boolean avr_no_stubs = FALSE;
++static bfd_boolean avr_debug_relax = FALSE;
++static bfd_boolean avr_debug_stubs = FALSE;
++static bfd_boolean avr_replace_call_ret_sequences = TRUE;
++static bfd_vma avr_pc_wrap_around = 0x10000000;
++
++/* Transfers information to the bfd frontend. */
++
++static void
++avr_elf_set_global_bfd_parameters (void)
++{
++ elf32_avr_setup_params (& link_info,
++ stub_file->the_bfd,
++ avr_stub_section,
++ avr_no_stubs,
++ avr_debug_stubs,
++ avr_debug_relax,
++ avr_pc_wrap_around,
++ avr_replace_call_ret_sequences);
++}
++
++
++/* Makes a conservative estimate of the trampoline section size that could
++ be corrected later on. */
++
++static void
++avr_elf_${EMULATION_NAME}_before_allocation (void)
++{
++ int ret;
++
++ gld${EMULATION_NAME}_before_allocation ();
++
++ /* We only need stubs for the avr6 family. */
++ if (strcmp ("${EMULATION_NAME}","avr6"))
++ avr_no_stubs = TRUE;
++
++ avr_elf_set_global_bfd_parameters ();
++
++ /* If generating a relocatable output file, then
++ we don't have to generate the trampolines. */
++ if (link_info.relocatable)
++ avr_no_stubs = TRUE;
++
++ if (avr_no_stubs)
++ return;
++
++ ret = elf32_avr_setup_section_lists (output_bfd, &link_info);
++
++ if (ret < 0)
++ einfo ("%X%P: can not setup the input section list: %E\n");
++
++ if (ret <= 0)
++ return;
++
++ /* Call into the BFD backend to do the real "stub"-work. */
++ if (! elf32_avr_size_stubs (output_bfd, &link_info, TRUE))
++ einfo ("%X%P: can not size stub section: %E\n");
++}
++
++/* This is called before the input files are opened. We create a new
++ fake input file to hold the stub section and generate the section itself. */
++
++static void
++avr_elf_create_output_section_statements (void)
++{
++ flagword flags;
++
++ stub_file = lang_add_input_file ("linker stubs",
++ lang_input_file_is_fake_enum,
++ NULL);
++
++ stub_file->the_bfd = bfd_create ("linker stubs", output_bfd);
++ if (stub_file->the_bfd == NULL
++ || !bfd_set_arch_mach (stub_file->the_bfd,
++ bfd_get_arch (output_bfd),
++ bfd_get_mach (output_bfd)))
++ {
++ einfo ("%X%P: can not create stub BFD %E\n");
++ return;
++ }
++
++ /* Now we add the stub section. */
++
++ avr_stub_section = bfd_make_section_anyway (stub_file->the_bfd,
++ ".trampolines");
++ if (avr_stub_section == NULL)
++ goto err_ret;
++
++ flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE
++ | SEC_HAS_CONTENTS | SEC_RELOC | SEC_IN_MEMORY | SEC_KEEP);
++ if (!bfd_set_section_flags (stub_file->the_bfd, avr_stub_section, flags))
++ goto err_ret;
++
++ avr_stub_section->alignment_power = 1;
++
++ ldlang_add_file (stub_file);
++
++ return;
++
++ err_ret:
++ einfo ("%X%P: can not make stub section: %E\n");
++ return;
++}
++
++/* Re-calculates the size of the stubs so that we won't waste space. */
++
++static void
++avr_elf_finish (void)
++{
++ if (!avr_no_stubs)
++ {
++ /* Now build the linker stubs. */
++ if (stub_file->the_bfd->sections != NULL)
++ {
++ /* Call again the trampoline analyzer to initialize the trampoline
++ stubs with the correct symbol addresses. Since there could have
++ been relaxation, the symbol addresses that were found during
++ first call may no longer be correct. */
++ if (!elf32_avr_size_stubs (output_bfd, &link_info, FALSE))
++ {
++ einfo ("%X%P: can not size stub section: %E\n");
++ return;
++ }
++
++ if (!elf32_avr_build_stubs (&link_info))
++ einfo ("%X%P: can not build stubs: %E\n");
++ }
++ }
++
++ gld${EMULATION_NAME}_finish ();
++}
++
++
++EOF
++
++
++PARSE_AND_LIST_PROLOGUE='
++
++#define OPTION_NO_CALL_RET_REPLACEMENT 301
++#define OPTION_PMEM_WRAP_AROUND 302
++#define OPTION_NO_STUBS 303
++#define OPTION_DEBUG_STUBS 304
++#define OPTION_DEBUG_RELAX 305
++'
++
++PARSE_AND_LIST_LONGOPTS='
++ { "no-call-ret-replacement", no_argument,
++ NULL, OPTION_NO_CALL_RET_REPLACEMENT},
++ { "pmem-wrap-around", required_argument,
++ NULL, OPTION_PMEM_WRAP_AROUND},
++ { "no-stubs", no_argument,
++ NULL, OPTION_NO_STUBS},
++ { "debug-stubs", no_argument,
++ NULL, OPTION_DEBUG_STUBS},
++ { "debug-relax", no_argument,
++ NULL, OPTION_DEBUG_RELAX},
++'
++
++PARSE_AND_LIST_OPTIONS='
++ fprintf (file, _(" --pmem-wrap-around=<val> "
++ "Make the linker relaxation machine assume that a\n"
++ " "
++ "program counter wrap-around occures at address\n"
++ " "
++ "<val>. Supported values are 16k, 32k and 64k.\n"));
++ fprintf (file, _(" --no-call-ret-replacement "
++ "The relaxation machine normally will\n"
++ " "
++ "substitute two immediately following call/ret\n"
++ " "
++ "instructions by a single jump instruction.\n"
++ " "
++ "This option disables this optimization.\n"));
++ fprintf (file, _(" --no-stubs "
++ "If the linker detects to attempt to access\n"
++ " "
++ "an instruction beyond 128k by a reloc that\n"
++ " "
++ "is limited to 128k max, it inserts a jump\n"
++ " "
++ "stub. You can de-active this with this switch.\n"));
++ fprintf (file, _(" --debug-stubs Used for debugging avr-ld.\n"));
++ fprintf (file, _(" --debug-relax Used for debugging avr-ld.\n"));
++'
++
++PARSE_AND_LIST_ARGS_CASES='
++
++ case OPTION_PMEM_WRAP_AROUND:
++ {
++ /* This variable is defined in the bfd library. */
++ if ((!strcmp (optarg,"32k")) || (!strcmp (optarg,"32K")))
++ avr_pc_wrap_around = 32768;
++ else if ((!strcmp (optarg,"16k")) || (!strcmp (optarg,"16K")))
++ avr_pc_wrap_around = 16384;
++ else if ((!strcmp (optarg,"64k")) || (!strcmp (optarg,"64K")))
++ avr_pc_wrap_around = 0x10000;
++ else
++ return FALSE;
++ }
++ break;
++
++ case OPTION_DEBUG_STUBS:
++ avr_debug_stubs = TRUE;
++ break;
++
++ case OPTION_DEBUG_RELAX:
++ avr_debug_relax = TRUE;
++ break;
++
++ case OPTION_NO_STUBS:
++ avr_no_stubs = TRUE;
++ break;
++
++ case OPTION_NO_CALL_RET_REPLACEMENT:
++ {
++ /* This variable is defined in the bfd library. */
++ avr_replace_call_ret_sequences = FALSE;
++ }
++ break;
++'
++
++#
++# Put these extra avr-elf routines in ld_${EMULATION_NAME}_emulation
++#
++LDEMUL_BEFORE_ALLOCATION=avr_elf_${EMULATION_NAME}_before_allocation
++LDEMUL_FINISH=avr_elf_finish
++LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS=avr_elf_create_output_section_statements
+diff -Nur ld/Makefile.am ld/Makefile.am
+--- ld/Makefile.am 2006-06-03 06:45:50.000000000 +0200
++++ ld/Makefile.am 2006-08-28 20:02:17.055286703 +0200
+@@ -133,6 +133,7 @@
+ eavr3.o \
+ eavr4.o \
+ eavr5.o \
++ eavr6.o \
+ ecoff_i860.o \
+ ecoff_sparc.o \
+ ecrisaout.o \
+@@ -595,6 +596,10 @@
+ $(srcdir)/emultempl/generic.em $(srcdir)/scripttempl/avr.sc \
+ ${GEN_DEPENDS}
+ ${GENSCRIPTS} avr5 "$(tdir_avr2)"
++eavr6.c: $(srcdir)/emulparams/avr6.sh \
++ $(srcdir)/emultempl/generic.em $(srcdir)/scripttempl/avr.sc \
++ ${GEN_DEPENDS}
++ ${GENSCRIPTS} avr6 "$(tdir_avr2)"
+ ecoff_i860.c: $(srcdir)/emulparams/coff_i860.sh \
+ $(srcdir)/emultempl/generic.em $(srcdir)/scripttempl/i860coff.sc ${GEN_DEPENDS}
+ ${GENSCRIPTS} coff_i860 "$(tdir_coff_i860)"
+diff -Nur ld/Makefile.in ld/Makefile.in
+--- ld/Makefile.in 2006-06-03 06:45:50.000000000 +0200
++++ ld/Makefile.in 2006-08-28 20:02:17.072285471 +0200
+@@ -357,6 +357,7 @@
+ eavr3.o \
+ eavr4.o \
+ eavr5.o \
++ eavr6.o \
+ ecoff_i860.o \
+ ecoff_sparc.o \
+ ecrisaout.o \
+@@ -1406,6 +1407,10 @@
+ $(srcdir)/emultempl/generic.em $(srcdir)/scripttempl/avr.sc \
+ ${GEN_DEPENDS}
+ ${GENSCRIPTS} avr5 "$(tdir_avr2)"
++eavr6.c: $(srcdir)/emulparams/avr6.sh \
++ $(srcdir)/emultempl/generic.em $(srcdir)/scripttempl/avr.sc \
++ ${GEN_DEPENDS}
++ ${GENSCRIPTS} avr6 "$(tdir_avr2)"
+ ecoff_i860.c: $(srcdir)/emulparams/coff_i860.sh \
+ $(srcdir)/emultempl/generic.em $(srcdir)/scripttempl/i860coff.sc ${GEN_DEPENDS}
+ ${GENSCRIPTS} coff_i860 "$(tdir_coff_i860)"
+diff -Nur ld/scripttempl/avr.sc ld/scripttempl/avr.sc
+--- ld/scripttempl/avr.sc 2006-03-03 16:25:31.000000000 +0100
++++ ld/scripttempl/avr.sc 2006-08-28 20:02:17.078285036 +0200
+@@ -71,12 +71,32 @@
+ .rel.plt ${RELOCATING-0} : { *(.rel.plt) }
+ .rela.plt ${RELOCATING-0} : { *(.rela.plt) }
+
+- /* Internal text space or external memory */
++ /* Internal text space or external memory. */
+ .text :
+ {
+ *(.vectors)
+ KEEP(*(.vectors))
+
++ /* For data that needs to reside in the lower 64k of progmem. */
++ *(.progmem.gcc*)
++ *(.progmem*)
++ ${RELOCATING+. = ALIGN(2);}
++
++ ${CONSTRUCTING+ __trampolines_start = . ; }
++ /* The jump trampolines for the 16-bit limited relocs will reside here. */
++ *(.trampolines)
++ *(.trampolines*)
++ ${CONSTRUCTING+ __trampolines_end = . ; }
++
++ /* For future tablejump instruction arrays for 3 byte pc devices.
++ We don't relax jump/call instructions within these sections. */
++ *(.jumptables)
++ *(.jumptables*)
++
++ /* For code that needs to reside in the lower 128k progmem. */
++ *(.lowtext)
++ *(.lowtext*)
++
+ ${CONSTRUCTING+ __ctors_start = . ; }
+ ${CONSTRUCTING+ *(.ctors) }
+ ${CONSTRUCTING+ __ctors_end = . ; }
+@@ -86,18 +106,8 @@
+ KEEP(SORT(*)(.ctors))
+ KEEP(SORT(*)(.dtors))
+
+- /* For data that needs to reside in the lower 64k of progmem */
+- *(.progmem.gcc*)
+- *(.progmem*)
+- ${RELOCATING+. = ALIGN(2);}
+-
+- /* for future tablejump instruction arrays for 3 byte pc devices */
+- *(.jumptables)
+- *(.jumptables*)
+- /* for code that needs to reside in the lower 128k progmem */
+- *(.lowtext)
+- *(.lowtext*)
+-
++ /* From this point on, we don't bother about wether the insns are
++ below or above the 16 bits boundary. */
+ *(.init0) /* Start here after reset. */
+ KEEP (*(.init0))
+ *(.init1)
diff --git a/51-binutils-2.17-newdevices.patch b/51-binutils-2.17-newdevices.patch
new file mode 100644
index 000000000000..a4daa6dc6de9
--- /dev/null
+++ b/51-binutils-2.17-newdevices.patch
@@ -0,0 +1,54 @@
+--- gas/config/tc-avr.c.orig Mon May 14 00:03:05 2007
++++ gas/config/tc-avr.c Mon May 14 00:04:56 2007
+@@ -111,27 +111,36 @@
+ {"atmega88", AVR_ISA_PWMx, bfd_mach_avr4},
+ {"atmega8515", AVR_ISA_M8, bfd_mach_avr4},
+ {"atmega8535", AVR_ISA_M8, bfd_mach_avr4},
++ {"atmega8hva", AVR_ISA_PWMx, bfd_mach_avr4},
++ {"at90pwm1", AVR_ISA_PWMx, bfd_mach_avr4},
+ {"at90pwm2", AVR_ISA_PWMx, bfd_mach_avr4},
+ {"at90pwm3", AVR_ISA_PWMx, bfd_mach_avr4},
+ {"atmega16", AVR_ISA_M323, bfd_mach_avr5},
+ {"atmega161", AVR_ISA_M161, bfd_mach_avr5},
+ {"atmega162", AVR_ISA_M323, bfd_mach_avr5},
+ {"atmega163", AVR_ISA_M161, bfd_mach_avr5},
+- {"atmega164", AVR_ISA_M323, bfd_mach_avr5},
++ {"atmega164p", AVR_ISA_M323, bfd_mach_avr5},
+ {"atmega165", AVR_ISA_M323, bfd_mach_avr5},
++ {"atmega165p", AVR_ISA_M323, bfd_mach_avr5},
+ {"atmega168", AVR_ISA_M323, bfd_mach_avr5},
+ {"atmega169", AVR_ISA_M323, bfd_mach_avr5},
++ {"atmega169p", AVR_ISA_M323, bfd_mach_avr5},
+ {"atmega32", AVR_ISA_M323, bfd_mach_avr5},
+ {"atmega323", AVR_ISA_M323, bfd_mach_avr5},
+- {"atmega324", AVR_ISA_M323, bfd_mach_avr5},
++ {"atmega324p", AVR_ISA_M323, bfd_mach_avr5},
+ {"atmega325", AVR_ISA_M323, bfd_mach_avr5},
++ {"atmega325p", AVR_ISA_M323, bfd_mach_avr5},
+ {"atmega329", AVR_ISA_M323, bfd_mach_avr5},
++ {"atmega329p", AVR_ISA_M323, bfd_mach_avr5},
+ {"atmega3250", AVR_ISA_M323, bfd_mach_avr5},
++ {"atmega3250p",AVR_ISA_M323, bfd_mach_avr5},
+ {"atmega3290", AVR_ISA_M323, bfd_mach_avr5},
++ {"atmega3290p",AVR_ISA_M323, bfd_mach_avr5},
+ {"atmega406", AVR_ISA_M323, bfd_mach_avr5},
+ {"atmega64", AVR_ISA_M323, bfd_mach_avr5},
+ {"atmega640", AVR_ISA_M323, bfd_mach_avr5},
+ {"atmega644", AVR_ISA_M323, bfd_mach_avr5},
++ {"atmega644p", AVR_ISA_M323, bfd_mach_avr5},
+ {"atmega128", AVR_ISA_M128, bfd_mach_avr5},
+ {"atmega1280", AVR_ISA_M128, bfd_mach_avr5},
+ {"atmega1281", AVR_ISA_M128, bfd_mach_avr5},
+@@ -139,9 +148,12 @@
+ {"atmega649", AVR_ISA_M323, bfd_mach_avr5},
+ {"atmega6450", AVR_ISA_M323, bfd_mach_avr5},
+ {"atmega6490", AVR_ISA_M323, bfd_mach_avr5},
++ {"atmega16hva",AVR_ISA_M323, bfd_mach_avr5},
+ {"at90can32" , AVR_ISA_M323, bfd_mach_avr5},
+ {"at90can64" , AVR_ISA_M323, bfd_mach_avr5},
+ {"at90can128", AVR_ISA_M128, bfd_mach_avr5},
++ {"at90usb82", AVR_ISA_M323, bfd_mach_avr5},
++ {"at90usb162", AVR_ISA_M323, bfd_mach_avr5},
+ {"at90usb646", AVR_ISA_M323, bfd_mach_avr5},
+ {"at90usb647", AVR_ISA_M323, bfd_mach_avr5},
+ {"at90usb1286",AVR_ISA_M128, bfd_mach_avr5},
diff --git a/PKGBUILD b/PKGBUILD
new file mode 100644
index 000000000000..1dbba4db1999
--- /dev/null
+++ b/PKGBUILD
@@ -0,0 +1,116 @@
+# Maintainer: ABDULLATIF Mouhamadi <bourou01dev@gmail.com>
+
+pkgname=binutils-avr-tinyos
+pkgver=2.17
+pkgrel=1
+pkgdesc="A set of programs to assemble and manipulate binary and object files for the avr architecture, with TinyOS patches"
+arch=('i686' 'x86_64')
+url="http://www.gnu.org/software/binutils/"
+license=('GPL')
+depends=('glibc>=2.12-5' 'zlib')
+makedepends=('subversion')
+provides=('binutils-avr')
+options=('staticlibs' '!libtool' '!distcc' '!ccache')
+
+source=("http://ftp.gnu.org/gnu/binutils/binutils-${pkgver}.tar.bz2"
+ "30-binutils-2.17-avr-size.patch"
+ "31-binutils-2.17-avr-coff.patch"
+ "50-binutils-2.17-atmega256x.patch"
+ "51-binutils-2.17-newdevices.patch"
+ "dollarsign.patch"
+ "makeinfo411.patch"
+ "rfa1-newdevice.patch"
+ "rfa1-size.patch")
+
+
+sha1sums=('0f5c10d155d7ef67c5eb1261f84e70e2b92293fa'
+ '2b5d2e59f69062e12cfcdec05c7a7c1605548b8d'
+ '9c7428e902e5064540e0ed51c4c4d39e7516232c'
+ 'a44eb430bc0209b9f1e4d97353de6b3db12748bd'
+ '5718008fd59182f828b65fde20d78559a700c5f5'
+ 'cf6f21fc4fc99c5b3ca5a065145619a3ed85960c'
+ '04f713709af32d149b77216b6e1419289f57c971'
+ '99a0e9ad9206c98b02602bc23dce78238e67399b'
+ '87d2de4f04199a8dcd1c10cd3f31a7d8ddfd058b')
+
+prepare() {
+ cd "${srcdir}/binutils-${pkgver}"
+
+ (cd "${srcdir}/binutils-${pkgver}" &&
+ patch -p0 < "${srcdir}/30-binutils-2.17-avr-size.patch" &&
+ patch -p0 < "${srcdir}/31-binutils-2.17-avr-coff.patch" &&
+ patch -p0 < "${srcdir}/50-binutils-2.17-atmega256x.patch" &&
+ patch -p0 < "${srcdir}/51-binutils-2.17-newdevices.patch" &&
+ patch -p0 < "${srcdir}/dollarsign.patch" &&
+ patch -p0 < "${srcdir}/makeinfo411.patch" &&
+ patch -p0 < "${srcdir}/rfa1-newdevice.patch" &&
+ patch -p0 < "${srcdir}/rfa1-size.patch" &&
+ for patch in ${_patches[@]} ; do
+ msg "Applying ${patch}"
+ patch -p1 < "${srcdir}/${patch}"
+ done)
+
+ # hack! - libiberty configure tests for header files using "$CPP $CPPFLAGS" - credits to jck
+ sed -i "/ac_cpp=/s/\$CPPFLAGS/\$CPPFLAGS -O2/" libiberty/configure
+}
+
+
+build() {
+ cd "${srcdir}/binutils-${pkgver}"
+
+ export MAKEINFO=${srcdir}/usr/bin/makeinfo
+
+ install -d build
+ cd build
+ export CC="gcc -L$(pwd)/bfd/.libs/"
+
+ if [ "${CARCH}" = "x86_64" ]; then
+ ../configure --build=$(../config.guess) \
+ --disable-multilib \
+ --disable-nls \
+ --enable-64-bit-bfd \
+ --enable-install-libbfd \
+ --includedir=/usr/$(../config.guess)/include \
+ --infodir=/usr/share/info \
+ --libdir=/usr/lib \
+ --mandir=/usr/share/man \
+ --prefix=/usr \
+ --target=avr \
+ --disable-werror
+ else
+ ../configure --build=$(../config.guess) \
+ --disable-nls \
+ --enable-install-libbfd \
+ --includedir=/usr/$(../config.guess)/include \
+ --infodir=/usr/share/info \
+ --libdir=/usr/lib \
+ --mandir=/usr/share/man \
+ --prefix=/usr \
+ --target=avr \
+ --disable-werror
+ fi
+
+ # This checks the host environment and makes sure all the necessary tools are available to compile Binutils.
+ make configure-host || return 1
+
+ make tooldir=/usr || return 1
+}
+
+package() {
+ cd ${srcdir}/binutils-${pkgver}
+
+ cd build
+ make DESTDIR=${pkgdir} tooldir=/usr install || return 1
+
+ rm -f ${pkgdir}/usr/lib/libiberty.a
+
+ for bin in addr2line ar as c++filt gprof ld nm objcopy objdump ranlib readelf size strings strip ; do
+ rm -f ${pkgdir}/usr/bin/${bin} || return 1
+ done
+
+ for info in as bfd binutils configure ld standards; do
+ mv ${pkgdir}/usr/share/info/${info}.info ${pkgdir}/usr/share/info/avr-${info}.info || return 1
+ done
+}
+
+# vim:set ts=2 sw=2 et:
diff --git a/dollarsign.patch b/dollarsign.patch
new file mode 100644
index 000000000000..49bd96adda2c
--- /dev/null
+++ b/dollarsign.patch
@@ -0,0 +1,49 @@
+diff -ruN binutils-2.17-orig/gas/config/tc-avr.h binutils-2.17/gas/config/tc-avr.h
+--- gas/config/tc-avr.h 2008-01-24 14:41:48.000000000 -0800
++++ gas/config/tc-avr.h 2008-01-24 14:43:07.000000000 -0800
+@@ -109,8 +109,12 @@
+ would print `12 34 56 78'. The default value is 4. */
+ #define LISTING_WORD_SIZE 2
+
+-/* AVR port uses `$' as a logical line separator */
+-#define LEX_DOLLAR 0
++/* AVR port uses `$' as a logical line separator and doesn't
++ allow it in symbols. We allow it in the middle of symbols.
++ We also hack get_symbol_end to disallow it at the end of a symbol. */
++#define LEX_DOLLAR 1
++#define TC_EOL_IN_INSN(PTR) (*(PTR) == '$' && is_part_of_name((PTR)[-1]) && is_part_of_name((PTR)[1]))
++#define TC_FORBID_DOLLAR_AT_END
+
+ /* An `.lcomm' directive with no explicit alignment parameter will
+ use this macro to set P2VAR to the alignment that a request for
+diff -ruN binutils-2.17-orig/gas/config/tc-msp430.h binutils-2.17/gas/config/tc-msp430.h
+--- gas/config/tc-msp430.h 2008-01-24 14:41:48.000000000 -0800
++++ gas/config/tc-msp430.h 2008-01-24 14:44:27.000000000 -0800
+@@ -97,7 +97,7 @@
+ example, a value of 2 might print `1234 5678' where a value of 1
+ would print `12 34 56 78'. The default value is 4. */
+
+-#define LEX_DOLLAR 0
++#undef LEX_DOLLAR
+ /* MSP430 port does not use `$' as a logical line separator */
+
+ #define TC_IMPLICIT_LCOMM_ALIGNMENT(SIZE, P2VAR) (P2VAR) = 0
+diff -ruN binutils-2.17-orig/gas/expr.c binutils-2.17/gas/expr.c
+--- gas/expr.c 2008-01-24 14:41:48.000000000 -0800
++++ gas/expr.c 2008-01-24 14:45:37.000000000 -0800
+@@ -2174,6 +2174,15 @@
+ ;
+ if (is_name_ender (c))
+ c = *input_line_pointer++;
++#ifdef TC_FORBID_DOLLAR_AT_END
++ /* This is for the Atmel AVR platforms. We want to allow $ in symbols
++ but also as a line separator. Yucky. */
++ if (input_line_pointer[-2] == '$')
++ {
++ input_line_pointer--;
++ c = '$';
++ }
++#endif
+ }
+ *--input_line_pointer = 0;
+ return (c);
diff --git a/makeinfo411.patch b/makeinfo411.patch
new file mode 100644
index 000000000000..178102398cc9
--- /dev/null
+++ b/makeinfo411.patch
@@ -0,0 +1,12 @@
+diff -ruN binorig/configure binutils-2.17/configure
+--- configure 2011-05-30 17:08:13.986437974 +0200
++++ configure 2006-04-06 23:49:25.000000000 +0200
+@@ -3637,7 +3637,7 @@
+ # For an installed makeinfo, we require it to be from texinfo 4.4 or
+ # higher, else we use the "missing" dummy.
+ if ${MAKEINFO} --version \
+- | egrep 'texinfo[^0-9]*([1-3][0-9]|4\.[4-9]|[5-9])' >/dev/null 2>&1; then
++ | egrep 'texinfo[^0-9]*(4\.([4-9]|[1-9][0-9])|[5-9]|[1-9][0-9])' >/dev/null 2>&1; then
+ :
+ else
+ MAKEINFO="$MISSING makeinfo"
diff --git a/rfa1-newdevice.patch b/rfa1-newdevice.patch
new file mode 100644
index 000000000000..c432cf570d5d
--- /dev/null
+++ b/rfa1-newdevice.patch
@@ -0,0 +1,9 @@
+diff -ruN binutils-2.17-orig/gas/config/tc-avr.c binutils-2.17/gas/config/tc-avr.c
+--- gas/config/tc-avr.c 2008-01-24 14:41:48.000000000 -0800
++++ gas/config/tc-avr.c 2008-01-24 14:43:07.000000000 -0800
+@@ -145,4 +145,5 @@
+ {"atmega1280",AVR_ISA_M128, bfd_mach_avr5},
+ {"atmega1281",AVR_ISA_M128, bfd_mach_avr5},
++ {"atmega128rfa1",AVR_ISA_M128, bfd_mach_avr5},
+ {"atmega645", AVR_ISA_M323, bfd_mach_avr5},
+ {"atmega649", AVR_ISA_M323, bfd_mach_avr5},
diff --git a/rfa1-size.patch b/rfa1-size.patch
new file mode 100644
index 000000000000..5b26e7cfc0b9
--- /dev/null
+++ b/rfa1-size.patch
@@ -0,0 +1,11 @@
+diff -rupN binutils-2.17orig/binutils/size.c binutils-2.17/binutils/size.c
+--- binutils/size.c 2011-05-30 15:19:37.000000000 +0200
++++ binutils/size.c 2011-05-30 15:28:14.461869141 +0200
+@@ -118,6 +118,7 @@ avr_device_t avr[] =
+ {"atmega128", AVR128K, AVR4K, AVR4K},
+ {"atmega1280", AVR128K, AVR8K, AVR4K},
+ {"atmega1281", AVR128K, AVR8K, AVR4K},
++ {"atmega128rfa1", AVR128K, AVR16K, AVR4K},
+ {"atmega103", AVR128K, 4000, AVR4K},
+
+ {"at90can64", AVR64K, AVR4K, AVR2K},