diff options
-rw-r--r-- | .SRCINFO | 37 | ||||
-rw-r--r-- | 30-binutils-2.17-avr-size.patch | 404 | ||||
-rw-r--r-- | 31-binutils-2.17-avr-coff.patch | 5564 | ||||
-rw-r--r-- | 50-binutils-2.17-atmega256x.patch | 2323 | ||||
-rw-r--r-- | 51-binutils-2.17-newdevices.patch | 54 | ||||
-rw-r--r-- | PKGBUILD | 116 | ||||
-rw-r--r-- | dollarsign.patch | 49 | ||||
-rw-r--r-- | makeinfo411.patch | 12 | ||||
-rw-r--r-- | rfa1-newdevice.patch | 9 | ||||
-rw-r--r-- | rfa1-size.patch | 11 |
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}, |