* archures.c: Add some more MSP430 machine numbers.
authorNick Clifton <nickc@redhat.com>
Thu, 2 May 2013 21:06:15 +0000 (21:06 +0000)
committerNick Clifton <nickc@redhat.com>
Thu, 2 May 2013 21:06:15 +0000 (21:06 +0000)
* config.bfd (msp430): Define targ_selvecs.
* configure.in: Add bfd_elf32_msp430_ti_vec.
* cpu-msp430.c: Add some more MSP430 machine numbers.
* elf32-msp430.c Add support for MSP430X relocations.
Add support for TI compiler generated relocations.
Add support for sym_diff relocations.
Add support for relaxing out of range short branches into long
branches.
Add support for MSP430 attribute section.
* reloc.c: Add MSP430X relocations.
* targets.c: Add bfd_elf32_msp430_ti_vec.
* bfd-in2.h: Regenerate.
* configure: Regenerate.
* libbfd.h: Regenerate.

* readelf.c: Add support for MSP430X architecture.

* readelf.exp: Expect -wi test to fail for the MSP430.

* config/tc-msp430.c: Add support for the MSP430X architecture.
Add code to insert a NOP instruction after any instruction that
might change the interrupt state.
Add support for the LARGE memory model.
Add code to initialise the .MSP430.attributes section.
* config/tc-msp430.h: Add support for the MSP430X architecture.
* doc/c-msp430.texi: Document the new -mL and -mN command line
options.
* NEWS: Mention support for the MSP430X architecture.

* gas/all/gas.exp: Skip the DIFF1 test for the MSP430.
Expect the FORWARD test to pass for the MSP430.
Skip the REDEF tests for the MSP430.
Expect the 930509A test to fail for the MSP430.
* gas/all/sleb128-4.d: Skip for the MSP430.
* gas/elf/elf.exp: Set target_machine to msp430 for the MSP430.
Skip the EHOPT0 test for the MSP430.
Skip the REDEF and EQU-RELOC tests for the MSP430.
* gas/elf/section2.e-msp430: New file.
* gas/lns/lns-big-delta.d: Remove expectation of 20-bit
addresses.
* gas/lns/lns.exp: Use alternate LNS COMMON test for the MSP430.
* gas/msp430/msp430x.s: New test.
* gas/msp430/msp430x.d: Expected disassembly.
* gas/msp430/msp430.exp: Run new test.
* gas/msp430/opcode.d: Update expected disassembly.

* msp430.h: Add MSP430X relocs.
Add some more MSP430 machine numbers.
Add values used by .MSP430.attributes section.

* msp430.h: Add patterns for MSP430X instructions.

* Makefile.am: Add emsp430X.c
* Makefine.in: Regenerate.
* configure.tgt (msp430): Add msp430X emulation.
* ldmain.c (multiple_definition): Only disable relaxation if it
was enabled by the user.
* ldmain.h (RELAXATION_ENABLED_BY_USER): New macro.
* emulparams/msp430all.sh: Add support for MSP430X.
* emultempl/generic.em: (before_parse): Enable relaxation for the
MSP430.
* scripttempl/msp430.sc: Reorganize sections.  Add .rodata
section.
* scripttempl/msp430_3.sc: Likewise.
* NEWS: Mention support for MSP430X.

* ld-elf/flags1.d: Expect this test to pass on the MSP430.
* ld-elf/init-fini-arrays.d: Expect this test to fail on the
MSP430.
* ld-elf/merge.d: Expect this test to pass on the MSP430.
* ld-elf/sec64k.exp: Skip these tests for the MSP430.
* ld-gc/pr13683.d: Expect this test to fail on the MSP430.
* ld-srec/srec.exp: Expect these tests to fail on the MSP430.
* ld-undefined/undefined.exp: Expect the UNDEFINED LINE test to
fail on the MSP430.

* msp430-dis.c: Add support for MSP430X instructions.

52 files changed:
bfd/ChangeLog
bfd/archures.c
bfd/bfd-in2.h
bfd/config.bfd
bfd/configure
bfd/configure.in
bfd/cpu-msp430.c
bfd/elf32-msp430.c
bfd/libbfd.h
bfd/reloc.c
bfd/targets.c
binutils/readelf.c
binutils/testsuite/ChangeLog
binutils/testsuite/binutils-all/readelf.exp
gas/ChangeLog
gas/NEWS
gas/config/tc-msp430.c
gas/config/tc-msp430.h
gas/doc/c-msp430.texi
gas/testsuite/ChangeLog
gas/testsuite/gas/all/gas.exp
gas/testsuite/gas/all/sleb128-4.d
gas/testsuite/gas/elf/elf.exp
gas/testsuite/gas/lns/lns-big-delta.d
gas/testsuite/gas/lns/lns.exp
gas/testsuite/gas/msp430/msp430.exp
gas/testsuite/gas/msp430/opcode.d
include/elf/ChangeLog
include/elf/msp430.h
include/opcode/ChangeLog
include/opcode/msp430.h
ld/ChangeLog
ld/Makefile.am
ld/Makefile.in
ld/NEWS
ld/configure.tgt
ld/emulparams/msp430all.sh
ld/emultempl/generic.em
ld/ldmain.c
ld/ldmain.h
ld/scripttempl/elf32msp430.sc
ld/scripttempl/elf32msp430_3.sc
ld/testsuite/ChangeLog
ld/testsuite/ld-elf/flags1.d
ld/testsuite/ld-elf/init-fini-arrays.d
ld/testsuite/ld-elf/merge.d
ld/testsuite/ld-elf/sec64k.exp
ld/testsuite/ld-gc/pr13683.d
ld/testsuite/ld-srec/srec.exp
ld/testsuite/ld-undefined/undefined.exp
opcodes/ChangeLog
opcodes/msp430-dis.c

index 2a0ee470961d38eacfb41f52c4a0163c098e510b..7fdc5313317cfc303def576c795ff48d470b6c15 100644 (file)
@@ -1,3 +1,21 @@
+2013-05-02  Nick Clifton  <nickc@redhat.com>
+
+       * archures.c: Add some more MSP430 machine numbers.
+       * config.bfd (msp430): Define targ_selvecs.
+       * configure.in: Add bfd_elf32_msp430_ti_vec.
+       * cpu-msp430.c: Add some more MSP430 machine numbers.
+       * elf32-msp430.c Add support for MSP430X relocations.
+       Add support for TI compiler generated relocations.
+       Add support for sym_diff relocations.
+       Add support for relaxing out of range short branches into long
+       branches.
+       Add support for MSP430 attribute section.
+       * reloc.c: Add MSP430X relocations.
+       * targets.c: Add bfd_elf32_msp430_ti_vec.
+       * bfd-in2.h: Regenerate.
+       * configure: Regenerate.
+       * libbfd.h: Regenerate.
+
 2013-05-01  Maciej W. Rozycki  <macro@codesourcery.com>
 
        * config.bfd: Replace alpha*-*-linuxecoff* pattern with
index 0be72da52843fc5b3b85e5f26b6e87906d646af7..f7cef8bfb253f331818719987705b4257f749e32 100644 (file)
@@ -1,7 +1,5 @@
 /* BFD library support routines for architectures.
-   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011,
-   2012, 2013 Free Software Foundation, Inc.
+   Copyright 1990-2013 Free Software Foundation, Inc.
    Hacked by John Gilmore and Steve Chamberlain of Cygnus Support.
 
    This file is part of BFD, the Binary File Descriptor library.
@@ -437,7 +435,12 @@ DESCRIPTION
 .#define bfd_mach_msp14          14
 .#define bfd_mach_msp15          15
 .#define bfd_mach_msp16          16
+.#define bfd_mach_msp20          20
 .#define bfd_mach_msp21          21
+.#define bfd_mach_msp22          22
+.#define bfd_mach_msp23          23
+.#define bfd_mach_msp24          24
+.#define bfd_mach_msp26          26
 .#define bfd_mach_msp31          31
 .#define bfd_mach_msp32          32
 .#define bfd_mach_msp33          33
@@ -445,6 +448,10 @@ DESCRIPTION
 .#define bfd_mach_msp42          42
 .#define bfd_mach_msp43          43
 .#define bfd_mach_msp44          44
+.#define bfd_mach_msp430x        45
+.#define bfd_mach_msp46          46
+.#define bfd_mach_msp47          47
+.#define bfd_mach_msp54          54
 .  bfd_arch_xc16x,     {* Infineon's XC16X Series.               *}
 .#define bfd_mach_xc16x         1
 .#define bfd_mach_xc16xl        2
index 5c4e9c4594af75942a81b9b8ce128a9c3b19e7d0..0050f46390b18ec7d75efc2cc54f3f53829cdba9 100644 (file)
@@ -2170,7 +2170,12 @@ enum bfd_architecture
 #define bfd_mach_msp14          14
 #define bfd_mach_msp15          15
 #define bfd_mach_msp16          16
+#define bfd_mach_msp20          20
 #define bfd_mach_msp21          21
+#define bfd_mach_msp22          22
+#define bfd_mach_msp23          23
+#define bfd_mach_msp24          24
+#define bfd_mach_msp26          26
 #define bfd_mach_msp31          31
 #define bfd_mach_msp32          32
 #define bfd_mach_msp33          33
@@ -2178,6 +2183,10 @@ enum bfd_architecture
 #define bfd_mach_msp42          42
 #define bfd_mach_msp43          43
 #define bfd_mach_msp44          44
+#define bfd_mach_msp430x        45
+#define bfd_mach_msp46          46
+#define bfd_mach_msp47          47
+#define bfd_mach_msp54          54
   bfd_arch_xc16x,     /* Infineon's XC16X Series.               */
 #define bfd_mach_xc16x         1
 #define bfd_mach_xc16xl        2
@@ -4918,6 +4927,21 @@ a matching LO8XG part.  */
   BFD_RELOC_MSP430_16_BYTE,
   BFD_RELOC_MSP430_2X_PCREL,
   BFD_RELOC_MSP430_RL_PCREL,
+  BFD_RELOC_MSP430_ABS8,
+  BFD_RELOC_MSP430X_PCR20_EXT_SRC,
+  BFD_RELOC_MSP430X_PCR20_EXT_DST,
+  BFD_RELOC_MSP430X_PCR20_EXT_ODST,
+  BFD_RELOC_MSP430X_ABS20_EXT_SRC,
+  BFD_RELOC_MSP430X_ABS20_EXT_DST,
+  BFD_RELOC_MSP430X_ABS20_EXT_ODST,
+  BFD_RELOC_MSP430X_ABS20_ADR_SRC,
+  BFD_RELOC_MSP430X_ABS20_ADR_DST,
+  BFD_RELOC_MSP430X_PCR16,
+  BFD_RELOC_MSP430X_PCR20_CALL,
+  BFD_RELOC_MSP430X_ABS16,
+  BFD_RELOC_MSP430_ABS_HI16,
+  BFD_RELOC_MSP430_PREL31,
+  BFD_RELOC_MSP430_SYM_DIFF,
 
 /* Relocations used by the Altera Nios II core.  */
   BFD_RELOC_NIOS2_S16,
index 563415442390b8e56fa1eae28cf0abb60ff43eaa..ebc9d40a86f346c1a609dad1a3d70acae689bd7e 100644 (file)
@@ -1134,6 +1134,7 @@ case "${targ}" in
 
   msp430-*-*)
     targ_defvec=bfd_elf32_msp430_vec
+    targ_selvecs=bfd_elf32_msp430_ti_vec
     ;;
 
   ns32k-pc532-mach* | ns32k-pc532-ux*)
index 24f6fd3d40f5384d8e70a9aed67e47269be0ba69..5fc08e4febbe384961e0f64349a7953fffce6bf7 100755 (executable)
@@ -15292,6 +15292,7 @@ do
     bfd_elf32_mn10300_vec)     tb="$tb elf-m10300.lo elf32.lo $elf" ;;
     bfd_elf32_mt_vec)           tb="$tb elf32-mt.lo elf32.lo $elf" ;;
     bfd_elf32_msp430_vec)      tb="$tb elf32-msp430.lo elf32.lo $elf" ;;
+    bfd_elf32_msp430_ti_vec)   tb="$tb elf32-msp430.lo elf32.lo $elf" ;;
     bfd_elf32_nbigmips_vec)    tb="$tb elfn32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;;
     bfd_elf32_nlittlemips_vec) tb="$tb elfn32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;;
     bfd_elf32_ntradbigmips_vec | bfd_elf32_ntradbigmips_freebsd_vec)
index d9bef830c7df301008ddfb852ffac315fbd74cad..befcf27094340b1426580f4cbc5b7cd4fad62ee4 100644 (file)
@@ -1,6 +1,6 @@
 dnl Process this file with autoconf to produce a configure script.
 dnl
-dnl   Copyright 2012 Free Software Foundation
+dnl   Copyright 2012-2013 Free Software Foundation
 dnl
 dnl This file is free software; you can redistribute it and/or modify
 dnl it under the terms of the GNU General Public License as published by
@@ -789,6 +789,7 @@ do
     bfd_elf32_mn10300_vec)     tb="$tb elf-m10300.lo elf32.lo $elf" ;;
     bfd_elf32_mt_vec)           tb="$tb elf32-mt.lo elf32.lo $elf" ;;
     bfd_elf32_msp430_vec)      tb="$tb elf32-msp430.lo elf32.lo $elf" ;;
+    bfd_elf32_msp430_ti_vec)   tb="$tb elf32-msp430.lo elf32.lo $elf" ;;
     bfd_elf32_nbigmips_vec)    tb="$tb elfn32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;;
     bfd_elf32_nlittlemips_vec) tb="$tb elfn32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;;
     bfd_elf32_ntradbigmips_vec | bfd_elf32_ntradbigmips_freebsd_vec)
index 09c0e54f014ac3ff97280470942d2dba5f11d8f8..73b6e664dff3afa2cc595645b3bf4bd1e460a3e0 100644 (file)
@@ -1,6 +1,5 @@
 /* BFD library support routines for the MSP architecture.
-   Copyright (C) 2002, 2003, 2005, 2007, 2012
-   Free Software Foundation, Inc.
+   Copyright (C) 2002-2013 Free Software Foundation, Inc.
    Contributed by Dmitry Diky <diwil@mail.ru>
 
    This file is part of BFD, the Binary File Descriptor library.
@@ -82,29 +81,56 @@ static const bfd_arch_info_type arch_info_struct[] =
   /* msp430x16x.  */
   N (16, bfd_mach_msp16, "msp:16", FALSE, & arch_info_struct[7]),
 
+  /* msp430x20x.  */
+  N (16, bfd_mach_msp20, "msp:20", FALSE, & arch_info_struct[8]),
+
   /* msp430x21x.  */
-  N (16, bfd_mach_msp21, "msp:21", FALSE, & arch_info_struct[8]),
+  N (16, bfd_mach_msp21, "msp:21", FALSE, & arch_info_struct[9]),
+
+  /* msp430x22x.  */
+  N (16, bfd_mach_msp22, "msp:22", FALSE, & arch_info_struct[10]),
+
+  /* msp430x23x.  */
+  N (16, bfd_mach_msp23, "msp:23", FALSE, & arch_info_struct[11]),
+
+  /* msp430x24x.  */
+  N (16, bfd_mach_msp24, "msp:24", FALSE, & arch_info_struct[12]),
+
+  /* msp430x26x.  */
+  N (16, bfd_mach_msp26, "msp:26", FALSE, & arch_info_struct[13]),
 
   /* msp430x31x.  */
-  N (16, bfd_mach_msp31, "msp:31", FALSE, & arch_info_struct[9]),
+  N (16, bfd_mach_msp31, "msp:31", FALSE, & arch_info_struct[14]),
 
   /* msp430x32x.  */
-  N (16, bfd_mach_msp32, "msp:32", FALSE, & arch_info_struct[10]),
+  N (16, bfd_mach_msp32, "msp:32", FALSE, & arch_info_struct[15]),
 
   /* msp430x33x.  */
-  N (16, bfd_mach_msp33, "msp:33", FALSE, & arch_info_struct[11]),
+  N (16, bfd_mach_msp33, "msp:33", FALSE, & arch_info_struct[16]),
 
   /* msp430x41x.  */
-  N (16, bfd_mach_msp41, "msp:41", FALSE, & arch_info_struct[12]),
+  N (16, bfd_mach_msp41, "msp:41", FALSE, & arch_info_struct[17]),
 
   /* msp430x42x.  */
-  N (16, bfd_mach_msp42, "msp:42", FALSE, & arch_info_struct[13]),
+  N (16, bfd_mach_msp42, "msp:42", FALSE, & arch_info_struct[18]),
 
   /* msp430x43x.  */
-  N (16, bfd_mach_msp43, "msp:43", FALSE, & arch_info_struct[14]),
+  N (16, bfd_mach_msp43, "msp:43", FALSE, & arch_info_struct[19]),
 
   /* msp430x44x.  */
-  N (16, bfd_mach_msp43, "msp:44", FALSE, NULL)
+  N (16, bfd_mach_msp43, "msp:44", FALSE, & arch_info_struct[20]),
+
+  /* msp430x46x.  */
+  N (16, bfd_mach_msp46, "msp:46", FALSE, & arch_info_struct[21]),
+
+  /* msp430x47x.  */
+  N (16, bfd_mach_msp47, "msp:47", FALSE, & arch_info_struct[22]),
+
+  /* msp430x54x.  */
+  N (16, bfd_mach_msp54, "msp:54", FALSE, & arch_info_struct[23]),
+
+  N (32, bfd_mach_msp430x, "msp:430X", FALSE, NULL)
+
 };
 
 const bfd_arch_info_type bfd_msp430_arch =
index b46e72ce0569485f710c192a945de210bef78da4..6f66282486d285df17acf0096dde40aa00c46b16 100644 (file)
@@ -1,6 +1,5 @@
 /*  MSP430-specific support for 32-bit ELF
-    Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2010, 2012
-    Free Software Foundation, Inc.
+    Copyright (C) 2002-2013 Free Software Foundation, Inc.
     Contributed by Dmitry Diky <diwil@mail.ru>
 
     This file is part of BFD, the Binary File Descriptor library.
@@ -27,9 +26,6 @@
 #include "elf-bfd.h"
 #include "elf/msp430.h"
 
-/* Use RELA instead of REL.  */
-#undef USE_REL
-
 static reloc_howto_type elf_msp430_howto_table[] =
 {
   HOWTO (R_MSP430_NONE,                /* type */
@@ -69,7 +65,7 @@ static reloc_howto_type elf_msp430_howto_table[] =
         0,                     /* bitpos */
         complain_overflow_bitfield,/* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
-        "R_MSP430_13_PCREL",   /* name */
+        "R_MSP430_10_PCREL",   /* name */
         FALSE,                 /* partial_inplace */
         0xfff,                 /* src_mask */
         0xfff,                 /* dst_mask */
@@ -90,7 +86,7 @@ static reloc_howto_type elf_msp430_howto_table[] =
         0xffff,                /* dst_mask */
         FALSE),                /* pcrel_offset */
 
-  /* A 16 bit absolute relocation for command address.  */
+  /* A 16 bit PC relative relocation for command address.  */
   HOWTO (R_MSP430_16_PCREL,    /* type */
         1,                     /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
@@ -164,6 +160,340 @@ static reloc_howto_type elf_msp430_howto_table[] =
         0,                     /* src_mask */
         0xffff,                /* dst_mask */
         TRUE)                  /* pcrel_offset */
+
+  /* A 8-bit absolute relocation.  */
+  , HOWTO (R_MSP430_8,         /* type */
+        0,                     /* rightshift */
+        0,                     /* 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_MSP430_8",          /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  /* Together with a following reloc, allows for the difference
+     between two symbols to be the real addend of the second reloc.  */
+  HOWTO (R_MSP430_SYM_DIFF,    /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        NULL,                  /* special handler.  */
+        "R_MSP430_SYM_DIFF",   /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE)                 /* pcrel_offset */  
+};
+
+static reloc_howto_type elf_msp430x_howto_table[] =
+{
+  HOWTO (R_MSP430_NONE,                /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MSP430_NONE",       /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0,                     /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  HOWTO (R_MSP430_ABS32,       /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MSP430_ABS32",      /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  HOWTO (R_MSP430_ABS16,       /* type */
+        0,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MSP430_ABS16",      /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  HOWTO (R_MSP430_ABS8,                /* type */
+        0,                     /* rightshift */
+        0,                     /* size (0 = byte, 1 = short, 2 = long) */
+        8,                     /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MSP430_ABS8",       /* name */
+        FALSE,                 /* partial_inplace */
+        0xff,                  /* src_mask */
+        0xff,                  /* dst_mask */
+        FALSE),                /* pcrel_offset */
+
+  HOWTO (R_MSP430_PCR16,       /* type */
+        1,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        TRUE,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MSP430_PCR16",      /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_MSP430X_PCR20_EXT_SRC,/* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        TRUE,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MSP430X_PCR20_EXT_SRC",/* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_MSP430X_PCR20_EXT_DST,/* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        TRUE,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MSP430X_PCR20_EXT_DST",/* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_MSP430X_PCR20_EXT_ODST,/* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        TRUE,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MSP430X_PCR20_EXT_ODST",/* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_MSP430X_ABS20_EXT_SRC,/* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        TRUE,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MSP430X_ABS20_EXT_SRC",/* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_MSP430X_ABS20_EXT_DST,/* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        TRUE,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MSP430X_ABS20_EXT_DST",/* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_MSP430X_ABS20_EXT_ODST,/* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        TRUE,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MSP430X_ABS20_EXT_ODST",/* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_MSP430X_ABS20_ADR_SRC,/* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        TRUE,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MSP430X_ABS20_ADR_SRC",/* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_MSP430X_ABS20_ADR_DST,/* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        TRUE,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MSP430X_ABS20_ADR_DST",/* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_MSP430X_PCR16,      /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        TRUE,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MSP430X_PCR16",     /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_MSP430X_PCR20_CALL, /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        TRUE,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MSP430X_PCR20_CALL",/* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_MSP430X_ABS16,      /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        TRUE,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MSP430X_ABS16",     /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_MSP430_ABS_HI16,    /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        TRUE,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MSP430_ABS_HI16",   /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  HOWTO (R_MSP430_PREL31,      /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        TRUE,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MSP430_PREL31",     /* name */
+        FALSE,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffff,                /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  EMPTY_HOWTO (R_MSP430_EHTYPE),
+  
+  /* A 13 bit PC relative relocation.  */
+  HOWTO (R_MSP430X_10_PCREL,   /* type */
+        1,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        10,                    /* bitsize */
+        TRUE,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MSP430X_10_PCREL",  /* name */
+        FALSE,                 /* partial_inplace */
+        0xfff,                 /* src_mask */
+        0xfff,                 /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  /* A 13 bit PC relative relocation for complicated polymorphs.  */
+  HOWTO (R_MSP430X_2X_PCREL,   /* type */
+        1,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        10,                    /* bitsize */
+        TRUE,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_MSP430X_2X_PCREL",  /* name */
+        FALSE,                 /* partial_inplace */
+        0xfff,                 /* src_mask */
+        0xfff,                 /* dst_mask */
+        TRUE),                 /* pcrel_offset */
+
+  /* Together with a following reloc, allows for the difference
+     between two symbols to be the real addend of the second reloc.  */
+  HOWTO (R_MSP430X_SYM_DIFF,   /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        NULL,                  /* special handler.  */
+        "R_MSP430X_SYM_DIFF",  /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffffff,            /* src_mask */
+        0xffffffff,            /* dst_mask */
+        FALSE)                 /* pcrel_offset */  
 };
 
 /* Map BFD reloc types to MSP430 ELF reloc types.  */
@@ -175,18 +505,55 @@ struct msp430_reloc_map
 };
 
 static const struct msp430_reloc_map msp430_reloc_map[] =
-  {
-    {BFD_RELOC_NONE,                 R_MSP430_NONE},
-    {BFD_RELOC_32,                   R_MSP430_32},
-    {BFD_RELOC_MSP430_10_PCREL,      R_MSP430_10_PCREL},
-    {BFD_RELOC_16,                   R_MSP430_16_BYTE},
-    {BFD_RELOC_MSP430_16_PCREL,      R_MSP430_16_PCREL},
-    {BFD_RELOC_MSP430_16,            R_MSP430_16},
-    {BFD_RELOC_MSP430_16_PCREL_BYTE, R_MSP430_16_PCREL_BYTE},
-    {BFD_RELOC_MSP430_16_BYTE,       R_MSP430_16_BYTE},
-    {BFD_RELOC_MSP430_2X_PCREL,      R_MSP430_2X_PCREL},
-    {BFD_RELOC_MSP430_RL_PCREL,      R_MSP430_RL_PCREL}
-  };
+{
+  {BFD_RELOC_NONE,                 R_MSP430_NONE},
+  {BFD_RELOC_32,                   R_MSP430_32},
+  {BFD_RELOC_MSP430_10_PCREL,      R_MSP430_10_PCREL},
+  {BFD_RELOC_16,                   R_MSP430_16_BYTE},
+  {BFD_RELOC_MSP430_16_PCREL,      R_MSP430_16_PCREL},
+  {BFD_RELOC_MSP430_16,            R_MSP430_16},
+  {BFD_RELOC_MSP430_16_PCREL_BYTE, R_MSP430_16_PCREL_BYTE},
+  {BFD_RELOC_MSP430_16_BYTE,       R_MSP430_16_BYTE},
+  {BFD_RELOC_MSP430_2X_PCREL,      R_MSP430_2X_PCREL},
+  {BFD_RELOC_MSP430_RL_PCREL,      R_MSP430_RL_PCREL},
+  {BFD_RELOC_8,                    R_MSP430_8},
+  {BFD_RELOC_MSP430_SYM_DIFF,      R_MSP430_SYM_DIFF}
+};
+
+static const struct msp430_reloc_map msp430x_reloc_map[] =
+{
+  {BFD_RELOC_NONE,                    R_MSP430_NONE},
+  {BFD_RELOC_32,                      R_MSP430_ABS32},
+  {BFD_RELOC_16,                      R_MSP430_ABS16},
+  {BFD_RELOC_8,                       R_MSP430_ABS8},
+  {BFD_RELOC_MSP430_ABS8,             R_MSP430_ABS8},
+  {BFD_RELOC_MSP430X_PCR20_EXT_SRC,   R_MSP430X_PCR20_EXT_SRC},
+  {BFD_RELOC_MSP430X_PCR20_EXT_DST,   R_MSP430X_PCR20_EXT_DST},
+  {BFD_RELOC_MSP430X_PCR20_EXT_ODST,  R_MSP430X_PCR20_EXT_ODST},
+  {BFD_RELOC_MSP430X_ABS20_EXT_SRC,   R_MSP430X_ABS20_EXT_SRC},
+  {BFD_RELOC_MSP430X_ABS20_EXT_DST,   R_MSP430X_ABS20_EXT_DST},
+  {BFD_RELOC_MSP430X_ABS20_EXT_ODST,  R_MSP430X_ABS20_EXT_ODST},
+  {BFD_RELOC_MSP430X_ABS20_ADR_SRC,   R_MSP430X_ABS20_ADR_SRC},
+  {BFD_RELOC_MSP430X_ABS20_ADR_DST,   R_MSP430X_ABS20_ADR_DST},
+  {BFD_RELOC_MSP430X_PCR16,           R_MSP430X_PCR16},
+  {BFD_RELOC_MSP430X_PCR20_CALL,      R_MSP430X_PCR20_CALL},
+  {BFD_RELOC_MSP430X_ABS16,           R_MSP430X_ABS16},
+  {BFD_RELOC_MSP430_ABS_HI16,         R_MSP430_ABS_HI16},
+  {BFD_RELOC_MSP430_PREL31,           R_MSP430_PREL31},
+  {BFD_RELOC_MSP430_10_PCREL,         R_MSP430X_10_PCREL},
+  {BFD_RELOC_MSP430_2X_PCREL,         R_MSP430X_2X_PCREL},
+  {BFD_RELOC_MSP430_RL_PCREL,         R_MSP430X_PCR16},
+  {BFD_RELOC_MSP430_SYM_DIFF,         R_MSP430X_SYM_DIFF}
+};
+
+static inline bfd_boolean
+uses_msp430x_relocs (bfd * abfd)
+{
+  extern const bfd_target bfd_elf32_msp430_ti_vec;
+
+  return bfd_get_mach (abfd) == bfd_mach_msp430x
+    || abfd->xvec == & bfd_elf32_msp430_ti_vec;
+}
 
 static reloc_howto_type *
 bfd_elf32_bfd_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED,
@@ -194,9 +561,18 @@ bfd_elf32_bfd_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED,
 {
   unsigned int i;
 
-  for (i = 0; i < ARRAY_SIZE (msp430_reloc_map); i++)
-    if (msp430_reloc_map[i].bfd_reloc_val == code)
-      return &elf_msp430_howto_table[msp430_reloc_map[i].elf_reloc_val];
+  if (uses_msp430x_relocs (abfd))
+    {
+      for (i = ARRAY_SIZE (msp430x_reloc_map); i--;)
+       if (msp430x_reloc_map[i].bfd_reloc_val == code)
+         return elf_msp430x_howto_table + msp430x_reloc_map[i].elf_reloc_val;
+    }
+  else
+    {
+      for (i = 0; i < ARRAY_SIZE (msp430_reloc_map); i++)
+       if (msp430_reloc_map[i].bfd_reloc_val == code)
+         return &elf_msp430_howto_table[msp430_reloc_map[i].elf_reloc_val];
+    }
 
   return NULL;
 }
@@ -207,13 +583,23 @@ bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
 {
   unsigned int i;
 
-  for (i = 0;
-       i < (sizeof (elf_msp430_howto_table)
-           / sizeof (elf_msp430_howto_table[0]));
-       i++)
-    if (elf_msp430_howto_table[i].name != NULL
-       && strcasecmp (elf_msp430_howto_table[i].name, r_name) == 0)
-      return &elf_msp430_howto_table[i];
+  if (uses_msp430x_relocs (abfd))
+    {
+      for (i = ARRAY_SIZE (elf_msp430x_howto_table); i--;)
+       if (elf_msp430x_howto_table[i].name != NULL
+           && strcasecmp (elf_msp430x_howto_table[i].name, r_name) == 0)
+         return elf_msp430x_howto_table + i;
+    }
+  else
+    {
+      for (i = 0;
+          i < (sizeof (elf_msp430_howto_table)
+               / sizeof (elf_msp430_howto_table[0]));
+          i++)
+       if (elf_msp430_howto_table[i].name != NULL
+           && strcasecmp (elf_msp430_howto_table[i].name, r_name) == 0)
+         return &elf_msp430_howto_table[i];
+    }
 
   return NULL;
 }
@@ -228,6 +614,14 @@ msp430_info_to_howto_rela (bfd * abfd ATTRIBUTE_UNUSED,
   unsigned int r_type;
 
   r_type = ELF32_R_TYPE (dst->r_info);
+
+  if (uses_msp430x_relocs (abfd))
+    {
+      BFD_ASSERT (r_type < (unsigned int) R_MSP430x_max);
+      cache_ptr->howto = elf_msp430x_howto_table + r_type;
+      return;
+    }
+
   BFD_ASSERT (r_type < (unsigned int) R_MSP430_max);
   cache_ptr->howto = &elf_msp430_howto_table[r_type];
 }
@@ -280,16 +674,413 @@ elf32_msp430_check_relocs (bfd * abfd, struct bfd_link_info * info,
    routines, but a few relocs, we have to do them ourselves.  */
 
 static bfd_reloc_status_type
-msp430_final_link_relocate (reloc_howto_type * howto, bfd * input_bfd,
-                           asection * input_section, bfd_byte * contents,
-                           Elf_Internal_Rela * rel, bfd_vma relocation)
+msp430_final_link_relocate (reloc_howto_type *     howto,
+                           bfd *                  input_bfd,
+                           asection *             input_section,
+                           bfd_byte *             contents,
+                           Elf_Internal_Rela *    rel,
+                           bfd_vma                relocation,
+                           struct bfd_link_info * info)
 {
+  static asection *  sym_diff_section;
+  static bfd_vma     sym_diff_value;
+
+  struct bfd_elf_section_data * esd = elf_section_data (input_section);
   bfd_reloc_status_type r = bfd_reloc_ok;
   bfd_vma x;
   bfd_signed_vma srel;
+  bfd_boolean is_rel_reloc = FALSE;
+
+  if (uses_msp430x_relocs (input_bfd))
+    {
+      /* See if we have a REL type relocation.  */
+      is_rel_reloc = (esd->rel.hdr != NULL);
+      /* Sanity check - only one type of relocation per section.
+        FIXME: Theoretically it is possible to have both types,
+        but if that happens how can we distinguish between the two ?  */
+      BFD_ASSERT (! is_rel_reloc || ! esd->rela.hdr);
+      /* If we are using a REL relocation then the addend should be empty.  */
+      BFD_ASSERT (! is_rel_reloc || rel->r_addend == 0);
+    }
 
-  switch (howto->type)
+  if (sym_diff_section != NULL)
     {
+      BFD_ASSERT (sym_diff_section == input_section);
+     if (uses_msp430x_relocs (input_bfd))
+       switch (howto->type)
+        {
+        case R_MSP430_ABS32:
+         /* If we are computing a 32-bit value for the location lists
+            and the result is 0 then we add one to the value.  A zero
+            value can result because of linker relaxation deleteing
+            prologue instructions and using a value of 1 (for the begin
+            and end offsets in the location list entry) results in a
+            nul entry which does not prevent the following entries from
+            being parsed.  */
+          if (relocation == sym_diff_value
+              && strcmp (input_section->name, ".debug_loc") == 0)
+            ++ relocation;
+          /* Fall through.  */
+        case R_MSP430_ABS16:
+        case R_MSP430X_ABS16:
+        case R_MSP430_ABS8:
+          BFD_ASSERT (! is_rel_reloc);
+          relocation -= sym_diff_value;
+         break;
+
+        default:
+          return bfd_reloc_dangerous;
+        }
+     else
+       switch (howto->type)
+        {
+        case R_MSP430_32:
+        case R_MSP430_16:
+        case R_MSP430_16_BYTE:
+        case R_MSP430_8:
+          relocation -= sym_diff_value;
+         break;
+
+        default:
+          return bfd_reloc_dangerous;
+        }
+       
+      sym_diff_section = NULL;
+    }
+
+  if (uses_msp430x_relocs (input_bfd))
+    switch (howto->type)
+      {
+      case R_MSP430X_SYM_DIFF:
+       /* Cache the input section and value.
+          The offset is unreliable, since relaxation may
+          have reduced the following reloc's offset.  */
+       BFD_ASSERT (! is_rel_reloc);
+       sym_diff_section = input_section;
+       sym_diff_value = relocation;
+       return bfd_reloc_ok;
+
+      case R_MSP430_ABS16:
+       contents += rel->r_offset;
+       srel = (bfd_signed_vma) relocation;
+       if (is_rel_reloc)
+         srel += bfd_get_16 (input_bfd, contents);
+       else
+         srel += rel->r_addend;
+       bfd_put_16 (input_bfd, srel & 0xffff, contents);
+       break;
+
+      case R_MSP430X_10_PCREL:
+       contents += rel->r_offset;
+       srel = (bfd_signed_vma) relocation;
+       if (is_rel_reloc)
+         srel += bfd_get_16 (input_bfd, contents) & 0x3ff;
+       else
+         srel += rel->r_addend;
+       srel -= rel->r_offset;
+       srel -= 2;              /* Branch instructions add 2 to the PC...  */
+       srel -= (input_section->output_section->vma +
+                input_section->output_offset);
+       if (srel & 1)
+         return bfd_reloc_outofrange;
+
+       /* MSP430 addresses commands as words.  */
+       srel >>= 1;
+
+       /* Check for an overflow.  */
+       if (srel < -512 || srel > 511)
+         {
+           if (info->disable_target_specific_optimizations < 0)
+             {
+               static bfd_boolean warned = FALSE;
+               if (! warned)
+                 {
+                   info->callbacks->warning
+                     (info,
+                      _("Try enabling relaxation to avoid relocation truncations"),
+                      NULL, input_bfd, input_section, relocation);
+                   warned = TRUE;
+                 }
+             }
+           return bfd_reloc_overflow;
+         }
+
+       x = bfd_get_16 (input_bfd, contents);
+       x = (x & 0xfc00) | (srel & 0x3ff);
+       bfd_put_16 (input_bfd, x, contents);
+       break;
+
+      case R_MSP430X_PCR20_EXT_ODST:
+       /* [0,4]+[48,16] = ---F ---- FFFF */
+       contents += rel->r_offset;
+       srel = (bfd_signed_vma) relocation;
+       if (is_rel_reloc)
+         {
+           bfd_vma addend;
+           addend = (bfd_get_16 (input_bfd, contents) & 0xf) << 16;
+           addend |= bfd_get_16 (input_bfd, contents+4);
+           srel += addend;
+           
+         }
+       else
+         srel += rel->r_addend;
+       srel -= rel->r_offset;
+       srel -= (input_section->output_section->vma +
+                input_section->output_offset);
+       bfd_put_16 (input_bfd, (srel & 0xffff), contents + 6);
+       x = bfd_get_16 (input_bfd, contents);
+       x = (x & 0xfff0) | ((srel >> 16) & 0xf);
+       bfd_put_16 (input_bfd, x, contents);
+       break;
+
+      case R_MSP430X_ABS20_EXT_SRC:
+       /* [7,4]+[32,16] = -78- FFFF */
+       contents += rel->r_offset;
+       srel = (bfd_signed_vma) relocation;
+       if (is_rel_reloc)
+         {
+           bfd_vma addend;
+           addend = (bfd_get_16 (input_bfd, contents) & 0x0780) << 9;
+           addend |= bfd_get_16 (input_bfd, contents+2);
+           srel += addend;
+         }
+       else
+         srel += rel->r_addend;
+       bfd_put_16 (input_bfd, (srel & 0xffff), contents + 4);
+       srel >>= 16;
+       x = bfd_get_16 (input_bfd, contents);
+       x = (x & 0xf87f) | ((srel << 7) & 0x0780);
+       bfd_put_16 (input_bfd, x, contents);
+       break;
+
+      case R_MSP430_16_PCREL:
+       contents += rel->r_offset;
+       srel = (bfd_signed_vma) relocation;
+       if (is_rel_reloc)
+         srel += bfd_get_16 (input_bfd, contents);
+       else
+         srel += rel->r_addend;
+       srel -= rel->r_offset;
+       /* Only branch instructions add 2 to the PC...  */
+       srel -= (input_section->output_section->vma +
+                input_section->output_offset);
+       if (srel & 1)
+         return bfd_reloc_outofrange;
+       bfd_put_16 (input_bfd, srel & 0xffff, contents);
+       break;
+
+      case R_MSP430X_PCR20_EXT_DST:
+       /* [0,4]+[32,16] = ---F FFFF */
+       contents += rel->r_offset;
+       srel = (bfd_signed_vma) relocation;
+       if (is_rel_reloc)
+         {
+           bfd_vma addend;
+           addend = (bfd_get_16 (input_bfd, contents) & 0xf) << 16;
+           addend |= bfd_get_16 (input_bfd, contents+2);
+           srel += addend;
+         }
+       else
+         srel += rel->r_addend;
+       srel -= rel->r_offset;
+       srel -= (input_section->output_section->vma +
+                input_section->output_offset);
+       bfd_put_16 (input_bfd, (srel & 0xffff), contents + 4);
+       srel >>= 16;
+       x = bfd_get_16 (input_bfd, contents);
+       x = (x & 0xfff0) | (srel & 0xf);
+       bfd_put_16 (input_bfd, x, contents);
+       break;
+
+      case R_MSP430X_PCR20_EXT_SRC:
+       /* [7,4]+32,16] = -78- FFFF */
+       contents += rel->r_offset;
+       srel = (bfd_signed_vma) relocation;
+       if (is_rel_reloc)
+         {
+           bfd_vma addend;
+           addend = ((bfd_get_16 (input_bfd, contents) & 0x0780) << 9);
+           addend |= bfd_get_16 (input_bfd, contents+2);
+           srel += addend;;
+         }
+       else
+         srel += rel->r_addend;
+       srel -= rel->r_offset;
+       /* Only branch instructions add 2 to the PC...  */
+       srel -= (input_section->output_section->vma +
+                input_section->output_offset);
+       bfd_put_16 (input_bfd, (srel & 0xffff), contents + 4);
+       srel >>= 16;
+       x = bfd_get_16 (input_bfd, contents);
+       x = (x & 0xf87f) | ((srel << 7) & 0x0780);
+       bfd_put_16 (input_bfd, x, contents);
+       break;
+
+      case R_MSP430_ABS8:
+       contents += rel->r_offset;
+       srel = (bfd_signed_vma) relocation;
+       if (is_rel_reloc)
+         srel += bfd_get_8 (input_bfd, contents);
+       else
+         srel += rel->r_addend;
+       bfd_put_8 (input_bfd, srel & 0xff, contents);
+       break;
+
+      case R_MSP430X_ABS20_EXT_DST:
+       contents += rel->r_offset;
+       srel = (bfd_signed_vma) relocation;
+       if (is_rel_reloc)
+         srel += bfd_get_16 (input_bfd, contents) & 0xf;
+       else
+         srel += rel->r_addend;
+       bfd_put_16 (input_bfd, (srel & 0xffff), contents + 4);
+       srel >>= 16;
+       x = bfd_get_16 (input_bfd, contents);
+       x = (x & 0xfff0) | (srel & 0xf);
+       bfd_put_16 (input_bfd, x, contents);
+       break;
+
+      case R_MSP430X_ABS20_EXT_ODST:
+       /* [0,4]+[48,16] = ---F ---- FFFF */
+       contents += rel->r_offset;
+       srel = (bfd_signed_vma) relocation;
+       if (is_rel_reloc)
+         {
+           bfd_vma addend;
+           addend = (bfd_get_16 (input_bfd, contents) & 0xf) << 16;
+           addend |= bfd_get_16 (input_bfd, contents+4);
+           srel += addend;
+         }
+       else
+         srel += rel->r_addend;
+       bfd_put_16 (input_bfd, (srel & 0xffff), contents + 6);
+       srel >>= 16;
+       x = bfd_get_16 (input_bfd, contents);
+       x = (x & 0xfff0) | (srel & 0xf);
+       bfd_put_16 (input_bfd, x, contents);
+       break;
+
+      case R_MSP430X_ABS20_ADR_SRC:
+       /* [8,4]+[32,16] = -F-- FFFF */
+       contents += rel->r_offset;
+       srel = (bfd_signed_vma) relocation;
+       if (is_rel_reloc)
+         {
+           bfd_vma addend;
+
+           addend = ((bfd_get_16 (input_bfd, contents) & 0xf00) << 8);
+           addend |= bfd_get_16 (input_bfd, contents+2);
+           srel += addend;
+         }
+       else
+         srel += rel->r_addend;
+       bfd_put_16 (input_bfd, (srel & 0xffff), contents + 2);
+       srel >>= 16;
+       x = bfd_get_16 (input_bfd, contents);
+       x = (x & 0xf0ff) | ((srel << 8) & 0x0f00);
+       bfd_put_16 (input_bfd, x, contents);
+       break;
+
+      case R_MSP430X_ABS20_ADR_DST:
+       /* [0,4]+[32,16] = ---F FFFF */
+       contents += rel->r_offset;
+       srel = (bfd_signed_vma) relocation;
+       if (is_rel_reloc)
+         {
+           bfd_vma addend;
+           addend = ((bfd_get_16 (input_bfd, contents) & 0xf) << 16);
+           addend |= bfd_get_16 (input_bfd, contents+2);
+           srel += addend;
+         }
+       else
+         srel += rel->r_addend;
+       bfd_put_16 (input_bfd, (srel & 0xffff), contents + 2);
+       srel >>= 16;
+       x = bfd_get_16 (input_bfd, contents);
+       x = (x & 0xfff0) | (srel & 0xf);
+       bfd_put_16 (input_bfd, x, contents);
+       break;
+
+      case R_MSP430X_ABS16:
+       contents += rel->r_offset;
+       srel = (bfd_signed_vma) relocation;
+       if (is_rel_reloc)
+         srel += bfd_get_16 (input_bfd, contents);
+       else
+         srel += rel->r_addend;
+       x = srel;
+       if (x > 0xffff)
+         return bfd_reloc_overflow;    
+       bfd_put_16 (input_bfd, srel & 0xffff, contents);
+       break;
+
+      case R_MSP430_ABS_HI16:
+       /* The EABI specifies that this must be a RELA reloc.  */
+       BFD_ASSERT (! is_rel_reloc);
+       contents += rel->r_offset;
+       srel = (bfd_signed_vma) relocation;
+       srel += rel->r_addend;
+       bfd_put_16 (input_bfd, (srel >> 16) & 0xffff, contents);
+       break;
+      
+      case R_MSP430X_PCR20_CALL:
+       /* [0,4]+[32,16] = ---F FFFF*/
+       contents += rel->r_offset;
+       srel = (bfd_signed_vma) relocation;
+       if (is_rel_reloc)
+         {
+           bfd_vma addend;
+           addend = (bfd_get_16 (input_bfd, contents) & 0xf) << 16;
+           addend |= bfd_get_16 (input_bfd, contents+2);
+           srel += addend;
+         }
+       else
+         srel += rel->r_addend;
+       srel -= rel->r_offset;
+       srel -= (input_section->output_section->vma +
+                input_section->output_offset);
+       bfd_put_16 (input_bfd, srel & 0xffff, contents + 2);
+       srel >>= 16;
+       x = bfd_get_16 (input_bfd, contents);
+       x = (x & 0xfff0) | (srel & 0xf);
+       bfd_put_16 (input_bfd, x, contents);
+       break;
+       
+      case R_MSP430X_PCR16:
+       contents += rel->r_offset;
+       srel = (bfd_signed_vma) relocation;
+       if (is_rel_reloc)
+         srel += bfd_get_16 (input_bfd, contents);
+       else
+         srel += rel->r_addend;
+       srel -= rel->r_offset;
+       srel -= (input_section->output_section->vma +
+                input_section->output_offset);
+       bfd_put_16 (input_bfd, srel & 0xffff, contents);
+       break;
+      
+      case R_MSP430_PREL31:
+       contents += rel->r_offset;
+       srel = (bfd_signed_vma) relocation;
+       if (is_rel_reloc)
+         srel += (bfd_get_32 (input_bfd, contents) & 0x7fffffff);
+       else
+         srel += rel->r_addend;
+       srel += rel->r_addend;
+       x = bfd_get_32 (input_bfd, contents);
+       x = (x & 0x80000000) | ((srel >> 31) & 0x7fffffff);
+       bfd_put_32 (input_bfd, x, contents);
+       break;
+       
+      default:
+       r = _bfd_final_link_relocate (howto, input_bfd, input_section,
+                                     contents, rel->r_offset,
+                                     relocation, rel->r_addend);
+      }
+  else
+    switch (howto->type)
+      {
     case R_MSP430_10_PCREL:
       contents += rel->r_offset;
       srel = (bfd_signed_vma) relocation;
@@ -307,8 +1098,22 @@ msp430_final_link_relocate (reloc_howto_type * howto, bfd * input_bfd,
 
       /* Check for an overflow.  */
       if (srel < -512 || srel > 511)
-       return bfd_reloc_overflow;
-
+       {
+         if (info->disable_target_specific_optimizations < 0)
+           {
+             static bfd_boolean warned = FALSE;
+             if (! warned)
+               {
+                 info->callbacks->warning
+                   (info,
+                    _("Try enabling relaxation to avoid relocation truncations"),
+                    NULL, input_bfd, input_section, relocation);
+                 warned = TRUE;
+               }
+           }
+         return bfd_reloc_overflow;
+       }
+      
       x = bfd_get_16 (input_bfd, contents);
       x = (x & 0xfc00) | (srel & 0x3ff);
       bfd_put_16 (input_bfd, x, contents);
@@ -389,11 +1194,27 @@ msp430_final_link_relocate (reloc_howto_type * howto, bfd * input_bfd,
       bfd_put_16 (input_bfd, srel & 0xffff, contents);
       break;
 
-    default:
-      r = _bfd_final_link_relocate (howto, input_bfd, input_section,
-                                   contents, rel->r_offset,
-                                   relocation, rel->r_addend);
-    }
+    case R_MSP430_8:
+      contents += rel->r_offset;
+      srel = (bfd_signed_vma) relocation;
+      srel += rel->r_addend;
+
+      bfd_put_8 (input_bfd, srel & 0xff, contents);
+      break;
+        
+    case R_MSP430_SYM_DIFF:
+      /* Cache the input section and value.
+        The offset is unreliable, since relaxation may
+        have reduced the following reloc's offset.  */
+      sym_diff_section = input_section;
+      sym_diff_value = relocation;
+      return bfd_reloc_ok;
+
+      default:
+       r = _bfd_final_link_relocate (howto, input_bfd, input_section,
+                                     contents, rel->r_offset,
+                                     relocation, rel->r_addend);
+      }
 
   return r;
 }
@@ -433,7 +1254,12 @@ elf32_msp430_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED,
 
       r_type = ELF32_R_TYPE (rel->r_info);
       r_symndx = ELF32_R_SYM (rel->r_info);
-      howto = elf_msp430_howto_table + r_type;
+
+      if (uses_msp430x_relocs (input_bfd))
+       howto = elf_msp430x_howto_table + r_type;
+      else
+       howto = elf_msp430_howto_table + r_type;
+
       h = NULL;
       sym = NULL;
       sec = NULL;
@@ -446,7 +1272,7 @@ elf32_msp430_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED,
 
          name = bfd_elf_string_from_elf_section
              (input_bfd, symtab_hdr->sh_link, sym->st_name);
-         name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
+         name = (name == NULL || * name == 0) ? bfd_section_name (input_bfd, sec) : name;
        }
       else
        {
@@ -456,6 +1282,7 @@ elf32_msp430_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED,
                                   r_symndx, symtab_hdr, sym_hashes,
                                   h, sec, relocation,
                                   unresolved_reloc, warned);
+         name = h->root.root.string;
        }
 
       if (sec != NULL && discarded_section (sec))
@@ -466,7 +1293,7 @@ elf32_msp430_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED,
        continue;
 
       r = msp430_final_link_relocate (howto, input_bfd, input_section,
-                                     contents, rel, relocation);
+                                     contents, rel, relocation, info);
 
       if (r != bfd_reloc_ok)
        {
@@ -476,7 +1303,7 @@ elf32_msp430_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED,
            {
            case bfd_reloc_overflow:
              r = info->callbacks->reloc_overflow
-                 (info, (h ? &h->root : NULL), name, howto->name,
+               (info, (h ? &h->root : NULL), name, howto->name,
                   (bfd_vma) 0, input_bfd, input_section,
                   rel->r_offset);
              break;
@@ -487,7 +1314,7 @@ elf32_msp430_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED,
              break;
 
            case bfd_reloc_outofrange:
-             msg = _("internal error: out of range error");
+             msg = _("internal error: branch/jump to an odd address detected");
              break;
 
            case bfd_reloc_notsupported:
@@ -529,61 +1356,29 @@ bfd_elf_msp430_final_write_processing (bfd * abfd,
   switch (bfd_get_mach (abfd))
     {
     default:
-    case bfd_mach_msp110:
-      val = E_MSP430_MACH_MSP430x11x1;
-      break;
-
-    case bfd_mach_msp11:
-      val = E_MSP430_MACH_MSP430x11;
-      break;
-
-    case bfd_mach_msp12:
-      val = E_MSP430_MACH_MSP430x12;
-      break;
-
-    case bfd_mach_msp13:
-      val = E_MSP430_MACH_MSP430x13;
-      break;
-
-    case bfd_mach_msp14:
-      val = E_MSP430_MACH_MSP430x14;
-      break;
-
-    case bfd_mach_msp15:
-      val = E_MSP430_MACH_MSP430x15;
-      break;
-
-    case bfd_mach_msp16:
-      val = E_MSP430_MACH_MSP430x16;
-      break;
-
-    case bfd_mach_msp31:
-      val = E_MSP430_MACH_MSP430x31;
-      break;
-
-    case bfd_mach_msp32:
-      val = E_MSP430_MACH_MSP430x32;
-      break;
-
-    case bfd_mach_msp33:
-      val = E_MSP430_MACH_MSP430x33;
-      break;
-
-    case bfd_mach_msp41:
-      val = E_MSP430_MACH_MSP430x41;
-      break;
-
-    case bfd_mach_msp42:
-      val = E_MSP430_MACH_MSP430x42;
-      break;
-
-    case bfd_mach_msp43:
-      val = E_MSP430_MACH_MSP430x43;
-      break;
-
-    case bfd_mach_msp44:
-      val = E_MSP430_MACH_MSP430x44;
-      break;
+    case bfd_mach_msp110: val = E_MSP430_MACH_MSP430x11x1; break;
+    case bfd_mach_msp11: val = E_MSP430_MACH_MSP430x11; break;
+    case bfd_mach_msp12: val = E_MSP430_MACH_MSP430x12; break;
+    case bfd_mach_msp13: val = E_MSP430_MACH_MSP430x13; break;
+    case bfd_mach_msp14: val = E_MSP430_MACH_MSP430x14; break;
+    case bfd_mach_msp15: val = E_MSP430_MACH_MSP430x15; break;
+    case bfd_mach_msp16: val = E_MSP430_MACH_MSP430x16; break;
+    case bfd_mach_msp31: val = E_MSP430_MACH_MSP430x31; break;
+    case bfd_mach_msp32: val = E_MSP430_MACH_MSP430x32; break;
+    case bfd_mach_msp33: val = E_MSP430_MACH_MSP430x33; break;
+    case bfd_mach_msp41: val = E_MSP430_MACH_MSP430x41; break;
+    case bfd_mach_msp42: val = E_MSP430_MACH_MSP430x42; break;
+    case bfd_mach_msp43: val = E_MSP430_MACH_MSP430x43; break;
+    case bfd_mach_msp44: val = E_MSP430_MACH_MSP430x44; break;
+    case bfd_mach_msp20: val = E_MSP430_MACH_MSP430x20; break;
+    case bfd_mach_msp22: val = E_MSP430_MACH_MSP430x22; break;
+    case bfd_mach_msp23: val = E_MSP430_MACH_MSP430x23; break;
+    case bfd_mach_msp24: val = E_MSP430_MACH_MSP430x24; break;
+    case bfd_mach_msp26: val = E_MSP430_MACH_MSP430x26; break;
+    case bfd_mach_msp46: val = E_MSP430_MACH_MSP430x46; break;
+    case bfd_mach_msp47: val = E_MSP430_MACH_MSP430x47; break;
+    case bfd_mach_msp54: val = E_MSP430_MACH_MSP430x54; break;
+    case bfd_mach_msp430x: val = E_MSP430_MACH_MSP430X; break;
     }
 
   elf_elfheader (abfd)->e_machine = EM_MSP430;
@@ -606,64 +1401,32 @@ elf32_msp430_object_p (bfd * abfd)
       switch (e_mach)
        {
        default:
-       case E_MSP430_MACH_MSP430x11:
-         e_set = bfd_mach_msp11;
-         break;
-
-       case E_MSP430_MACH_MSP430x11x1:
-         e_set = bfd_mach_msp110;
-         break;
-
-       case E_MSP430_MACH_MSP430x12:
-         e_set = bfd_mach_msp12;
-         break;
-
-       case E_MSP430_MACH_MSP430x13:
-         e_set = bfd_mach_msp13;
-         break;
-
-       case E_MSP430_MACH_MSP430x14:
-         e_set = bfd_mach_msp14;
-         break;
-
-       case E_MSP430_MACH_MSP430x15:
-         e_set = bfd_mach_msp15;
-         break;
-
-       case E_MSP430_MACH_MSP430x16:
-         e_set = bfd_mach_msp16;
-         break;
-
-       case E_MSP430_MACH_MSP430x31:
-         e_set = bfd_mach_msp31;
-         break;
-
-       case E_MSP430_MACH_MSP430x32:
-         e_set = bfd_mach_msp32;
-         break;
-
-       case E_MSP430_MACH_MSP430x33:
-         e_set = bfd_mach_msp33;
-         break;
-
-       case E_MSP430_MACH_MSP430x41:
-         e_set = bfd_mach_msp41;
-         break;
-
-       case E_MSP430_MACH_MSP430x42:
-         e_set = bfd_mach_msp42;
-         break;
-
-       case E_MSP430_MACH_MSP430x43:
-         e_set = bfd_mach_msp43;
-         break;
-
-       case E_MSP430_MACH_MSP430x44:
-         e_set = bfd_mach_msp44;
-         break;
+       case E_MSP430_MACH_MSP430x11: e_set = bfd_mach_msp11; break;
+       case E_MSP430_MACH_MSP430x11x1: e_set = bfd_mach_msp110; break;
+       case E_MSP430_MACH_MSP430x12: e_set = bfd_mach_msp12; break;
+       case E_MSP430_MACH_MSP430x13: e_set = bfd_mach_msp13; break;
+       case E_MSP430_MACH_MSP430x14: e_set = bfd_mach_msp14; break;
+       case E_MSP430_MACH_MSP430x15: e_set = bfd_mach_msp15; break;
+       case E_MSP430_MACH_MSP430x16: e_set = bfd_mach_msp16; break;
+       case E_MSP430_MACH_MSP430x31: e_set = bfd_mach_msp31; break;
+       case E_MSP430_MACH_MSP430x32: e_set = bfd_mach_msp32; break;
+       case E_MSP430_MACH_MSP430x33: e_set = bfd_mach_msp33; break;
+       case E_MSP430_MACH_MSP430x41: e_set = bfd_mach_msp41; break;
+       case E_MSP430_MACH_MSP430x42: e_set = bfd_mach_msp42; break;
+       case E_MSP430_MACH_MSP430x43: e_set = bfd_mach_msp43; break;
+       case E_MSP430_MACH_MSP430x44: e_set = bfd_mach_msp44; break;
+       case E_MSP430_MACH_MSP430x20: e_set = bfd_mach_msp20; break;
+       case E_MSP430_MACH_MSP430x22: e_set = bfd_mach_msp22; break;
+       case E_MSP430_MACH_MSP430x23: e_set = bfd_mach_msp23; break;
+       case E_MSP430_MACH_MSP430x24: e_set = bfd_mach_msp24; break;
+       case E_MSP430_MACH_MSP430x26: e_set = bfd_mach_msp26; break;
+       case E_MSP430_MACH_MSP430x46: e_set = bfd_mach_msp46; break;
+       case E_MSP430_MACH_MSP430x47: e_set = bfd_mach_msp47; break;
+       case E_MSP430_MACH_MSP430x54: e_set = bfd_mach_msp54; break;
+       case E_MSP430_MACH_MSP430X: e_set = bfd_mach_msp430x; break;
        }
     }
-
+  
   return bfd_default_set_arch_mach (abfd, bfd_arch_msp430, e_set);
 }
 
@@ -674,6 +1437,8 @@ elf32_msp430_object_p (bfd * abfd)
     - Sibling calls. This will affect only 'jump label' polymorph. Without
       relaxing this enlarges code by 2 bytes. Sibcalls implemented but
       do not work in gcc's port by the reason I do not know.
+    - To convert out of range conditional jump instructions (found inside
+      a function) into inverted jumps over an unconditional branch instruction.
    Anyway, if a relaxation required, user should pass -relax option to the
    linker.
 
@@ -797,11 +1562,13 @@ msp430_elf_symbol_address_p (bfd * abfd,
   return FALSE;
 }
 
-/* Adjust all local symbols defined as '.section + 0xXXXX' (.section has sec_shndx)
-    referenced from current and other sections.  */
+/* Adjust all local symbols defined as '.section + 0xXXXX' (.section has
+   sec_shndx) referenced from current and other sections.  */
+
 static bfd_boolean
-msp430_elf_relax_adjust_locals(bfd * abfd, asection * sec, bfd_vma addr,
-    int count, unsigned int sec_shndx, bfd_vma toaddr)
+msp430_elf_relax_adjust_locals (bfd * abfd, asection * sec, bfd_vma addr,
+                               int count, unsigned int sec_shndx,
+                               bfd_vma toaddr)
 {
   Elf_Internal_Shdr *symtab_hdr;
   Elf_Internal_Rela *irel;
@@ -809,21 +1576,24 @@ msp430_elf_relax_adjust_locals(bfd * abfd, asection * sec, bfd_vma addr,
   Elf_Internal_Sym *isym;
 
   irel = elf_section_data (sec)->relocs;
+  if (irel == NULL)
+    return TRUE;
+
   irelend = irel + sec->reloc_count;
   symtab_hdr = & elf_tdata (abfd)->symtab_hdr;
   isym = (Elf_Internal_Sym *) symtab_hdr->contents;
-
-  for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++)
+  
+  for (;irel < irelend; irel++)
     {
       int sidx = ELF32_R_SYM(irel->r_info);
       Elf_Internal_Sym *lsym = isym + sidx;
-
+      
       /* Adjust symbols referenced by .sec+0xXX */
-      if (irel->r_addend > addr && irel->r_addend < toaddr
+      if (irel->r_addend > addr && irel->r_addend < toaddr 
          && lsym->st_shndx == sec_shndx)
        irel->r_addend -= count;
     }
-
+  
   return TRUE;
 }
 
@@ -863,7 +1633,7 @@ msp430_elf_relax_delete_bytes (bfd * abfd, asection * sec, bfd_vma addr,
   /* Adjust all the relocs.  */
   symtab_hdr = & elf_tdata (abfd)->symtab_hdr;
   isym = (Elf_Internal_Sym *) symtab_hdr->contents;
-  for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++)
+  for (; irel < irelend; irel++)
     {
       /* Get the new reloc address.  */
       if ((irel->r_offset > addr && irel->r_offset < toaddr))
@@ -871,8 +1641,8 @@ msp430_elf_relax_delete_bytes (bfd * abfd, asection * sec, bfd_vma addr,
     }
 
   for (p = abfd->sections; p != NULL; p = p->next)
-    msp430_elf_relax_adjust_locals(abfd,p,addr,count,sec_shndx,toaddr);
-
+    msp430_elf_relax_adjust_locals (abfd,p,addr,count,sec_shndx,toaddr);
+  
   /* Adjust the local symbols defined in this section.  */
   symtab_hdr = & elf_tdata (abfd)->symtab_hdr;
   isym = (Elf_Internal_Sym *) symtab_hdr->contents;
@@ -901,6 +1671,82 @@ msp430_elf_relax_delete_bytes (bfd * abfd, asection * sec, bfd_vma addr,
   return TRUE;
 }
 
+/* Insert two words into a section whilst relaxing.  */
+
+static bfd_byte *
+msp430_elf_relax_add_two_words (bfd * abfd, asection * sec, bfd_vma addr,
+                               int word1, int word2)
+{
+  Elf_Internal_Shdr *symtab_hdr;
+  unsigned int sec_shndx;
+  bfd_byte *contents;
+  Elf_Internal_Rela *irel;
+  Elf_Internal_Rela *irelend;
+  Elf_Internal_Sym *isym;
+  Elf_Internal_Sym *isymend;
+  struct elf_link_hash_entry **sym_hashes;
+  struct elf_link_hash_entry **end_hashes;
+  unsigned int symcount;
+  bfd_vma sec_end;
+  asection *p;
+
+  contents = elf_section_data (sec)->this_hdr.contents;
+  sec_end = sec->size;
+
+  /* Make space for the new words.  */
+  contents = bfd_realloc (contents, sec_end + 4);
+  memmove (contents + addr + 4, contents + addr, sec_end - addr);
+
+  /* Insert the new words.  */
+  bfd_put_16 (abfd, word1, contents + addr);
+  bfd_put_16 (abfd, word2, contents + addr + 2);
+
+  /* Update the section information.  */
+  sec->size += 4;
+  elf_section_data (sec)->this_hdr.contents = contents;  
+
+  /* Adjust all the relocs.  */
+  irel = elf_section_data (sec)->relocs;
+  irelend = irel + sec->reloc_count;
+
+  for (; irel < irelend; irel++)
+    if ((irel->r_offset >= addr && irel->r_offset < sec_end))
+      irel->r_offset += 4;
+
+  /* Adjust the local symbols defined in this section.  */
+  sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
+  for (p = abfd->sections; p != NULL; p = p->next)
+    msp430_elf_relax_adjust_locals (abfd, p, addr, -4,
+                                   sec_shndx, sec_end);
+
+  /* Adjust the global symbols affected by the move.  */
+  symtab_hdr = & elf_tdata (abfd)->symtab_hdr;
+  isym = (Elf_Internal_Sym *) symtab_hdr->contents;
+  for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++)
+    if (isym->st_shndx == sec_shndx
+       && isym->st_value >= addr && isym->st_value < sec_end)
+      isym->st_value += 4;
+
+  /* Now adjust the global symbols defined in this section.  */
+  symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
+             - symtab_hdr->sh_info);
+  sym_hashes = elf_sym_hashes (abfd);
+  end_hashes = sym_hashes + symcount;
+  for (; sym_hashes < end_hashes; sym_hashes++)
+    {
+      struct elf_link_hash_entry *sym_hash = *sym_hashes;
+
+      if ((sym_hash->root.type == bfd_link_hash_defined
+          || sym_hash->root.type == bfd_link_hash_defweak)
+         && sym_hash->root.u.def.section == sec
+         && sym_hash->root.u.def.value >= addr
+         && sym_hash->root.u.def.value < sec_end)
+       sym_hash->root.u.def.value += 4;
+    }
+
+  return contents;
+}
+   
 static bfd_boolean
 msp430_elf_relax_section (bfd * abfd, asection * sec,
                          struct bfd_link_info * link_info,
@@ -913,6 +1759,7 @@ msp430_elf_relax_section (bfd * abfd, asection * sec,
   bfd_byte *          contents = NULL;
   Elf_Internal_Sym *  isymbuf = NULL;
 
+
   /* Assume nothing changes.  */
   *again = FALSE;
 
@@ -920,8 +1767,8 @@ msp430_elf_relax_section (bfd * abfd, asection * sec,
      this section does not have relocs, or if this is not a
      code section.  */
   if (link_info->relocatable
-      || (sec->flags & SEC_RELOC) == 0
-      || sec->reloc_count == 0 || (sec->flags & SEC_CODE) == 0)
+    || (sec->flags & SEC_RELOC) == 0
+    || sec->reloc_count == 0 || (sec->flags & SEC_CODE) == 0)
     return TRUE;
 
   symtab_hdr = & elf_tdata (abfd)->symtab_hdr;
@@ -934,13 +1781,21 @@ msp430_elf_relax_section (bfd * abfd, asection * sec,
 
   /* Walk through them looking for relaxing opportunities.  */
   irelend = internal_relocs + sec->reloc_count;
+
+  /* Do code size growing relocs first.  */
   for (irel = internal_relocs; irel < irelend; irel++)
     {
       bfd_vma symval;
 
       /* If this isn't something that can be relaxed, then ignore
          this reloc.  */
-      if (ELF32_R_TYPE (irel->r_info) != (int) R_MSP430_RL_PCREL)
+      if (uses_msp430x_relocs (abfd)
+          && ELF32_R_TYPE (irel->r_info) == (int) R_MSP430X_10_PCREL)
+       ;
+      else if (! uses_msp430x_relocs (abfd)
+               && ELF32_R_TYPE (irel->r_info) == (int) R_MSP430_10_PCREL)
+       ;
+      else
        continue;
 
       /* Get the section contents if we haven't done so already.  */
@@ -1014,108 +1869,287 @@ msp430_elf_relax_section (bfd * abfd, asection * sec,
          that would be more work, but would require less memory when
          the linker is run.  */
 
-      /* Try to turn a 16bit pc-relative branch into a 10bit pc-relative
-         branch.  */
-      /* Paranoia? paranoia...  */
-      if (ELF32_R_TYPE (irel->r_info) == (int) R_MSP430_RL_PCREL)
-       {
-         bfd_vma value = symval;
+      bfd_signed_vma value = symval;
+      int opcode;
 
-         /* Deal with pc-relative gunk.  */
-         value -= (sec->output_section->vma + sec->output_offset);
-         value -= irel->r_offset;
-         value += irel->r_addend;
+      /* Compute the value that will be relocated.  */
+      value += irel->r_addend;
+      /* Convert to PC relative.  */
+      value -= (sec->output_section->vma + sec->output_offset);
+      value -= irel->r_offset;
+      value -= 2;
+      /* Scale.  */
+      value >>= 1;
 
-         /* See if the value will fit in 10 bits, note the high value is
-            1016 as the target will be two bytes closer if we are
-            able to relax. */
-         if ((long) value < 1016 && (long) value > -1016)
-           {
-             int code0 = 0, code1 = 0, code2 = 0;
-             int i;
-             struct rcodes_s *rx;
+      /* If it is in range then no modifications are needed.  */
+      if (value >= -512 && value <= 511)
+       continue;
 
-             /* Get the opcode.  */
-             if (irel->r_offset >= 6)
-               code0 = bfd_get_16 (abfd, contents + irel->r_offset - 6);
+      /* Get the opcode.  */
+      opcode = bfd_get_16 (abfd, contents + irel->r_offset);
+         
+      /* Compute the new opcode.  We are going to convert:
+        J<cond> label
+        into:
+        J<inv-cond> 1f
+        BR[A] #label
+        1:                     */
+      switch (opcode & 0xfc00)
+       {
+       case 0x3800: opcode = 0x3402; break; /* Jl  -> Jge +2 */  
+       case 0x3400: opcode = 0x3802; break; /* Jge -> Jl  +2 */
+       case 0x2c00: opcode = 0x2802; break; /* Jhs -> Jlo +2 */
+       case 0x2800: opcode = 0x2c02; break; /* Jlo -> Jhs +2 */
+       case 0x2400: opcode = 0x2002; break; /* Jeq -> Jne +2 */
+       case 0x2000: opcode = 0x2402; break; /* jne -> Jeq +2 */
+       case 0x3000: /* jn    */
+         /* There is no direct inverse of the Jn insn.
+            FIXME: we could do this as:
+               Jn 1f
+               br 2f
+            1: br label
+            2:                */
+         continue;
+       default:
+         /* Not a conditional branch instruction.  */
+         /* fprintf (stderr, "unrecog: %x\n", opcode); */
+         goto error_return;
+       }
 
-             if (irel->r_offset >= 4)
-               code1 = bfd_get_16 (abfd, contents + irel->r_offset - 4);
+      /* Note that we've changed the relocs, section contents, etc.  */
+      elf_section_data (sec)->relocs = internal_relocs;
+      elf_section_data (sec)->this_hdr.contents = contents;
+      symtab_hdr->contents = (unsigned char *) isymbuf;
 
-             code2 = bfd_get_16 (abfd, contents + irel->r_offset - 2);
+      /* Install the new opcode.  */
+      bfd_put_16 (abfd, opcode, contents + irel->r_offset);
 
-             if (code2 != 0x4010)
-               continue;
+      /* Insert the new branch instruction.  */
+      if (uses_msp430x_relocs (abfd))
+       {
+         /* Insert an absolute branch (aka MOVA) instruction.  */        
+         contents = msp430_elf_relax_add_two_words
+           (abfd, sec, irel->r_offset + 2, 0x0080, 0x0000);
+
+         /* Update the relocation to point to the inserted branch
+            instruction.  Note - we are changing a PC-relative reloc
+            into an absolute reloc, but this is OK because we have
+            arranged with the assembler to have the reloc's value be
+            a (local) symbol, not a section+offset value.  */
+         irel->r_offset += 2;
+         irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
+                                      R_MSP430X_ABS20_ADR_SRC);
+       }
+      else
+       {
+         contents = msp430_elf_relax_add_two_words
+           (abfd, sec, irel->r_offset + 2, 0x4030, 0x0000);
+
+         /* See comment above about converting a 10-bit PC-rel
+            relocation into a 16-bit absolute relocation.  */
+         irel->r_offset += 4;
+         irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
+                                      R_MSP430_16);
+       }
 
-             /* Check r4 and r3.  */
-             for (i = NUMB_RELAX_CODES - 1; i >= 0; i--)
-               {
-                 rx = &rcode[i];
-                 if (rx->cdx == 2 && rx->f0 == code0 && rx->f1 == code1)
-                   break;
-                 else if (rx->cdx == 1 && rx->f1 == code1)
-                   break;
-                 else if (rx->cdx == 0)        /* This is an unconditional jump.  */
-                   break;
-               }
+      /* Growing the section may mean that other
+        conditional branches need to be fixed.  */
+      *again = TRUE;
+    }
 
-             /* Check labels:
+  if (! uses_msp430x_relocs (abfd))
+    /* Now perform the relocations that shrink the code size.
+       We only do this for non msp430x as gas only generates the RL
+       reloc for the msp430.  */
+    for (irel = internal_relocs; irel < irelend; irel++)
+      {
+       bfd_vma symval;
+
+       /* Get the section contents if we haven't done so already.  */
+       if (contents == NULL)
+         {
+           /* Get cached copy if it exists.  */
+           if (elf_section_data (sec)->this_hdr.contents != NULL)
+             contents = elf_section_data (sec)->this_hdr.contents;
+           else if (! bfd_malloc_and_get_section (abfd, sec, &contents))
+             goto error_return;
+         }
+
+       /* Read this BFD's local symbols if we haven't done so already.  */
+       if (isymbuf == NULL && symtab_hdr->sh_info != 0)
+         {
+           isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
+           if (isymbuf == NULL)
+             isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
+                                             symtab_hdr->sh_info, 0,
+                                             NULL, NULL, NULL);
+           if (isymbuf == NULL)
+             goto error_return;
+         }
+
+       /* Get the value of the symbol referred to by the reloc.  */
+       if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
+         {
+           /* A local symbol.  */
+           Elf_Internal_Sym *isym;
+           asection *sym_sec;
+
+           isym = isymbuf + ELF32_R_SYM (irel->r_info);
+           if (isym->st_shndx == SHN_UNDEF)
+             sym_sec = bfd_und_section_ptr;
+           else if (isym->st_shndx == SHN_ABS)
+             sym_sec = bfd_abs_section_ptr;
+           else if (isym->st_shndx == SHN_COMMON)
+             sym_sec = bfd_com_section_ptr;
+           else
+             sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
+           symval = (isym->st_value
+                     + sym_sec->output_section->vma + sym_sec->output_offset);
+         }
+       else
+         {
+           unsigned long indx;
+           struct elf_link_hash_entry *h;
+
+           /* An external symbol.  */
+           indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
+           h = elf_sym_hashes (abfd)[indx];
+           BFD_ASSERT (h != NULL);
+
+           if (h->root.type != bfd_link_hash_defined
+               && h->root.type != bfd_link_hash_defweak)
+             /* This appears to be a reference to an undefined
+                symbol.  Just ignore it--it will be caught by the
+                regular reloc processing.  */
+             continue;
+
+           symval = (h->root.u.def.value
+                     + h->root.u.def.section->output_section->vma
+                     + h->root.u.def.section->output_offset);
+         }
+
+       /* For simplicity of coding, we are going to modify the section
+          contents, the section relocs, and the BFD symbol table.  We
+          must tell the rest of the code not to free up this
+          information.  It would be possible to instead create a table
+          of changes which have to be made, as is done in coff-mips.c;
+          that would be more work, but would require less memory when
+          the linker is run.  */
+
+       /* Try to turn a 16bit pc-relative branch into a 10bit pc-relative
+          branch.  */
+       /* Paranoia? paranoia...  */      
+       if (ELF32_R_TYPE (irel->r_info) == (int) R_MSP430_RL_PCREL)
+         {
+           bfd_vma value = symval;
+
+           /* Deal with pc-relative gunk.  */
+           value -= (sec->output_section->vma + sec->output_offset);
+           value -= irel->r_offset;
+           value += irel->r_addend;
+
+           /* See if the value will fit in 10 bits, note the high value is
+              1016 as the target will be two bytes closer if we are
+              able to relax.  */
+           if ((long) value < 1016 && (long) value > -1016)
+             {
+               int code0 = 0, code1 = 0, code2 = 0;
+               int i;
+               struct rcodes_s *rx;
+
+               /* Get the opcode.  */
+               if (irel->r_offset >= 6)
+                 code0 = bfd_get_16 (abfd, contents + irel->r_offset - 6);
+
+               if (irel->r_offset >= 4)
+                 code1 = bfd_get_16 (abfd, contents + irel->r_offset - 4);
+
+               code2 = bfd_get_16 (abfd, contents + irel->r_offset - 2);
+
+               if (code2 != 0x4010)
+                 continue;
+
+               /* Check r4 and r3.  */
+               for (i = NUMB_RELAX_CODES - 1; i >= 0; i--)
+                 {
+                   rx = &rcode[i];
+                   if (rx->cdx == 2 && rx->f0 == code0 && rx->f1 == code1)
+                     break;
+                   else if (rx->cdx == 1 && rx->f1 == code1)
+                     break;
+                   else if (rx->cdx == 0)      /* This is an unconditional jump.  */
+                     break;
+                 }
+
+               /* Check labels:
                   .Label0:       ; we do not care about this label
-                     jeq    +6
+                  jeq    +6
                   .Label1:       ; make sure there is no label here
-                     jl     +4
+                  jl     +4
                   .Label2:       ; make sure there is no label here
-                     br .Label_dst
-
-                So, if there is .Label1 or .Label2 we cannot relax this code.
-                This actually should not happen, cause for relaxable
-                instructions we use RL_PCREL reloc instead of 16_PCREL.
-                Will change this in the future. */
-
-             if (rx->cdx > 0
-                 && msp430_elf_symbol_address_p (abfd, sec, isymbuf,
-                                                 irel->r_offset - 2))
-               continue;
-             if (rx->cdx > 1
-                 && msp430_elf_symbol_address_p (abfd, sec, isymbuf,
-                                                 irel->r_offset - 4))
-               continue;
-
-             /* Note that we've changed the relocs, section contents, etc.  */
-             elf_section_data (sec)->relocs = internal_relocs;
-             elf_section_data (sec)->this_hdr.contents = contents;
-             symtab_hdr->contents = (unsigned char *) isymbuf;
-
-             /* Fix the relocation's type.  */
-             if (rx->labels == 3)      /* Handle special cases.  */
-               irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
-                                          R_MSP430_2X_PCREL);
-             else
-               irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
-                                          R_MSP430_10_PCREL);
-
-             /* Fix the opcode right way.  */
-             bfd_put_16 (abfd, rx->t0, contents + irel->r_offset - rx->off);
-             if (rx->t1)
-               bfd_put_16 (abfd, rx->t1,
-                           contents + irel->r_offset - rx->off + 2);
-
-             /* Delete bytes. */
-             if (!msp430_elf_relax_delete_bytes (abfd, sec,
-                                                 irel->r_offset - rx->off +
-                                                 rx->ncl, rx->bs))
-               goto error_return;
-
-             /* Handle unconditional jumps.  */
-             if (rx->cdx == 0)
-               irel->r_offset -= 2;
-
-             /* That will change things, so, we should relax again.
-                Note that this is not required, and it may be slow.  */
-             *again = TRUE;
-           }
-       }
-    }
+                  br .Label_dst
+
+                  So, if there is .Label1 or .Label2 we cannot relax this code.
+                  This actually should not happen, cause for relaxable
+                  instructions we use RL_PCREL reloc instead of 16_PCREL.
+                  Will change this in the future. */
+
+               if (rx->cdx > 0
+                   && msp430_elf_symbol_address_p (abfd, sec, isymbuf,
+                                                   irel->r_offset - 2))
+                 continue;
+               if (rx->cdx > 1
+                   && msp430_elf_symbol_address_p (abfd, sec, isymbuf,
+                                                   irel->r_offset - 4))
+                 continue;
+
+               /* Note that we've changed the relocs, section contents, etc.  */
+               elf_section_data (sec)->relocs = internal_relocs;
+               elf_section_data (sec)->this_hdr.contents = contents;
+               symtab_hdr->contents = (unsigned char *) isymbuf;
+
+               /* Fix the relocation's type.  */
+               if (uses_msp430x_relocs (abfd))
+                 {
+                   if (rx->labels == 3)        /* Handle special cases.  */
+                     irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
+                                                  R_MSP430X_2X_PCREL);
+                   else
+                     irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
+                                                  R_MSP430X_10_PCREL);
+                 }
+               else
+                 {
+                   if (rx->labels == 3)        /* Handle special cases.  */
+                     irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
+                                                  R_MSP430_2X_PCREL);
+                   else
+                     irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
+                                                  R_MSP430_10_PCREL);
+                 }
+
+               /* Fix the opcode right way.  */
+               bfd_put_16 (abfd, rx->t0, contents + irel->r_offset - rx->off);
+               if (rx->t1)
+                 bfd_put_16 (abfd, rx->t1,
+                             contents + irel->r_offset - rx->off + 2);
+
+               /* Delete bytes. */
+               if (!msp430_elf_relax_delete_bytes (abfd, sec,
+                                                   irel->r_offset - rx->off +
+                                                   rx->ncl, rx->bs))
+                 goto error_return;
+
+               /* Handle unconditional jumps.  */
+               if (rx->cdx == 0)
+                 irel->r_offset -= 2;
+
+               /* That will change things, so, we should relax again.
+                  Note that this is not required, and it may be slow.  */
+               *again = TRUE;
+             }
+         }
+      }
 
   if (isymbuf != NULL && symtab_hdr->contents != (unsigned char *) isymbuf)
     {
@@ -1159,11 +2193,259 @@ error_return:
   return FALSE;
 }
 
+/* Handle an MSP430 specific section when reading an object file.
+   This is called when bfd_section_from_shdr finds a section with
+   an unknown type.  */
+
+static bfd_boolean
+elf32_msp430_section_from_shdr (bfd *abfd,
+                               Elf_Internal_Shdr * hdr,
+                               const char *name,
+                               int shindex)
+{
+  switch (hdr->sh_type)
+    {
+    case SHT_MSP430_SEC_FLAGS:
+    case SHT_MSP430_SYM_ALIASES:
+    case SHT_MSP430_ATTRIBUTES:
+      return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
+    default:
+      return FALSE;
+    }
+}
+
+static bfd_boolean
+elf32_msp430_obj_attrs_handle_unknown (bfd *abfd, int tag)
+{
+  _bfd_error_handler
+    (_("Warning: %B: Unknown MSPABI object attribute %d"),
+     abfd, tag);
+  return TRUE;
+}
+
+/* Determine whether an object attribute tag takes an integer, a
+   string or both.  */
+
+static int
+elf32_msp430_obj_attrs_arg_type (int tag)
+{
+  if (tag == Tag_compatibility)
+    return ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL;
+
+  if (tag < 32)
+    return ATTR_TYPE_FLAG_INT_VAL;
+
+  return (tag & 1) != 0 ? ATTR_TYPE_FLAG_STR_VAL : ATTR_TYPE_FLAG_INT_VAL;
+}
+
+static inline const char *
+isa_type (int isa)
+{
+  switch (isa)
+    {
+    case 1: return "MSP430";
+    case 2: return "MSP430X";
+    default: return "unknown";
+    }
+}
+
+static inline const char *
+code_model (int model)
+{
+  switch (model)
+    {
+    case 1: return "small";
+    case 2: return "large";
+    default: return "unknown";
+    }
+}
+
+static inline const char *
+data_model (int model)
+{
+  switch (model)
+    {
+    case 1: return "small";
+    case 2: return "large";
+    case 3: return "restricted large";
+    default: return "unknown";
+    }
+}
+
+/* Merge MSPABI object attributes from IBFD into OBFD.
+   Raise an error if there are conflicting attributes.  */
+
+static bfd_boolean
+elf32_msp430_merge_mspabi_attributes (bfd *ibfd, bfd *obfd)
+{
+  obj_attribute *in_attr;
+  obj_attribute *out_attr;
+  bfd_boolean result = TRUE;
+  static bfd * first_input_bfd = NULL;
+
+  /* Skip linker created files.  */
+  if (ibfd->flags & BFD_LINKER_CREATED)
+    return TRUE;
+
+  /* If this is the first real object just copy the attributes.  */
+  if (!elf_known_obj_attributes_proc (obfd)[0].i)
+    {
+      _bfd_elf_copy_obj_attributes (ibfd, obfd);
+
+      out_attr = elf_known_obj_attributes_proc (obfd);
+
+      /* Use the Tag_null value to indicate that
+        the attributes have been initialized.  */
+      out_attr[0].i = 1;
+
+      first_input_bfd = ibfd;
+      return TRUE;
+    }
+
+  in_attr = elf_known_obj_attributes_proc (ibfd);
+  out_attr = elf_known_obj_attributes_proc (obfd);
+
+  /* The ISAs must be the same.  */
+  if (in_attr[OFBA_MSPABI_Tag_ISA].i != out_attr[OFBA_MSPABI_Tag_ISA].i)
+    {
+      _bfd_error_handler
+       (_("error: %B uses %s instructions but %B uses %s"),
+        ibfd, first_input_bfd,
+        isa_type (in_attr[OFBA_MSPABI_Tag_ISA].i),
+        isa_type (out_attr[OFBA_MSPABI_Tag_ISA].i));
+      result = FALSE;
+    }
+
+  /* The code models must be the same.  */
+  if (in_attr[OFBA_MSPABI_Tag_Code_Model].i !=
+      out_attr[OFBA_MSPABI_Tag_Code_Model].i)
+    {
+      _bfd_error_handler
+       (_("error: %B uses the %s code model whereas %B uses the %s code model"),
+        ibfd, first_input_bfd,
+        code_model (in_attr[OFBA_MSPABI_Tag_Code_Model].i),
+        code_model (out_attr[OFBA_MSPABI_Tag_Code_Model].i));
+      result = FALSE;
+    }
+
+  /* The large code model is only supported by the MSP430X.  */
+  if (in_attr[OFBA_MSPABI_Tag_Code_Model].i == 2
+      && out_attr[OFBA_MSPABI_Tag_ISA].i != 2)
+    {
+      _bfd_error_handler
+       (_("error: %B uses the large code model but %B uses MSP430 instructions"),
+        ibfd, first_input_bfd);
+      result = FALSE;
+    }
+
+  /* The data models must be the same.  */
+  if (in_attr[OFBA_MSPABI_Tag_Data_Model].i !=
+      out_attr[OFBA_MSPABI_Tag_Data_Model].i)
+    {
+      _bfd_error_handler
+       (_("error: %B uses the %s data model whereas %B uses the %s data model"),
+        ibfd, first_input_bfd,
+        data_model (in_attr[OFBA_MSPABI_Tag_Data_Model].i),
+        data_model (out_attr[OFBA_MSPABI_Tag_Data_Model].i));
+      result = FALSE;
+    }
+
+  /* The small code model requires the use of the small data model.  */
+  if (in_attr[OFBA_MSPABI_Tag_Code_Model].i == 1
+      && out_attr[OFBA_MSPABI_Tag_Data_Model].i != 1)
+    {
+      _bfd_error_handler
+       (_("error: %B uses the small code model but %B uses the %s data model"),
+        ibfd, first_input_bfd,
+        data_model (out_attr[OFBA_MSPABI_Tag_Data_Model].i));
+      result = FALSE;
+    }
+
+  /* The large data models are only supported by the MSP430X.  */
+  if (in_attr[OFBA_MSPABI_Tag_Data_Model].i > 1
+      && out_attr[OFBA_MSPABI_Tag_ISA].i != 2)
+    {
+      _bfd_error_handler
+       (_("error: %B uses the %s data model but %B only uses MSP430 instructions"),
+        ibfd, first_input_bfd,
+        data_model (in_attr[OFBA_MSPABI_Tag_Data_Model].i));
+      result = FALSE;
+    }
+  
+  return result;
+}
+
+/* Merge backend specific data from an object file to the output
+   object file when linking.  */
+
+static bfd_boolean
+elf32_msp430_merge_private_bfd_data (bfd * ibfd, bfd * obfd)
+{
+  /* Make sure that the machine number reflects the most
+     advanced version of the MSP architecture required.  */
+#define max(a,b) ((a) > (b) ? (a) : (b))
+  if (bfd_get_mach (ibfd) != bfd_get_mach (obfd))
+    bfd_default_set_arch_mach (obfd, bfd_get_arch (obfd),
+                              max (bfd_get_mach (ibfd), bfd_get_mach (obfd)));
+#undef max
+
+  return elf32_msp430_merge_mspabi_attributes (ibfd, obfd);
+}
+
+/* Copy backend specific data from one object module to another.  */
+
+static bfd_boolean
+elf32_msp430_copy_private_bfd_data (bfd *ibfd, bfd *obfd)
+{
+  /* Copy object attributes.  */
+  _bfd_elf_copy_obj_attributes (ibfd, obfd);
+
+  return TRUE;
+}
+
+static bfd_boolean
+msp430_elf_is_target_special_symbol (bfd *abfd, asymbol *sym)
+{
+  return _bfd_elf_is_local_label_name (abfd, sym->name);
+}
+
+/* This is gross.  The MSP430 EABI says that (sec 11.5):
+
+     "An implementation may choose to use Rel or Rela
+      type relocations for other relocations."
+
+   But it also says that:
+   
+     "Certain relocations are identified as Rela only. [snip]
+      Where Rela is specified, an implementation must honor
+      this requirement."
+
+  There is one relocation marked as requiring RELA - R_MSP430_ABS_HI16 - but
+  to keep things simple we choose to use RELA relocations throughout.  The
+  problem is that the TI compiler generates REL relocations, so we have to
+  be able to accept those as well.  */
+
+#define elf_backend_may_use_rel_p  1
+#define elf_backend_may_use_rela_p 1
+#define elf_backend_default_use_rela_p 1
+
+#undef  elf_backend_obj_attrs_vendor
+#define elf_backend_obj_attrs_vendor           "mspabi"
+#undef  elf_backend_obj_attrs_section
+#define elf_backend_obj_attrs_section          ".MSP430.attributes"
+#undef  elf_backend_obj_attrs_section_type
+#define elf_backend_obj_attrs_section_type     SHT_MSP430_ATTRIBUTES
+#define elf_backend_section_from_shdr                  elf32_msp430_section_from_shdr
+#define elf_backend_obj_attrs_handle_unknown   elf32_msp430_obj_attrs_handle_unknown
+#undef  elf_backend_obj_attrs_arg_type
+#define elf_backend_obj_attrs_arg_type         elf32_msp430_obj_attrs_arg_type
+#define bfd_elf32_bfd_copy_private_bfd_data    elf32_msp430_copy_private_bfd_data
+#define bfd_elf32_bfd_merge_private_bfd_data   elf32_msp430_merge_private_bfd_data
 
 #define ELF_ARCH               bfd_arch_msp430
 #define ELF_MACHINE_CODE       EM_MSP430
 #define ELF_MACHINE_ALT1       EM_MSP430_OLD
-#define ELF_MAXPAGESIZE                1
+#define ELF_MAXPAGESIZE                4
 #define        ELF_OSABI               ELFOSABI_STANDALONE
 
 #define TARGET_LITTLE_SYM       bfd_elf32_msp430_vec
@@ -1178,5 +2460,30 @@ error_return:
 #define elf_backend_object_p                elf32_msp430_object_p
 #define elf_backend_post_process_headers     _bfd_elf_set_osabi
 #define bfd_elf32_bfd_relax_section         msp430_elf_relax_section
+#define bfd_elf32_bfd_is_target_special_symbol msp430_elf_is_target_special_symbol
+
+#undef  elf32_bed
+#define elf32_bed              elf32_msp430_bed
+
+#include "elf32-target.h"
+
+/* The TI compiler sets the OSABI field to ELFOSABI_NONE.  */
+#undef  TARGET_LITTLE_SYM
+#define TARGET_LITTLE_SYM       bfd_elf32_msp430_ti_vec
+
+#undef  elf32_bed
+#define elf32_bed              elf32_msp430_ti_bed
+
+#undef ELF_OSABI               
+#define        ELF_OSABI               ELFOSABI_NONE
+
+static const struct bfd_elf_special_section msp430_ti_elf_special_sections[] =
+{
+  /* prefix, prefix_length,        suffix_len, type,               attributes.  */
+  { STRING_COMMA_LEN (".TI.symbol.alias"),  0, SHT_MSP430_SYM_ALIASES, 0 },
+  { STRING_COMMA_LEN (".TI.section.flags"), 0, SHT_MSP430_SEC_FLAGS,   0 },
+  { STRING_COMMA_LEN ("_TI_build_attrib"),  0, SHT_MSP430_ATTRIBUTES,  0 },
+  { NULL, 0,                                0, 0,                      0 }
+};
 
 #include "elf32-target.h"
index 6a4b5724f9919823c5ca3e1e9a1d919e1e3f07d7..1c4d36f91ae692b13302573d23c342ddabca2041 100644 (file)
@@ -2376,6 +2376,21 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_MSP430_16_BYTE",
   "BFD_RELOC_MSP430_2X_PCREL",
   "BFD_RELOC_MSP430_RL_PCREL",
+  "BFD_RELOC_MSP430_ABS8",
+  "BFD_RELOC_MSP430X_PCR20_EXT_SRC",
+  "BFD_RELOC_MSP430X_PCR20_EXT_DST",
+  "BFD_RELOC_MSP430X_PCR20_EXT_ODST",
+  "BFD_RELOC_MSP430X_ABS20_EXT_SRC",
+  "BFD_RELOC_MSP430X_ABS20_EXT_DST",
+  "BFD_RELOC_MSP430X_ABS20_EXT_ODST",
+  "BFD_RELOC_MSP430X_ABS20_ADR_SRC",
+  "BFD_RELOC_MSP430X_ABS20_ADR_DST",
+  "BFD_RELOC_MSP430X_PCR16",
+  "BFD_RELOC_MSP430X_PCR20_CALL",
+  "BFD_RELOC_MSP430X_ABS16",
+  "BFD_RELOC_MSP430_ABS_HI16",
+  "BFD_RELOC_MSP430_PREL31",
+  "BFD_RELOC_MSP430_SYM_DIFF",
   "BFD_RELOC_NIOS2_S16",
   "BFD_RELOC_NIOS2_U16",
   "BFD_RELOC_NIOS2_CALL26",
index e93b3b9da9df243e6187535973688761f0bfd112..57df51b391829e45d841a84c57f6c11509cb659c 100644 (file)
@@ -5662,6 +5662,36 @@ ENUMX
   BFD_RELOC_MSP430_2X_PCREL
 ENUMX
   BFD_RELOC_MSP430_RL_PCREL
+ENUMX
+  BFD_RELOC_MSP430_ABS8
+ENUMX
+  BFD_RELOC_MSP430X_PCR20_EXT_SRC
+ENUMX
+  BFD_RELOC_MSP430X_PCR20_EXT_DST
+ENUMX
+  BFD_RELOC_MSP430X_PCR20_EXT_ODST
+ENUMX
+  BFD_RELOC_MSP430X_ABS20_EXT_SRC
+ENUMX
+  BFD_RELOC_MSP430X_ABS20_EXT_DST
+ENUMX
+  BFD_RELOC_MSP430X_ABS20_EXT_ODST
+ENUMX
+  BFD_RELOC_MSP430X_ABS20_ADR_SRC
+ENUMX
+  BFD_RELOC_MSP430X_ABS20_ADR_DST
+ENUMX
+  BFD_RELOC_MSP430X_PCR16
+ENUMX
+  BFD_RELOC_MSP430X_PCR20_CALL
+ENUMX
+  BFD_RELOC_MSP430X_ABS16
+ENUMX
+  BFD_RELOC_MSP430_ABS_HI16
+ENUMX
+  BFD_RELOC_MSP430_PREL31
+ENUMX
+  BFD_RELOC_MSP430_SYM_DIFF
 ENUMDOC
   msp430 specific relocation codes
 
index c9fbbc2fe31ca014025ce6464b4592bad5aa6e02..c6794ee507cd1ad1f5686261b5438eca3c5517b2 100644 (file)
@@ -1,7 +1,5 @@
 /* Generic target-file-type support for the BFD library.
-   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
-   Free Software Foundation, Inc.
+   Copyright 1990-2013 Free Software Foundation, Inc.
    Written by Cygnus Support.
 
    This file is part of BFD, the Binary File Descriptor library.
@@ -668,6 +666,7 @@ extern const bfd_target bfd_elf32_mn10200_vec;
 extern const bfd_target bfd_elf32_mn10300_vec;
 extern const bfd_target bfd_elf32_mt_vec;
 extern const bfd_target bfd_elf32_msp430_vec;
+extern const bfd_target bfd_elf32_msp430_ti_vec;
 extern const bfd_target bfd_elf32_nbigmips_vec;
 extern const bfd_target bfd_elf32_nlittlemips_vec;
 extern const bfd_target bfd_elf32_ntradbigmips_vec;
@@ -1047,6 +1046,7 @@ static const bfd_target * const _bfd_target_vector[] =
        &bfd_elf32_mn10300_vec,
        &bfd_elf32_mt_vec,
        &bfd_elf32_msp430_vec,
+       &bfd_elf32_msp430_ti_vec,
 #ifdef BFD64
        &bfd_elf32_nbigmips_vec,
        &bfd_elf32_nlittlemips_vec,
index a71bf94cf3e3439a84f4b604680fca67198edce7..6b75fac1bbef5cb047e25c4be3e57f8ce106b02c 100644 (file)
 #include "elf/moxie.h"
 #include "elf/mt.h"
 #include "elf/msp430.h"
+#include "elf/nios2.h"
 #include "elf/or32.h"
 #include "elf/pj.h"
 #include "elf/ppc.h"
 #include "elf/xstormy16.h"
 #include "elf/xtensa.h"
 
-#include "elf/nios2.h"
-
 #include "getopt.h"
 #include "libiberty.h"
 #include "safe-ctype.h"
@@ -903,6 +902,17 @@ get_reloc_symindex (bfd_vma reloc_info)
   return is_32bit_elf ? ELF32_R_SYM (reloc_info) : ELF64_R_SYM (reloc_info);
 }
 
+static inline bfd_boolean
+uses_msp430x_relocs (void)
+{
+  return
+    elf_header.e_machine == EM_MSP430 /* Paranoia.  */
+    /* GCC uses osabi == ELFOSBI_STANDALONE.  */
+    && (((elf_header.e_flags & EF_MSP430_MACH) == E_MSP430_MACH_MSP430X)
+       /* TI compiler uses ELFOSABI_NONE.  */
+       || (elf_header.e_ident[EI_OSABI] == ELFOSABI_NONE));
+}
+
 /* Display the contents of the relocation data found at the specified
    offset.  */
 
@@ -1125,6 +1135,11 @@ dump_relocations (FILE * file,
          break;
 
        case EM_MSP430:
+         if (uses_msp430x_relocs ())
+           {
+             rtype = elf_msp430x_reloc_type (type);
+             break;
+           }
        case EM_MSP430_OLD:
          rtype = elf_msp430_reloc_type (type);
          break;
@@ -2781,6 +2796,32 @@ get_machine_flags (unsigned e_flags, unsigned e_machine)
          if ((e_flags & EF_C6000_REL))
            strcat (buf, ", relocatable module");
          break;
+
+       case EM_MSP430:
+         strcat (buf, _(": architecture variant: "));
+         switch (e_flags & EF_MSP430_MACH)
+           {
+           case E_MSP430_MACH_MSP430x11: strcat (buf, "MSP430x11"); break;
+           case E_MSP430_MACH_MSP430x11x1 : strcat (buf, "MSP430x11x1 "); break;
+           case E_MSP430_MACH_MSP430x12: strcat (buf, "MSP430x12"); break;
+           case E_MSP430_MACH_MSP430x13: strcat (buf, "MSP430x13"); break;
+           case E_MSP430_MACH_MSP430x14: strcat (buf, "MSP430x14"); break;
+           case E_MSP430_MACH_MSP430x15: strcat (buf, "MSP430x15"); break;
+           case E_MSP430_MACH_MSP430x16: strcat (buf, "MSP430x16"); break;
+           case E_MSP430_MACH_MSP430x31: strcat (buf, "MSP430x31"); break;
+           case E_MSP430_MACH_MSP430x32: strcat (buf, "MSP430x32"); break;
+           case E_MSP430_MACH_MSP430x33: strcat (buf, "MSP430x33"); break;
+           case E_MSP430_MACH_MSP430x41: strcat (buf, "MSP430x41"); break;
+           case E_MSP430_MACH_MSP430x42: strcat (buf, "MSP430x42"); break;
+           case E_MSP430_MACH_MSP430x43: strcat (buf, "MSP430x43"); break;
+           case E_MSP430_MACH_MSP430x44: strcat (buf, "MSP430x44"); break;
+           case E_MSP430_MACH_MSP430X  : strcat (buf, "MSP430X"); break;
+           default:
+             strcat (buf, _(": unknown")); break;
+           }
+
+         if (e_flags & ~ EF_MSP430_MACH)
+           strcat (buf, _(": unknown extra flag bits also present"));
        }
     }
 
@@ -3205,6 +3246,18 @@ get_tic6x_section_type_name (unsigned int sh_type)
   return NULL;
 }
 
+static const char *
+get_msp430x_section_type_name (unsigned int sh_type)
+{
+  switch (sh_type)
+    {
+    case SHT_MSP430_SEC_FLAGS:   return "MSP430_SEC_FLAGS";
+    case SHT_MSP430_SYM_ALIASES: return "MSP430_SYM_ALIASES";
+    case SHT_MSP430_ATTRIBUTES:  return "MSP430_ATTRIBUTES";
+    default: return NULL;
+    }
+}
+
 static const char *
 get_section_type_name (unsigned int sh_type)
 {
@@ -3270,6 +3323,9 @@ get_section_type_name (unsigned int sh_type)
            case EM_TI_C6000:
              result = get_tic6x_section_type_name (sh_type);
              break;
+           case EM_MSP430:
+             result = get_msp430x_section_type_name (sh_type);
+             break;
            default:
              result = NULL;
              break;
@@ -8994,8 +9050,13 @@ get_symbol_type (unsigned int type)
     default:
       if (type >= STT_LOPROC && type <= STT_HIPROC)
        {
-         if (elf_header.e_machine == EM_ARM && type == STT_ARM_TFUNC)
-           return "THUMB_FUNC";
+         if (elf_header.e_machine == EM_ARM)
+           {
+             if (type == STT_ARM_TFUNC)
+               return "THUMB_FUNC";
+             if (type == STT_ARM_16BIT)
+               return "THUMB_LABEL";
+           }
 
          if (elf_header.e_machine == EM_SPARCV9 && type == STT_REGISTER)
            return "REGISTER";
@@ -9961,6 +10022,60 @@ target_specific_reloc_handling (Elf_Internal_Rela * reloc,
 
   switch (elf_header.e_machine)
     {
+    case EM_MSP430:
+    case EM_MSP430_OLD:
+      {
+       static Elf_Internal_Sym * saved_sym = NULL;
+
+       switch (reloc_type)
+         {
+         case 10: /* R_MSP430_SYM_DIFF */
+           if (uses_msp430x_relocs ())
+             break;
+         case 21: /* R_MSP430X_SYM_DIFF */
+           saved_sym = symtab + get_reloc_symindex (reloc->r_info);
+           return TRUE;
+
+         case 1: /* R_MSP430_32 or R_MSP430_ABS32 */
+         case 3: /* R_MSP430_16 or R_MSP430_ABS8 */
+           goto handle_sym_diff;
+           
+         case 5: /* R_MSP430_16_BYTE */
+         case 9: /* R_MSP430_8 */
+           if (uses_msp430x_relocs ())
+             break;
+           goto handle_sym_diff;
+
+         case 2: /* R_MSP430_ABS16 */
+         case 15: /* R_MSP430X_ABS16 */
+           if (! uses_msp430x_relocs ())
+             break;
+           goto handle_sym_diff;
+           
+         handle_sym_diff:
+           if (saved_sym != NULL)
+             {
+               bfd_vma value;
+
+               value = reloc->r_addend
+                 + (symtab[get_reloc_symindex (reloc->r_info)].st_value
+                    - saved_sym->st_value);
+
+               byte_put (start + reloc->r_offset, value, reloc_type == 1 ? 4 : 2);
+
+               saved_sym = NULL;
+               return TRUE;
+             }
+           break;
+
+         default:
+           if (saved_sym != NULL)
+             error (_("Unhandled MSP430 reloc type found after SYM_DIFF reloc"));
+           break;
+         }
+       break;
+      }
+
     case EM_MN10300:
     case EM_CYGNUS_MN10300:
       {
@@ -10100,7 +10215,7 @@ is_32bit_abs_reloc (unsigned int reloc_type)
       return reloc_type == 1; /* R_MOXIE_32.  */
     case EM_MSP430_OLD:
     case EM_MSP430:
-      return reloc_type == 1; /* R_MSP43_32.  */
+      return reloc_type == 1; /* R_MSP430_32 or R_MSP320_ABS32.  */
     case EM_MT:
       return reloc_type == 2; /* R_MT_32.  */
     case EM_ALTERA_NIOS2:
@@ -10352,6 +10467,8 @@ is_16bit_abs_reloc (unsigned int reloc_type)
     case EM_M32C:
       return reloc_type == 1; /* R_M32C_16 */
     case EM_MSP430:
+      if (uses_msp430x_relocs ())
+       return reloc_type == 2; /* R_MSP430_ABS16.  */
     case EM_MSP430_OLD:
       return reloc_type == 5; /* R_MSP430_16_BYTE.  */
     case EM_ALTERA_NIOS2:
@@ -11905,6 +12022,79 @@ display_raw_attribute (unsigned char * p, unsigned char * end)
   putchar ('\n');
 }
 
+static unsigned char *
+display_msp430x_attribute (unsigned char * p,
+                          const unsigned char * const end)
+{
+  unsigned int len;
+  int val;
+  int tag;
+
+  tag = read_uleb128 (p, & len, end);
+  p += len;
+  
+  switch (tag)
+    {
+    case OFBA_MSPABI_Tag_ISA:
+      val = read_uleb128 (p, &len, end);
+      p += len;
+      printf ("  Tag_ISA: ");
+      switch (val)
+       {
+       case 0: printf (_("None\n")); break;
+       case 1: printf (_("MSP430\n")); break;
+       case 2: printf (_("MSP430X\n")); break;
+       default: printf ("??? (%d)\n", val); break;
+       }
+      break;
+
+    case OFBA_MSPABI_Tag_Code_Model:
+      val = read_uleb128 (p, &len, end);
+      p += len;
+      printf ("  Tag_Code_Model: ");
+      switch (val)
+       {
+       case 0: printf (_("None\n")); break;
+       case 1: printf (_("Small\n")); break;
+       case 2: printf (_("Large\n")); break;
+       default: printf ("??? (%d)\n", val); break;
+       }
+      break;
+
+    case OFBA_MSPABI_Tag_Data_Model:
+      val = read_uleb128 (p, &len, end);
+      p += len;
+      printf ("  Tag_Data_Model: ");
+      switch (val)
+       {
+       case 0: printf (_("None\n")); break;
+       case 1: printf (_("Small\n")); break;
+       case 2: printf (_("Large\n")); break;
+       case 3: printf (_("Restricted Large\n")); break;
+       default: printf ("??? (%d)\n", val); break;
+       }
+      break;
+
+    default:
+      printf (_("  <unknown tag %d>: "), tag);
+
+      if (tag & 1)
+       {
+         printf ("\"%s\"\n", p);
+         p += strlen ((char *) p) + 1;
+       }
+      else
+       {
+         val = read_uleb128 (p, &len, end);
+         p += len;
+         printf ("%d (0x%x)\n", val, val);
+       }
+      break;
+   }
+
+  return p;
+}
+
 static int
 process_attributes (FILE * file,
                    const char * public_name,
@@ -12076,6 +12266,13 @@ process_tic6x_specific (FILE * file)
                             display_tic6x_attribute, NULL);
 }
 
+static int
+process_msp430x_specific (FILE * file)
+{
+  return process_attributes (file, "mspabi", SHT_MSP430_ATTRIBUTES,
+                            display_msp430x_attribute, NULL);
+}
+
 /* DATA points to the contents of a MIPS GOT that starts at VMA PLTGOT.
    Print the Address, Access and Initial fields of an entry at VMA ADDR
    and return the VMA of the next entry.  */
@@ -13554,6 +13751,8 @@ process_arch_specific (FILE * file)
     case EM_TI_C6000:
       return process_tic6x_specific (file);
       break;
+    case EM_MSP430:
+      return process_msp430x_specific (file);
     default:
       break;
     }
index cd12d3824d14bbab26d62029a6474aa5d0c8d03b..37cb9d675a259731648e84eca4f166286eaa86c8 100644 (file)
@@ -1,3 +1,7 @@
+2013-05-02  Nick Clifton  <nickc@redhat.com>
+
+       * readelf.exp: Expect -wi test to fail for the MSP430.
+
 2013-05-01  Maciej W. Rozycki  <macro@codesourcery.com>
 
        * lib/binutils-common.exp (is_elf_format): Also exclude
index c1d7286de55081d591442e6ecca3b86fd1b4ef38..db56a8685534ea3e185135dcff473b4cf72c5f29 100644 (file)
@@ -1,5 +1,4 @@
-#   Copyright 1999, 2000, 2001, 2003, 2004, 2007, 2009, 2012
-#   Free Software Foundation, Inc.
+#   Copyright 1999-2013 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
@@ -196,6 +195,9 @@ proc readelf_wi_test {} {
        ".*\(DW_OP_addr: 0\).*"
     }
 
+    # The MSP430 in LARGE mode does not generate a DW_OP_addr.
+    setup_xfail msp430*-*-*
+
     foreach looked_for $sought {
        set lines [grep $output $looked_for]
        if ![llength $lines] then {
index 1eba1b29c4f5af3bcd4307bd6814665c2364da71..e4f896ad2d0f2c3588c9f2d6bb5a3325337b2671 100644 (file)
@@ -1,3 +1,15 @@
+2013-05-02  Nick Clifton  <nickc@redhat.com>
+
+       * config/tc-msp430.c: Add support for the MSP430X architecture.
+       Add code to insert a NOP instruction after any instruction that
+       might change the interrupt state.
+       Add support for the LARGE memory model.
+       Add code to initialise the .MSP430.attributes section.
+       * config/tc-msp430.h: Add support for the MSP430X architecture.
+       * doc/c-msp430.texi: Document the new -mL and -mN command line
+       options.
+       * NEWS: Mention support for the MSP430X architecture.
+
 2013-05-01  Maciej W. Rozycki  <macro@codesourcery.com>
 
        * configure.tgt: Replace alpha*-*-linuxecoff* pattern with
index 202db36aa239fcb7bf51418b523606c573b15c88..29b0fdf978aa4cbad658a3cdab1ce8171786a62b 100644 (file)
--- a/gas/NEWS
+++ b/gas/NEWS
@@ -1,5 +1,7 @@
 -*- text -*-
 
+* Add support for the Texas Instruments MSP430X processor.
+
 * Add -gdwarf-sections command line option to enable per-code-section
   generation of DWARF .debug_line sections.
 
index 8ec7546406db32172d04ba2db47a8499721e7527..0fed29a1bbebe8a417b52825ec722f5c5afe6cf7 100644 (file)
@@ -1,7 +1,6 @@
 /* tc-msp430.c -- Assembler code for the Texas Instruments MSP430
 
-  Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010, 2012
-  Free Software Foundation, Inc.
+  Copyright (C) 2002-2013 Free Software Foundation, Inc.
   Contributed by Dmitry Diky <diwil@mail.ru>
 
   This file is part of GAS, the GNU Assembler.
@@ -28,6 +27,7 @@
 #include "opcode/msp430.h"
 #include "safe-ctype.h"
 #include "dwarf2dbg.h"
+#include "elf/msp430.h"
 
 /* We will disable polymorphs by default because it is dangerous.
    The potential problem here is the following: assume we got the
@@ -39,7 +39,7 @@
       .l1:
        nop
        ret
-   
+
    In case of assembly time relaxation we'll get:
        0: jmp .l1 <.text +0x08> (reloc deleted)
        2: nop
 
    If polymorphs are enabled, and relax isn't, treat all jumps as long jumps,
    do not delete any relocs and leave them for linker.
-   
+
    If relax is enabled, relax at assembly time and kill relocs as necessary.  */
 
 int msp430_enable_relax;
 int msp430_enable_polys;
 
+/*  Set linkrelax here to avoid fixups in most sections.  */
+int linkrelax = 1;
+
 /* GCC uses the some condition codes which we'll
    implement as new polymorph instructions.
-  
+
    COND        EXPL       SHORT JUMP   LONG JUMP
    ===============================================
    eq  ==         jeq          jne +4; br lab
@@ -80,7 +83,7 @@ int msp430_enable_polys;
    ltn honours no-overflow flag
    ltn <          jn           jn +2;  jmp +4; br lab
 
-   lt  <          jl           jge +4; br lab 
+   lt  <          jl           jge +4; br lab
    ltu <          jlo          lhs +4; br lab
    le  <= see below
    leu <= see below
@@ -93,14 +96,14 @@ int msp430_enable_polys;
 
    Therefore, new opcodes are (BranchEQ -> beq; and so on...)
    beq,bne,blt,bltn,bltu,bge,bgeu
-   'u' means unsigned compares 
-  
+   'u' means unsigned compares
+
    Also, we add 'jump' instruction:
    jump        UNCOND  -> jmp          br lab
 
    They will have fmt == 4, and insn_opnumb == number of instruction.  */
 
-struct rcodes_s 
+struct rcodes_s
 {
   char * name;
   int    index;        /* Corresponding insn_opnumb.  */
@@ -114,7 +117,7 @@ struct rcodes_s
 #define MSP430_RLC(n,i,sop,o1) \
   {#n, i, sop, 2, (o1 + 2), 0x4010, 0}
 
-static struct rcodes_s msp430_rcodes[] = 
+static struct rcodes_s msp430_rcodes[] =
 {
   MSP430_RLC (beq,  0, 0x2400, 0x2000),
   MSP430_RLC (bne,  1, 0x2000, 0x2400),
@@ -126,11 +129,27 @@ static struct rcodes_s msp430_rcodes[] =
   {"jump",          7, 0x3c00, 1, 0x4010, 0, 0},
   {0,0,0,0,0,0,0}
 };
-#undef MSP430_RLC
 
+#undef  MSP430_RLC
+#define MSP430_RLC(n,i,sop,o1) \
+  {#n, i, sop, 2, (o1 + 2), 0x0030, 0}
+
+static struct rcodes_s msp430x_rcodes[] =
+{
+  MSP430_RLC (beq,  0, 0x2400,    0x2000),
+  MSP430_RLC (bne,  1, 0x2000,    0x2400),
+  MSP430_RLC (blt,  2, 0x3800,    0x3400),
+  MSP430_RLC (bltu, 3, 0x2800,    0x2c00),
+  MSP430_RLC (bge,  4, 0x3400,    0x3800),
+  MSP430_RLC (bgeu, 5, 0x2c00,    0x2800),
+  {"bltn",          6, 0x3000, 3, 0x0030 + 1, 0x3c00 + 2, 0x3000},
+  {"jump",          7, 0x3c00, 1, 0x0030,     0,          0},
+  {0,0,0,0,0,0,0}
+};
+#undef MSP430_RLC
 
 /* More difficult than above and they have format 5.
-   
+
    COND        EXPL    SHORT                   LONG
    =================================================================
    gt  >       jeq +2; jge label       jeq +6; jl  +4; br label
@@ -139,9 +158,9 @@ static struct rcodes_s msp430_rcodes[] =
    le  <=      jeq label; jl  label    jeq +2; jge +4; br label
    =================================================================  */
 
-struct hcodes_s 
+struct hcodes_s
 {
-  char * name; 
+  char * name;
   int    index;                /* Corresponding insn_opnumb.  */
   int    tlab;         /* Number of labels in short mode.  */
   int    op0;          /* Opcode for first word of short jump.  */
@@ -151,7 +170,7 @@ struct hcodes_s
   int    lop2;
 };
 
-static struct hcodes_s msp430_hcodes[] = 
+static struct hcodes_s msp430_hcodes[] =
 {
   {"bgt",  0, 1, 0x2401, 0x3400, 0x2403, 0x3802, 0x4010 },
   {"bgtu", 1, 1, 0x2401, 0x2c00, 0x2403, 0x2802, 0x4010 },
@@ -160,6 +179,15 @@ static struct hcodes_s msp430_hcodes[] =
   {0,0,0,0,0,0,0,0}
 };
 
+static struct hcodes_s msp430x_hcodes[] =
+{
+  {"bgt",  0, 1, 0x2401, 0x3400, 0x2403, 0x3802, 0x0030 },
+  {"bgtu", 1, 1, 0x2401, 0x2c00, 0x2403, 0x2802, 0x0030 },
+  {"bleu", 2, 2, 0x2400, 0x2800, 0x2401, 0x2c02, 0x0030 },
+  {"ble",  3, 2, 0x2400, 0x3800, 0x2401, 0x3402, 0x0030 },
+  {0,0,0,0,0,0,0,0}
+};
+
 const char comment_chars[] = ";";
 const char line_comment_chars[] = "#";
 const char line_separator_chars[] = "{";
@@ -243,7 +271,12 @@ struct mcu_type_s
 #define MSP430_ISA_14   14
 #define MSP430_ISA_15   15
 #define MSP430_ISA_16   16
+#define MSP430_ISA_20   20
 #define MSP430_ISA_21   21
+#define MSP430_ISA_22   22
+#define MSP430_ISA_23   23
+#define MSP430_ISA_24   24
+#define MSP430_ISA_26   26
 #define MSP430_ISA_31   31
 #define MSP430_ISA_32   32
 #define MSP430_ISA_33   33
@@ -251,14 +284,43 @@ struct mcu_type_s
 #define MSP430_ISA_42   42
 #define MSP430_ISA_43   43
 #define MSP430_ISA_44   44
-
-#define CHECK_RELOC_MSP430             ((imm_op || byte_op)?BFD_RELOC_MSP430_16_BYTE:BFD_RELOC_MSP430_16)
-#define CHECK_RELOC_MSP430_PCREL       ((imm_op || byte_op)?BFD_RELOC_MSP430_16_PCREL_BYTE:BFD_RELOC_MSP430_16_PCREL)
+#define MSP430X_ISA     45
+#define MSP430_ISA_46   46
+#define MSP430_ISA_47   47
+#define MSP430_ISA_54   54
+
+/* Generate a 16-bit relocation.
+   For the 430X we generate a relocation without linkwer range checking
+   if the value is being used in an extended (ie 20-bit) instruction.
+   For the 430 we generate a relocation without assembler range checking
+   if we are handling an immediate value or a byte-width instruction.  */
+#undef  CHECK_RELOC_MSP430
+#define CHECK_RELOC_MSP430                                  \
+  (msp430_mcu->isa == MSP430X_ISA                           \
+   ? (extended_op ? BFD_RELOC_16 : BFD_RELOC_MSP430X_ABS16)  \
+   : ((imm_op || byte_op)                                   \
+      ? BFD_RELOC_MSP430_16_BYTE : BFD_RELOC_MSP430_16))
+
+/* Generate a 16-bit pc-relative relocation.
+   For the 430X we generate a relocation without linkwer range checking.
+   For the 430 we generate a relocation without assembler range checking
+   if we are handling an immediate value or a byte-width instruction.  */
+#undef  CHECK_RELOC_MSP430_PCREL
+#define CHECK_RELOC_MSP430_PCREL                            \
+  (msp430_mcu->isa == MSP430X_ISA                           \
+   ? BFD_RELOC_MSP430X_PCR16                                \
+   : (imm_op || byte_op)                                    \
+   ? BFD_RELOC_MSP430_16_PCREL_BYTE : BFD_RELOC_MSP430_16_PCREL)
 
 static struct mcu_type_s mcu_types[] =
 {
   {"msp1",        MSP430_ISA_11, bfd_mach_msp11},
   {"msp2",        MSP430_ISA_14, bfd_mach_msp14},
+  {"msp3",        MSP430_ISA_20, bfd_mach_msp20},
+  {"msp4",        MSP430_ISA_24, bfd_mach_msp24},
+  {"msp5",        MSP430_ISA_31, bfd_mach_msp31},
+  {"msp6",        MSP430_ISA_42, bfd_mach_msp42},
+
   {"msp430x110",  MSP430_ISA_11, bfd_mach_msp11},
   {"msp430x112",  MSP430_ISA_11, bfd_mach_msp11},
   {"msp430x1101", MSP430_ISA_110, bfd_mach_msp110},
@@ -279,6 +341,9 @@ static struct mcu_type_s mcu_types[] =
   {"msp430x147",  MSP430_ISA_14, bfd_mach_msp14},
   {"msp430x148",  MSP430_ISA_14, bfd_mach_msp14},
   {"msp430x149",  MSP430_ISA_14, bfd_mach_msp14},
+  {"msp430x1471", MSP430_ISA_14, bfd_mach_msp14},
+  {"msp430x1481", MSP430_ISA_14, bfd_mach_msp14},
+  {"msp430x1491", MSP430_ISA_14, bfd_mach_msp14},
 
   {"msp430x155",  MSP430_ISA_15, bfd_mach_msp15},
   {"msp430x156",  MSP430_ISA_15, bfd_mach_msp15},
@@ -290,11 +355,50 @@ static struct mcu_type_s mcu_types[] =
   {"msp430x1611", MSP430_ISA_16, bfd_mach_msp16},
   {"msp430x1612", MSP430_ISA_16, bfd_mach_msp16},
 
+  {"msp430x2001", MSP430_ISA_20, bfd_mach_msp20},
+  {"msp430x2011", MSP430_ISA_20, bfd_mach_msp20},
+  {"msp430x2002", MSP430_ISA_20, bfd_mach_msp20},
+  {"msp430x2012", MSP430_ISA_20, bfd_mach_msp20},
+  {"msp430x2003", MSP430_ISA_20, bfd_mach_msp20},
+  {"msp430x2013", MSP430_ISA_20, bfd_mach_msp20 },
+
   {"msp430x2101", MSP430_ISA_21, bfd_mach_msp21},
   {"msp430x2111", MSP430_ISA_21, bfd_mach_msp21},
+  {"msp430x2112", MSP430_ISA_21, bfd_mach_msp21},
   {"msp430x2121", MSP430_ISA_21, bfd_mach_msp21},
   {"msp430x2131", MSP430_ISA_21, bfd_mach_msp21},
-  
+  {"msp430x2132", MSP430_ISA_21, bfd_mach_msp21},
+
+  {"msp430x2232", MSP430_ISA_22, bfd_mach_msp22},
+  {"msp430x2234", MSP430_ISA_22, bfd_mach_msp22},
+  {"msp430x2252", MSP430_ISA_22, bfd_mach_msp22},
+  {"msp430x2254", MSP430_ISA_22, bfd_mach_msp22},
+  {"msp430x2272", MSP430_ISA_22, bfd_mach_msp22},
+  {"msp430x2274", MSP430_ISA_22, bfd_mach_msp22},
+
+  {"msp430x233",  MSP430_ISA_23, bfd_mach_msp23},
+  {"msp430x235",  MSP430_ISA_23, bfd_mach_msp23},
+  {"msp430x2330", MSP430_ISA_23, bfd_mach_msp23},
+  {"msp430x2350", MSP430_ISA_23, bfd_mach_msp23},
+  {"msp430x2370", MSP430_ISA_23, bfd_mach_msp23},
+
+  {"msp430x247",  MSP430_ISA_24, bfd_mach_msp24},
+  {"msp430x2471", MSP430_ISA_24, bfd_mach_msp24},
+  {"msp430x248",  MSP430_ISA_24, bfd_mach_msp24},
+  {"msp430x2481", MSP430_ISA_24, bfd_mach_msp24},
+  {"msp430x249",  MSP430_ISA_24, bfd_mach_msp24},
+  {"msp430x2491", MSP430_ISA_24, bfd_mach_msp24},
+  {"msp430x2410", MSP430_ISA_24, bfd_mach_msp24},
+  {"msp430x2416", MSP430_ISA_24, bfd_mach_msp24},
+  {"msp430x2417", MSP430_ISA_24, bfd_mach_msp24},
+  {"msp430x2418", MSP430_ISA_24, bfd_mach_msp24},
+  {"msp430x2419", MSP430_ISA_24, bfd_mach_msp24},
+
+  {"msp430x2616", MSP430_ISA_26, bfd_mach_msp26},
+  {"msp430x2617", MSP430_ISA_26, bfd_mach_msp26},
+  {"msp430x2618", MSP430_ISA_26, bfd_mach_msp26},
+  {"msp430x2619", MSP430_ISA_26, bfd_mach_msp26},
+
   {"msp430x311",  MSP430_ISA_31, bfd_mach_msp31},
   {"msp430x312",  MSP430_ISA_31, bfd_mach_msp31},
   {"msp430x313",  MSP430_ISA_31, bfd_mach_msp31},
@@ -310,9 +414,23 @@ static struct mcu_type_s mcu_types[] =
   {"msp430x415",  MSP430_ISA_41, bfd_mach_msp41},
   {"msp430x417",  MSP430_ISA_41, bfd_mach_msp41},
 
+  {"msp430x423",  MSP430_ISA_42, bfd_mach_msp42},
+  {"msp430x425",  MSP430_ISA_42, bfd_mach_msp42},
+  {"msp430x427",  MSP430_ISA_42, bfd_mach_msp42},
+  {"msp430x4250", MSP430_ISA_42, bfd_mach_msp42},
+  {"msp430x4260", MSP430_ISA_42, bfd_mach_msp42},
+  {"msp430x4270", MSP430_ISA_42, bfd_mach_msp42},
+  {"msp430xG4250",MSP430_ISA_42, bfd_mach_msp42},
+  {"msp430xG4260",MSP430_ISA_42, bfd_mach_msp42},
+  {"msp430xG4270",MSP430_ISA_42, bfd_mach_msp42},
+
   {"msp430xE423", MSP430_ISA_42, bfd_mach_msp42},
+  {"msp430xE4232",MSP430_ISA_42, bfd_mach_msp42},
+  {"msp430xE4242",MSP430_ISA_42, bfd_mach_msp42},
+  {"msp430xE4252",MSP430_ISA_42, bfd_mach_msp42},
   {"msp430xE425", MSP430_ISA_42, bfd_mach_msp42},
   {"msp430xE427", MSP430_ISA_42, bfd_mach_msp42},
+  {"msp430xE4272",MSP430_ISA_42, bfd_mach_msp42},
 
   {"msp430xW423", MSP430_ISA_42, bfd_mach_msp42},
   {"msp430xW425", MSP430_ISA_42, bfd_mach_msp42},
@@ -323,12 +441,43 @@ static struct mcu_type_s mcu_types[] =
   {"msp430xG439", MSP430_ISA_43, bfd_mach_msp43},
 
   {"msp430x435",  MSP430_ISA_43, bfd_mach_msp43},
+  {"msp430x4351", MSP430_ISA_43, bfd_mach_msp43},
   {"msp430x436",  MSP430_ISA_43, bfd_mach_msp43},
+  {"msp430x4361", MSP430_ISA_43, bfd_mach_msp43},
   {"msp430x437",  MSP430_ISA_43, bfd_mach_msp43},
+  {"msp430x4371", MSP430_ISA_43, bfd_mach_msp43},
+
   {"msp430x447",  MSP430_ISA_44, bfd_mach_msp44},
   {"msp430x448",  MSP430_ISA_44, bfd_mach_msp44},
   {"msp430x449",  MSP430_ISA_44, bfd_mach_msp44},
 
+  {"msp430xG4616",MSP430_ISA_46, bfd_mach_msp46},
+  {"msp430xG4617",MSP430_ISA_46, bfd_mach_msp46},
+  {"msp430xG4618",MSP430_ISA_46, bfd_mach_msp46},
+  {"msp430xG4619",MSP430_ISA_46, bfd_mach_msp46},
+
+  {"msp430x4783", MSP430_ISA_47, bfd_mach_msp47},
+  {"msp430x4784", MSP430_ISA_47, bfd_mach_msp47},
+  {"msp430x4793", MSP430_ISA_47, bfd_mach_msp47},
+  {"msp430x4794", MSP430_ISA_47, bfd_mach_msp47},
+  {"msp430x47166",MSP430_ISA_47, bfd_mach_msp47},
+  {"msp430x47176",MSP430_ISA_47, bfd_mach_msp47},
+  {"msp430x47186",MSP430_ISA_47, bfd_mach_msp47},
+  {"msp430x47196",MSP430_ISA_47, bfd_mach_msp47},
+  {"msp430x47167",MSP430_ISA_47, bfd_mach_msp47},
+  {"msp430x47177",MSP430_ISA_47, bfd_mach_msp47},
+  {"msp430x47187",MSP430_ISA_47, bfd_mach_msp47},
+  {"msp430x47197",MSP430_ISA_47, bfd_mach_msp47},
+
+  {"msp430x5418", MSP430_ISA_54, bfd_mach_msp54},
+  {"msp430x5419", MSP430_ISA_54, bfd_mach_msp54},
+  {"msp430x5435", MSP430_ISA_54, bfd_mach_msp54},
+  {"msp430x5436", MSP430_ISA_54, bfd_mach_msp54},
+  {"msp430x5437", MSP430_ISA_54, bfd_mach_msp54},
+  {"msp430x5438", MSP430_ISA_54, bfd_mach_msp54},
+
+  {"msp430X",     MSP430X_ISA,   bfd_mach_msp430x},
+
   {NULL, 0, 0}
 };
 
@@ -699,6 +848,10 @@ extract_word (char * from, char * to, int limit)
 #define OPTION_MMCU 'm'
 #define OPTION_RELAX 'Q'
 #define OPTION_POLYMORPHS 'P'
+#define OPTION_LARGE 'l'
+static bfd_boolean large_model = FALSE;
+#define OPTION_NO_INTR_NOPS 'N'
+static bfd_boolean gen_interrupt_nops = TRUE;
 
 static void
 msp430_set_arch (int dummy ATTRIBUTE_UNUSED)
@@ -719,7 +872,11 @@ show_mcu_list (FILE * stream)
   fprintf (stream, _("Known MCU names:\n"));
 
   for (i = 0; mcu_types[i].name; i++)
-    fprintf (stream, _("\t %s\n"), mcu_types[i].name);
+    {
+      fprintf (stream, "%13.13s", mcu_types[i].name);
+      if ((i % 6) == 5)
+       fprintf (stream, "\n");
+    }
 
   fprintf (stream, "\n");
 }
@@ -744,21 +901,29 @@ md_parse_option (int c, char * arg)
 
       if (msp430_mcu == &default_mcu || msp430_mcu->mach == mcu_types[i].mach)
        msp430_mcu = &mcu_types[i];
+      else if (msp430_mcu->mach == bfd_mach_msp430x)
+       /* Allow switching to a lesser architecture.  */
+       msp430_mcu = mcu_types + i;
       else
        as_fatal (_("redefinition of mcu type %s' to %s'"),
                  msp430_mcu->name, mcu_types[i].name);
       return 1;
-      break;
-      
+
     case OPTION_RELAX:
-      msp430_enable_relax = 1; 
+      msp430_enable_relax = 1;
       return 1;
-      break;
-      
+
     case OPTION_POLYMORPHS:
       msp430_enable_polys = 1;
       return 1;
-      break;
+
+    case OPTION_LARGE:
+      large_model = TRUE;
+      return 1;
+
+    case OPTION_NO_INTR_NOPS:
+      gen_interrupt_nops = FALSE;
+      return 1;
     }
 
   return 0;
@@ -779,6 +944,8 @@ struct option md_longopts[] =
   {"mmcu", required_argument, NULL, OPTION_MMCU},
   {"mP", no_argument, NULL, OPTION_POLYMORPHS},
   {"mQ", no_argument, NULL, OPTION_RELAX},
+  {"ml", no_argument, NULL, OPTION_LARGE},
+  {"mN", no_argument, NULL, OPTION_NO_INTR_NOPS},
   {NULL, no_argument, NULL, 0}
 };
 
@@ -789,30 +956,14 @@ md_show_usage (FILE * stream)
 {
   fprintf (stream,
           _("MSP430 options:\n"
-            "  -mmcu=[msp430-name] select microcontroller type\n"
-            "                  msp430x110  msp430x112\n"
-            "                  msp430x1101 msp430x1111\n"
-            "                  msp430x1121 msp430x1122 msp430x1132\n"
-            "                  msp430x122  msp430x123\n"
-            "                  msp430x1222 msp430x1232\n"
-            "                  msp430x133  msp430x135\n"
-            "                  msp430x1331 msp430x1351\n"
-            "                  msp430x147  msp430x148  msp430x149\n"
-            "                  msp430x155  msp430x156  msp430x157\n"
-            "                  msp430x167  msp430x168  msp430x169\n"
-            "                  msp430x1610 msp430x1611 msp430x1612\n"
-            "                  msp430x311  msp430x312  msp430x313  msp430x314  msp430x315\n"
-            "                  msp430x323  msp430x325\n"
-            "                  msp430x336  msp430x337\n"
-            "                  msp430x412  msp430x413  msp430x415  msp430x417\n"
-            "                  msp430xE423 msp430xE425 msp430E427\n"
-            "                  msp430xW423 msp430xW425 msp430W427\n"
-            "                  msp430xG437 msp430xG438 msp430G439\n"
-            "                  msp430x435  msp430x436  msp430x437\n"
-            "                  msp430x447  msp430x448  msp430x449\n"));
+            "  -mmcu=<msp430-name> select microcontroller type\n"));
   fprintf (stream,
           _("  -mQ - enable relaxation at assembly time. DANGEROUS!\n"
             "  -mP - enable polymorph instructions\n"));
+  fprintf (stream,
+          _("  -ml - enable large code model\n"));
+  fprintf (stream,
+          _("  -mN - disable generation of NOP after changing interrupts\n"));
 
   show_mcu_list (stream);
 }
@@ -820,7 +971,7 @@ md_show_usage (FILE * stream)
 symbolS *
 md_undefined_symbol (char * name ATTRIBUTE_UNUSED)
 {
-  return 0;
+  return NULL;
 }
 
 static char *
@@ -858,31 +1009,49 @@ md_begin (void)
   bfd_set_arch_mach (stdoutput, TARGET_ARCH, msp430_mcu->mach);
 }
 
-static int
+/* Returns the register number equivalent to the string T.
+   Returns -1 if there is no such register.
+   Skips a leading 'r' or 'R' character if there is one.
+   Handles the register aliases PC and SP.  */
+
+static signed int
 check_reg (char * t)
 {
-  /* If this is a reg numb, str 't' must be a number from 0 - 15.  */
+  signed int val;
 
-  if (strlen (t) > 2 && *(t + 2) != '+')
-    return 1;
+  if (t == NULL)
+    return -1;
 
-  while (*t)
-    {
-      if ((*t < '0' || *t > '9') && *t != '+')
-       break;
-      t++;
-    }
+  if (*t == 'r' || *t == 'R')
+    ++t;
+
+  if (strncasecmp (t, "pc", 2) == 0)
+    return 0;
 
-  if (*t)
+  if (strncasecmp (t, "sp", 2) == 0)
     return 1;
 
-  return 0;
-}
+  if (strncasecmp (t, "sr", 2) == 0)
+    return 2;
+
+  if (*t == '0')
+    return 0;
 
+  val = atoi (t);
+
+  if (val < 1 || val > 15)
+    return -1;
+
+  return val;
+}
 
 static int
 msp430_srcoperand (struct msp430_operand_s * op,
-                  char * l, int bin, int * imm_op)
+                  char * l,
+                  int bin,
+                  int * imm_op,
+                  bfd_boolean allow_20bit_values,
+                  bfd_boolean constants_allowed)
 {
   char *__tl = l;
 
@@ -963,7 +1132,15 @@ msp430_srcoperand (struct msp430_operand_s * op,
              x = op->exp.X_add_number;
            }
 
-         if (op->exp.X_add_number > 65535 || op->exp.X_add_number < -32768)
+         if (allow_20bit_values)
+           {
+             if (op->exp.X_add_number > 0xfffff || op->exp.X_add_number < - (0x7ffff))
+               {
+                 as_bad (_("value 0x%x out of extended range."), x);
+                 return 1;
+               }
+           }
+         else if (op->exp.X_add_number > 65535 || op->exp.X_add_number < -32768)
            {
              as_bad (_("value %d out of range. Use #lo() or #hi()"), x);
              return 1;
@@ -972,9 +1149,12 @@ msp430_srcoperand (struct msp430_operand_s * op,
          /* Now check constants.  */
          /* Substitute register mode with a constant generator if applicable.  */
 
-         x = (short) x;        /* Extend sign.  */
+         if (!allow_20bit_values)
+           x = (short) x;      /* Extend sign.  */
 
-         if (x == 0)
+         if (! constants_allowed)
+           ;
+         else if (x == 0)
            {
              op->reg = 3;
              op->am = 0;
@@ -1126,9 +1306,17 @@ msp430_srcoperand (struct msp430_operand_s * op,
        {
          int x = op->exp.X_add_number;
 
-         if (x > 65535 || x < -32768)
+         if (allow_20bit_values)
+           {
+             if (x > 0xfffff || x < -(0x7ffff))
+               {
+                 as_bad (_("value 0x%x out of extended range."), x);
+                 return 1;
+               }
+           }
+         else if (x > 65535 || x < -32768)
            {
-             as_bad (_("value out of range: %d"), x);
+             as_bad (_("value out of range: 0x%x"), x);
              return 1;
            }
        }
@@ -1160,31 +1348,16 @@ msp430_srcoperand (struct msp430_operand_s * op,
        }
 
       t++;
-      if (*t != 'r' && *t != 'R')
-       {
-         as_bad (_("unknown addressing mode %s"), l);
-         return 1;
-       }
 
-      t++;     /* Points to the reg value.  */
-
-      if (check_reg (t))
+      if ((op->reg = check_reg (t)) == -1)
        {
-         as_bad (_("Bad register name r%s"), t);
+         as_bad (_("Bad register name %s"), t);
          return 1;
        }
 
       op->mode = OP_REG;
       op->am = m ? 3 : 2;
       op->ol = 0;
-      if (m)
-       *m = 0;                 /* strip '+' */
-      op->reg = atoi (t);
-      if (op->reg < 0 || op->reg > 15)
-       {
-         as_bad (_("MSP430 does not have %d registers"), op->reg);
-         return 1;
-       }
 
       return 0;
     }
@@ -1209,48 +1382,21 @@ msp430_srcoperand (struct msp430_operand_s * op,
       t = h;
       op->am = 1;
       op->ol = 1;
-      /* Extract a register.  */
-      t++;     /* Advance pointer.  */
 
-      if (*t != 'r' && *t != 'R')
+      /* Extract a register.  */
+      if ((op->reg = check_reg (t + 1)) == -1)
        {
          as_bad (_
                  ("unknown operator %s. Did you mean X(Rn) or #[hl][hl][oi](CONST) ?"),
                  l);
          return 1;
        }
-      t++;
 
-      op->reg = *t - '0';
-      if (op->reg > 9 || op->reg < 0)
+      if (op->reg == 2)
        {
-         as_bad (_("unknown operator (r%s substituted as a register name"),
-                 t);
+         as_bad (_("r2 should not be used in indexed addressing mode"));
          return 1;
        }
-      t++;
-      if (*t != ')')
-       {
-         op->reg = op->reg * 10;
-         op->reg += *t - '0';
-
-         if (op->reg > 15)
-           {
-             as_bad (_("unknown operator %s"), l);
-             return 1;
-           }
-         if (op->reg == 2)
-           {
-             as_bad (_("r2 should not be used in indexed addressing mode"));
-             return 1;
-           }
-
-         if (*(t + 1) != ')')
-           {
-             as_bad (_("unknown operator %s"), l);
-             return 1;
-           }
-       }
 
       /* Extract constant.  */
       __tl = l;
@@ -1261,9 +1407,17 @@ msp430_srcoperand (struct msp430_operand_s * op,
        {
          int x = op->exp.X_add_number;
 
-         if (x > 65535 || x < -32768)
+         if (allow_20bit_values)
+           {
+             if (x > 0xfffff || x < - (0x7ffff))
+               {
+                 as_bad (_("value 0x%x out of extended range."), x);
+                 return 1;
+               }
+           }
+         else if (x > 65535 || x < -32768)
            {
-             as_bad (_("value out of range: %d"), x);
+             as_bad (_("value out of range: 0x%x"), x);
              return 1;
            }
 
@@ -1292,37 +1446,22 @@ msp430_srcoperand (struct msp430_operand_s * op,
     }
   while (0);
 
-  /* Register mode 'mov r1,r2'.  */
-  do
+  /* Possibly register mode 'mov r1,r2'.  */
+  if ((op->reg = check_reg (l)) != -1)
     {
-      char *t = l;
-
-      /* Operand should be a register.  */
-      if (*t == 'r' || *t == 'R')
-       {
-         int x = atoi (t + 1);
-
-         if (check_reg (t + 1))
-           break;
-
-         if (x < 0 || x > 15)
-           break;              /* Symbolic mode.  */
-
-         op->mode = OP_REG;
-         op->am = 0;
-         op->ol = 0;
-         op->reg = x;
-         return 0;
-       }
+      op->mode = OP_REG;
+      op->am = 0;
+      op->ol = 0;
+      return 0;
     }
-  while (0);
 
   /* Symbolic mode 'mov a, b' == 'mov x(pc), y(pc)'.  */
   do
     {
       op->mode = OP_EXP;
       op->reg = 0;             /* PC relative... be careful.  */
-      op->am = 1;
+      /* An expression starting with a minus sign is a constant, not an address.  */
+      op->am = (*l == '-' ? 3 : 1);
       op->ol = 1;
       __tl = l;
       parse_exp (__tl, &(op->exp));
@@ -1337,10 +1476,16 @@ msp430_srcoperand (struct msp430_operand_s * op,
 
 
 static int
-msp430_dstoperand (struct msp430_operand_s * op, char * l, int bin)
+msp430_dstoperand (struct msp430_operand_s * op,
+                  char * l,
+                  int bin,
+                  bfd_boolean allow_20bit_values,
+                  bfd_boolean constants_allowed)
 {
   int dummy;
-  int ret = msp430_srcoperand (op, l, bin, & dummy);
+  int ret = msp430_srcoperand (op, l, bin, & dummy,
+                              allow_20bit_values,
+                              constants_allowed);
 
   if (ret)
     return ret;
@@ -1373,6 +1518,265 @@ msp430_dstoperand (struct msp430_operand_s * op, char * l, int bin)
 }
 
 
+/* Attempt to encode a MOVA instruction with the given operands.
+   Returns the length of the encoded instruction if successful
+   or 0 upon failure.  If the encoding fails, an error message
+   will be returned if a pointer is provided.  */
+
+static int
+try_encode_mova (bfd_boolean imm_op,
+                int bin,
+                struct msp430_operand_s * op1,
+                struct msp430_operand_s * op2,
+                const char ** error_message_return)
+{
+  short ZEROS = 0;
+  char *frag;
+  int where;
+
+  /* Only a restricted subset of the normal MSP430 addressing modes
+     are supported here, so check for the ones that are allowed.  */
+  if (imm_op)
+    {
+      if (op1->mode == OP_EXP)
+       {
+         if (op2->mode != OP_REG)
+           {
+             if (error_message_return != NULL)
+               * error_message_return = _("expected register as second argument of %s");
+             return 0;
+           }
+
+         if (op1->am == 3)
+           {
+             /* MOVA #imm20, Rdst.  */
+             bin |= 0x80 | op2->reg;
+             frag = frag_more (4);
+             where = frag - frag_now->fr_literal;
+             if (op1->exp.X_op == O_constant)
+               {
+                 bin |= ((op1->exp.X_add_number >> 16) & 0xf) << 8;
+                 bfd_putl16 ((bfd_vma) bin, frag);
+                 bfd_putl16 (op1->exp.X_add_number & 0xffff, frag + 2);
+               }
+             else
+               {
+                 bfd_putl16 ((bfd_vma) bin, frag);
+                 fix_new_exp (frag_now, where, 4, &(op1->exp), FALSE,
+                              BFD_RELOC_MSP430X_ABS20_ADR_SRC);
+                 bfd_putl16 ((bfd_vma) ZEROS, frag + 2);
+               }
+
+             return 4;
+           }
+         else if (op1->am == 1)
+           {
+             /* MOVA z16(Rsrc), Rdst.  */
+             bin |= 0x30 | (op1->reg << 8) | op2->reg;
+             frag = frag_more (4);
+             where = frag - frag_now->fr_literal;
+             bfd_putl16 ((bfd_vma) bin, frag);
+             if (op1->exp.X_op == O_constant)
+               {
+                 if (op1->exp.X_add_number > 0xffff
+                     || op1->exp.X_add_number < -(0x7fff))
+                   {
+                     if (error_message_return != NULL)
+                       * error_message_return = _("index value too big for %s");
+                     return 0;
+                   }
+                 bfd_putl16 (op1->exp.X_add_number & 0xffff, frag + 2);
+               }
+             else
+               {
+                 bfd_putl16 ((bfd_vma) ZEROS, frag + 2);
+                 fix_new_exp (frag_now, where + 2, 2, &(op1->exp), FALSE,
+                              op1->reg == 0 ?
+                              BFD_RELOC_MSP430X_PCR16 :
+                              BFD_RELOC_MSP430X_ABS16);
+               }
+             return 4;
+           }
+
+         if (error_message_return != NULL)
+           * error_message_return = _("unexpected addressing mode for %s");
+         return 0;
+       }
+      else if (op1->am == 0)
+       {
+         /* MOVA Rsrc, ... */
+         if (op2->mode == OP_REG)
+           {
+             bin |= 0xc0 | (op1->reg << 8) | op2->reg;
+             frag = frag_more (2);
+             where = frag - frag_now->fr_literal;
+             bfd_putl16 ((bfd_vma) bin, frag);
+             return 2;
+           }
+         else if (op2->am == 1)
+           {
+             if (op2->reg == 2)
+               {
+                 /* MOVA Rsrc, &abs20.  */
+                 bin |= 0x60 | (op1->reg << 8);
+                 frag = frag_more (4);
+                 where = frag - frag_now->fr_literal;
+                 if (op2->exp.X_op == O_constant)
+                   {
+                     bin |= (op2->exp.X_add_number >> 16) & 0xf;
+                     bfd_putl16 ((bfd_vma) bin, frag);
+                     bfd_putl16 (op2->exp.X_add_number & 0xffff, frag + 2);
+                   }
+                 else
+                   {
+                     bfd_putl16 ((bfd_vma) bin, frag);
+                     bfd_putl16 ((bfd_vma) ZEROS, frag + 2);
+                     fix_new_exp (frag_now, where, 4, &(op2->exp), FALSE,
+                                  BFD_RELOC_MSP430X_ABS20_ADR_DST);
+                   }
+                 return 4;
+               }
+
+             /* MOVA Rsrc, z16(Rdst).  */
+             bin |= 0x70 | (op1->reg << 8) | op2->reg;
+             frag = frag_more (4);
+             where = frag - frag_now->fr_literal;
+             bfd_putl16 ((bfd_vma) bin, frag);
+             if (op2->exp.X_op == O_constant)
+               {
+                 if (op2->exp.X_add_number > 0xffff
+                     || op2->exp.X_add_number < -(0x7fff))
+                   {
+                     if (error_message_return != NULL)
+                       * error_message_return = _("index value too big for %s");
+                     return 0;
+                   }
+                 bfd_putl16 (op2->exp.X_add_number & 0xffff, frag + 2);
+               }
+             else
+               {
+                 bfd_putl16 ((bfd_vma) ZEROS, frag + 2);
+                 fix_new_exp (frag_now, where + 2, 2, &(op2->exp), FALSE,
+                              op2->reg == 0 ?
+                              BFD_RELOC_MSP430X_PCR16 :
+                              BFD_RELOC_MSP430X_ABS16);
+               }
+             return 4;
+           }
+
+         if (error_message_return != NULL)
+           * error_message_return = _("unexpected addressing mode for %s");
+         return 0;
+       }
+    }
+
+  /* imm_op == FALSE.  */
+
+  if (op1->reg == 2 && op1->am == 1 && op1->mode == OP_EXP)
+    {
+      /* MOVA &abs20, Rdst.  */
+      if (op2->mode != OP_REG)
+       {
+         if (error_message_return != NULL)
+           * error_message_return = _("expected register as second argument of %s");
+         return 0;
+       }
+
+      if (op2->reg == 2 || op2->reg == 3)
+       {
+         if (error_message_return != NULL)
+           * error_message_return = _("constant generator destination register found in %s");
+         return 0;
+       }
+
+      bin |= 0x20 | op2->reg;
+      frag = frag_more (4);
+      where = frag - frag_now->fr_literal;
+      if (op1->exp.X_op == O_constant)
+       {
+         bin |= ((op1->exp.X_add_number >> 16) & 0xf) << 8;
+         bfd_putl16 ((bfd_vma) bin, frag);
+         bfd_putl16 (op1->exp.X_add_number & 0xffff, frag + 2);
+       }
+      else
+       {
+         bfd_putl16 ((bfd_vma) bin, frag);
+         bfd_putl16 ((bfd_vma) ZEROS, frag + 2);
+         fix_new_exp (frag_now, where, 4, &(op1->exp), FALSE,
+                      BFD_RELOC_MSP430X_ABS20_ADR_SRC);
+       }
+      return 4;
+    }
+  else if (op1->mode == OP_REG)
+    {
+      if (op1->am == 3)
+       {
+         /* MOVA @Rsrc+, Rdst.  */
+         if (op2->mode != OP_REG)
+           {
+             if (error_message_return != NULL)
+               * error_message_return = _("expected register as second argument of %s");
+             return 0;
+           }
+
+         if (op2->reg == 2 || op2->reg == 3)
+           {
+             if (error_message_return != NULL)
+               * error_message_return = _("constant generator destination register found in %s");
+             return 0;
+           }
+
+         if (op1->reg == 2 || op1->reg == 3)
+           {
+             if (error_message_return != NULL)
+               * error_message_return = _("constant generator source register found in %s");
+             return 0;
+           }
+
+         bin |= 0x10 | (op1->reg << 8) | op2->reg;
+         frag = frag_more (2);
+         where = frag - frag_now->fr_literal;
+         bfd_putl16 ((bfd_vma) bin, frag);
+         return 2;
+       }
+      else if (op1->am == 2)
+       {
+         /* MOVA @Rsrc,Rdst */
+         if (op2->mode != OP_REG)
+           {
+             if (error_message_return != NULL)
+               * error_message_return = _("expected register as second argument of %s");
+             return 0;
+           }
+
+         if (op2->reg == 2 || op2->reg == 3)
+           {
+             if (error_message_return != NULL)
+               * error_message_return = _("constant generator destination register found in %s");
+             return 0;
+           }
+
+         if (op1->reg == 2 || op1->reg == 3)
+           {
+             if (error_message_return != NULL)
+               * error_message_return = _("constant generator source register found in %s");
+             return 0;
+           }
+
+         bin |= (op1->reg << 8) | op2->reg;
+         frag = frag_more (2);
+         where = frag - frag_now->fr_literal;
+         bfd_putl16 ((bfd_vma) bin, frag);
+         return 2;
+       }
+    }
+
+  if (error_message_return != NULL)
+    * error_message_return = _("unexpected addressing mode for %s");
+
+  return 0;
+}
+
 /* Parse instruction operands.
    Return binary opcode.  */
 
@@ -1380,7 +1784,7 @@ static unsigned int
 msp430_operands (struct msp430_opcode_s * opcode, char * line)
 {
   int bin = opcode->bin_opcode;        /* Opcode mask.  */
-  int __is = 0;
+  int insn_length = 0;
   char l1[MAX_OP_LEN], l2[MAX_OP_LEN];
   char *frag;
   int where;
@@ -1388,6 +1792,14 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line)
   int res = 0;
   static short ZEROS = 0;
   int byte_op, imm_op;
+  int op_length = 0;
+  int fmt;
+  int extended = 0x1800;
+  bfd_boolean extended_op = FALSE;
+  bfd_boolean addr_op;
+  const char * error_message;
+  static signed int repeat_count = 0;
+  bfd_boolean fix_emitted;
 
   /* Opcode is the one from opcodes table
      line contains something like
@@ -1404,11 +1816,22 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line)
   else
     byte_op = 0;
 
-  /* skip .[bwBW].  */
+  /* "Address" ops work on 20-bit values.  */
+  if (*line == '.' && TOLOWER (*(line + 1)) == 'a')
+    {
+      addr_op = TRUE;
+      bin |= BYTE_OPERATION;
+    }
+  else
+    addr_op = FALSE;
+
+  /* skip .[aAbwBW].  */
   while (! ISSPACE (*line) && *line)
     line++;
 
-  if (opcode->insn_opnumb && (!*line || *line == '\n'))
+  if (opcode->fmt != -1
+      && opcode->insn_opnumb
+      && (!*line || *line == '\n'))
     {
       as_bad (_("instruction %s requires %d operand(s)"),
              opcode->name, opcode->insn_opnumb);
@@ -1422,204 +1845,971 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line)
 
   imm_op = 0;
 
-  switch (opcode->fmt)
+  if ((fmt = opcode->fmt) < 0)
+    {
+      if (msp430_mcu->isa != MSP430X_ISA)
+       {
+         as_bad (_("instruction %s requires MSP430X mcu"),
+                 opcode->name);
+         return 0;
+       }
+
+      fmt = (-fmt) - 1;
+      extended_op = TRUE;
+    }
+
+  if (repeat_count)
+    {
+      /* If requested set the extended instruction repeat count.  */
+      if (extended_op)
+       {
+         if (repeat_count > 0)
+           extended |= (repeat_count - 1);
+         else
+           extended |= (1 << 7) | (- repeat_count);
+       }
+      else
+       as_bad (_("unable to repeat %s insn"), opcode->name);
+
+      repeat_count = 0;
+    }
+
+  switch (fmt)
     {
     case 0:                    /* Emulated.  */
       switch (opcode->insn_opnumb)
        {
        case 0:
          /* Set/clear bits instructions.  */
-         __is = 2;
-         frag = frag_more (__is);
+         if (extended_op)
+           {
+             if (!addr_op)
+               extended |= BYTE_OPERATION;
+
+             /* Emit the extension word.  */
+             insn_length += 2;
+             frag = frag_more (insn_length);
+             bfd_putl16 (extended, frag);
+           }
+         insn_length += 2;
+         frag = frag_more (insn_length);
          bfd_putl16 ((bfd_vma) bin, frag);
-         dwarf2_emit_insn (__is);
+
+         if (gen_interrupt_nops
+             && msp430_mcu->isa == MSP430_ISA_54
+             && (strcmp (opcode->name, "eint") == 0
+                 || strcmp (opcode->name, "dint") == 0))
+           {
+             /* Emit a NOP following interrupt enable/disable.
+                See 1.3.4.1 of the MSP430x5xx User Guide.  */
+             insn_length += 2;
+             frag = frag_more (2);
+             bfd_putl16 ((bfd_vma) 0x4303 /* NOP */, frag);
+           }
+
+         dwarf2_emit_insn (insn_length);
          break;
+
        case 1:
          /* Something which works with destination operand.  */
          line = extract_operand (line, l1, sizeof (l1));
-         res = msp430_dstoperand (&op1, l1, opcode->bin_opcode);
+         res = msp430_dstoperand (&op1, l1, opcode->bin_opcode, extended_op, TRUE);
          if (res)
            break;
 
-         bin |= (op1.reg | (op1.am << 7));
-         __is = 1 + op1.ol;
-         frag = frag_more (2 * __is);
+         /* Compute the entire instruction length, in bytes.  */
+         insn_length = (extended_op ? 2 : 0) + 2 + (op1.ol * 2);
+         frag = frag_more (insn_length);
          where = frag - frag_now->fr_literal;
-         bfd_putl16 ((bfd_vma) bin, frag);
-         dwarf2_emit_insn (2 * __is);
 
-         if (op1.mode == OP_EXP)
+         if (extended_op)
            {
-             where += 2;
-             bfd_putl16 ((bfd_vma) ZEROS, frag + 2);
+             if (!addr_op)
+               extended |= BYTE_OPERATION;
+
+             if (op1.ol != 0 && ((extended & 0xf) != 0))
+               {
+                 as_bad (_("repeat instruction used with non-register mode instruction"));
+                 extended &= ~ 0xf;
+               }
 
-             if (op1.reg)
-               fix_new_exp (frag_now, where, 2,
-                            &(op1.exp), FALSE, CHECK_RELOC_MSP430);
+             if (op1.mode == OP_EXP)
+               {
+                 if (op1.exp.X_op == O_constant)
+                   extended |= ((op1.exp.X_add_number >> 16) & 0xf) << 7;
+
+                 else if (op1.reg || (op1.reg == 0 && op1.am == 3))    /* Not PC relative.  */
+                   fix_new_exp (frag_now, where, 6, &(op1.exp), FALSE,
+                                BFD_RELOC_MSP430X_ABS20_EXT_SRC);
+                 else
+                   fix_new_exp (frag_now, where, 6, &(op1.exp), FALSE,
+                                BFD_RELOC_MSP430X_PCR20_EXT_SRC);
+               }
+
+             /* Emit the extension word.  */
+             bfd_putl16 (extended, frag);
+             frag += 2;
+             where += 2;
+           }
+
+         bin |= (op1.reg | (op1.am << 7));
+         bfd_putl16 ((bfd_vma) bin, frag);
+         frag += 2;
+         where += 2;
+
+         if (op1.mode == OP_EXP)
+           {
+             if (op1.exp.X_op == O_constant)
+               {
+                 bfd_putl16 (op1.exp.X_add_number & 0xffff, frag);
+               }
              else
-               fix_new_exp (frag_now, where, 2,
-                            &(op1.exp), TRUE, CHECK_RELOC_MSP430_PCREL);
+               {
+                 bfd_putl16 ((bfd_vma) ZEROS, frag);
+
+                 if (!extended_op)
+                   {
+                     if (op1.reg)
+                       fix_new_exp (frag_now, where, 2,
+                                    &(op1.exp), FALSE, CHECK_RELOC_MSP430);
+                     else
+                       fix_new_exp (frag_now, where, 2,
+                                    &(op1.exp), TRUE, CHECK_RELOC_MSP430_PCREL);
+                   }
+               }
+           }
+
+         if (gen_interrupt_nops
+             && msp430_mcu->isa == MSP430_ISA_54
+             && strcmp (opcode->name, "clr") == 0
+             && bin == 0x4302 /* CLR R2*/)
+           {
+             /* Emit a NOP following interrupt enable/disable.
+                See 1.3.4.1 of the MSP430x5xx User Guide.  */
+             insn_length += 2;
+             frag = frag_more (2);
+             bfd_putl16 ((bfd_vma) 0x4303 /* NOP */, frag);
            }
+
+         dwarf2_emit_insn (insn_length);
          break;
 
        case 2:
+         /* Shift instruction.  */
+         line = extract_operand (line, l1, sizeof (l1));
+         strncpy (l2, l1, sizeof (l2));
+         l2[sizeof (l2) - 1] = '\0';
+         res = msp430_srcoperand (&op1, l1, opcode->bin_opcode, &imm_op, extended_op, TRUE);
+         res += msp430_dstoperand (&op2, l2, opcode->bin_opcode, extended_op, TRUE);
+
+         if (res)
+           break;      /* An error occurred.  All warnings were done before.  */
+
+         insn_length = (extended_op ? 2 : 0) + 2 + (op1.ol * 2) + (op2.ol * 2);
+         frag = frag_more (insn_length);
+         where = frag - frag_now->fr_literal;
+
+         if (extended_op)
+           {
+             if (!addr_op)
+               extended |= BYTE_OPERATION;
+
+             if ((op1.ol != 0 || op2.ol != 0) && ((extended & 0xf) != 0))
+               {
+                 as_bad (_("repeat instruction used with non-register mode instruction"));
+                 extended &= ~ 0xf;
+               }
+
+             if (op1.mode == OP_EXP)
+               {
+                 if (op1.exp.X_op == O_constant)
+                   extended |= ((op1.exp.X_add_number >> 16) & 0xf) << 7;
+
+                 else if (op1.reg || (op1.reg == 0 && op1.am == 3))    /* Not PC relative.  */
+                   fix_new_exp (frag_now, where, 6, &(op1.exp), FALSE,
+                                BFD_RELOC_MSP430X_ABS20_EXT_SRC);
+                 else
+                   fix_new_exp (frag_now, where, 6, &(op1.exp), FALSE,
+                                BFD_RELOC_MSP430X_PCR20_EXT_SRC);
+               }
+
+             if (op2.mode == OP_EXP)
+               {
+                 if (op2.exp.X_op == O_constant)
+                   extended |= (op2.exp.X_add_number >> 16) & 0xf;
+
+                 else if (op1.mode == OP_EXP)
+                   fix_new_exp (frag_now, where, 8, &(op2.exp), FALSE,
+                                op2.reg ? BFD_RELOC_MSP430X_ABS20_EXT_ODST
+                                : BFD_RELOC_MSP430X_PCR20_EXT_ODST);
+                 else
+                   fix_new_exp (frag_now, where, 6, &(op2.exp), FALSE,
+                                op2.reg ? BFD_RELOC_MSP430X_ABS20_EXT_DST
+                                : BFD_RELOC_MSP430X_PCR20_EXT_DST);
+               }
+
+             /* Emit the extension word.  */
+             bfd_putl16 (extended, frag);
+             frag += 2;
+             where += 2;
+           }
+
+         bin |= (op2.reg | (op1.reg << 8) | (op1.am << 4) | (op2.am << 7));
+         bfd_putl16 ((bfd_vma) bin, frag);
+         frag += 2;
+         where += 2;
+
+         if (op1.mode == OP_EXP)
+           {
+             if (op1.exp.X_op == O_constant)
+               {
+                 bfd_putl16 (op1.exp.X_add_number & 0xffff, frag);
+               }
+             else
+               {
+                 bfd_putl16 ((bfd_vma) ZEROS, frag);
+
+                 if (!extended_op)
+                   {
+                     if (op1.reg || (op1.reg == 0 && op1.am == 3))     /* Not PC relative.  */
+                       fix_new_exp (frag_now, where, 2,
+                                    &(op1.exp), FALSE, CHECK_RELOC_MSP430);
+                     else
+                       fix_new_exp (frag_now, where, 2,
+                                    &(op1.exp), TRUE, CHECK_RELOC_MSP430_PCREL);
+                   }
+               }
+             frag += 2;
+             where += 2;
+           }
+
+         if (op2.mode == OP_EXP)
+           {
+             if (op2.exp.X_op == O_constant)
+               {
+                 bfd_putl16 (op2.exp.X_add_number & 0xffff, frag);
+               }
+             else
+               {
+                 bfd_putl16 ((bfd_vma) ZEROS, frag);
+
+                 if (!extended_op)
+                   {
+                     if (op2.reg)      /* Not PC relative.  */
+                       fix_new_exp (frag_now, where, 2,
+                                    &(op2.exp), FALSE, CHECK_RELOC_MSP430);
+                     else
+                       fix_new_exp (frag_now, where, 2,
+                                    &(op2.exp), TRUE, CHECK_RELOC_MSP430_PCREL);
+                   }
+               }
+           }
+
+         dwarf2_emit_insn (insn_length);
+         break;
+
+       case 3:
+         /* Branch instruction => mov dst, r0.  */
+         if (extended_op)
+           {
+             as_bad ("Internal error: state 0/3 not coded for extended instructions");
+             return 0;
+           }
+
+         line = extract_operand (line, l1, sizeof (l1));
+         res = msp430_srcoperand (&op1, l1, opcode->bin_opcode, &imm_op, extended_op, FALSE);
+         if (res)
+           break;
+
+         byte_op = 0;
+         imm_op = 0;
+         bin |= ((op1.reg << 8) | (op1.am << 4));
+         op_length = 2 + 2 * op1.ol;
+         frag = frag_more (op_length);
+         where = frag - frag_now->fr_literal;
+         bfd_putl16 ((bfd_vma) bin, frag);
+
+         if (op1.mode == OP_EXP)
+           {
+             if (op1.exp.X_op == O_constant)
+               {
+                 bfd_putl16 (op1.exp.X_add_number & 0xffff, frag + 2);
+               }
+             else
+               {
+                 where += 2;
+
+                 bfd_putl16 ((bfd_vma) ZEROS, frag + 2);
+
+                 if (op1.reg || (op1.reg == 0 && op1.am == 3))
+                   fix_new_exp (frag_now, where, 2,
+                                &(op1.exp), FALSE, CHECK_RELOC_MSP430);
+                 else
+                   fix_new_exp (frag_now, where, 2,
+                                &(op1.exp), TRUE, CHECK_RELOC_MSP430_PCREL);
+               }
+           }
+
+         dwarf2_emit_insn (insn_length + op_length);
+         break;
+
+       case 4:
+         /* CALLA instructions.  */
+         fix_emitted = FALSE;
+
+         line = extract_operand (line, l1, sizeof (l1));
+         imm_op = 0;
+
+         res = msp430_srcoperand (&op1, l1, opcode->bin_opcode, &imm_op,
+                                  extended_op, FALSE);
+         if (res)
+           break;
+
+         byte_op = 0;
+
+         op_length = 2 + 2 * op1.ol;
+         frag = frag_more (op_length);
+         where = frag - frag_now->fr_literal;
+
+         if (imm_op)
+           {
+             if (op1.am == 3)
+               {
+                 bin |= 0xb0;
+
+                 fix_new_exp (frag_now, where, 4, &(op1.exp), FALSE,
+                              BFD_RELOC_MSP430X_ABS20_ADR_DST);
+                 fix_emitted = TRUE;
+               }
+             else if (op1.am == 1)
+               {
+                 if (op1.reg == 0)
+                   {
+                     bin |=  0x90;
+
+                     fix_new_exp (frag_now, where, 4, &(op1.exp), FALSE,
+                                  BFD_RELOC_MSP430X_PCR20_CALL);
+                     fix_emitted = TRUE;
+                   }
+                 else
+                   bin |=  0x50 | op1.reg;
+               }
+             else if (op1.am == 0)
+               bin |= 0x40 | op1.reg;
+           }
+         else if (op1.am == 1)
+           {
+             bin |= 0x80;
+
+             fix_new_exp (frag_now, where, 4, &(op1.exp), FALSE,
+                          BFD_RELOC_MSP430X_ABS20_ADR_DST);
+             fix_emitted = TRUE;
+           }
+         else if (op1.am == 2)
+           bin |= 0x60 | op1.reg;
+         else if (op1.am == 3)
+           bin |= 0x70 | op1.reg;
+
+         bfd_putl16 ((bfd_vma) bin, frag);
+
+         if (op1.mode == OP_EXP)
+           {
+             if (op1.ol != 1)
+               {
+                 as_bad ("Internal error: unexpected CALLA instruction length: %d\n", op1.ol);
+                 return 0;
+               }
+
+             bfd_putl16 ((bfd_vma) ZEROS, frag + 2);
+
+             if (! fix_emitted)
+               fix_new_exp (frag_now, where + 2, 2,
+                            &(op1.exp), FALSE, BFD_RELOC_16);
+           }
+
+         dwarf2_emit_insn (insn_length + op_length);
+         break;
+
+       case 5:
          {
-           /* Shift instruction.  */
+           int n;
+           int reg;
+
+           /* [POP|PUSH]M[.A] #N, Rd */
            line = extract_operand (line, l1, sizeof (l1));
-           strncpy (l2, l1, sizeof (l2));
-           l2[sizeof (l2) - 1] = '\0';
-           res = msp430_srcoperand (&op1, l1, opcode->bin_opcode, &imm_op);
-           res += msp430_dstoperand (&op2, l2, opcode->bin_opcode);
+           line = extract_operand (line, l2, sizeof (l2));
 
-           if (res)
-             break;    /* An error occurred.  All warnings were done before.  */
+           if (*l1 != '#')
+             {
+               as_bad (_("expected #n as first argument of POPM"));
+               return 0;
+             }
+           parse_exp (l1 + 1, &(op1.exp));
+           if (op1.exp.X_op != O_constant)
+             {
+               as_bad (_("expected constant expression for first argument of %s"),
+                       opcode->name);
+               return 0;
+             }
 
-           bin |= (op2.reg | (op1.reg << 8) | (op1.am << 4) | (op2.am << 7));
+           if ((reg = check_reg (l2)) == -1)
+             {
+               as_bad (_("expected register as second argument of %s"),
+                       opcode->name);
+               return 0;
+             }
 
-           __is = 1 + op1.ol + op2.ol; /* insn size in words.  */
-           frag = frag_more (2 * __is);
+           op_length = 2;
+           frag = frag_more (op_length);
            where = frag - frag_now->fr_literal;
+           bin = opcode->bin_opcode;
+           if (! addr_op)
+             bin |= 0x100;
+           n = op1.exp.X_add_number;
+           bin |= (n - 1) << 4;
+           if (strcmp (opcode->name, "pushm") == 0)
+             bin |= reg;
+           else
+             {
+               if (reg - n + 1 < 0)
+                 {
+                   as_bad (_("Too many registers popped"));
+                   return 0;
+                 }
+               bin |= (reg - n + 1);
+             }
+
            bfd_putl16 ((bfd_vma) bin, frag);
-           dwarf2_emit_insn (2 * __is);
-           
-           if (op1.mode == OP_EXP)
+           dwarf2_emit_insn (op_length);
+           break;
+         }
+
+       case 6:
+         {
+           int n;
+           int reg;
+
+           /* Bit rotation instructions. RRCM, RRAM, RRUM, RLAM.  */
+           if (extended & 0xff)
+             {
+               as_bad (_("repeat count cannot be used with %s"), opcode->name);
+               return 0;
+             }
+
+           line = extract_operand (line, l1, sizeof (l1));
+           line = extract_operand (line, l2, sizeof (l2));
+
+           if (*l1 != '#')
+             {
+               as_bad (_("expected #n as first argument of %s"), opcode->name);
+               return 0;
+             }
+           parse_exp (l1 + 1, &(op1.exp));
+           if (op1.exp.X_op != O_constant)
+             {
+               as_bad (_("expected constant expression for first argument of %s"),
+                       opcode->name);
+               return 0;
+             }
+           n = op1.exp.X_add_number;
+           if (n > 4 || n < 1)
              {
-               where += 2;     /* Advance 'where' as we do not know _where_.  */
-               bfd_putl16 ((bfd_vma) ZEROS, frag + 2);
+               as_bad (_("expected first argument of %s to be in the range 1-4"),
+                       opcode->name);
+               return 0;
+             }
 
-               if (op1.reg || (op1.reg == 0 && op1.am == 3))   /* Not PC relative.  */
-                 fix_new_exp (frag_now, where, 2,
-                              &(op1.exp), FALSE, CHECK_RELOC_MSP430);
-               else
-                 fix_new_exp (frag_now, where, 2,
-                              &(op1.exp), TRUE, CHECK_RELOC_MSP430_PCREL);
+           if ((reg = check_reg (l2)) == -1)
+             {
+               as_bad (_("expected register as second argument of %s"),
+                       opcode->name);
+               return 0;
              }
 
-           if (op2.mode == OP_EXP)
+           op_length = 2;
+           frag = frag_more (op_length);
+           where = frag - frag_now->fr_literal;
+
+           bin = opcode->bin_opcode;
+           if (! addr_op)
+             bin |= 0x10;
+           bin |= (n - 1) << 10;
+           bin |= reg;
+
+           bfd_putl16 ((bfd_vma) bin, frag);
+           dwarf2_emit_insn (op_length);
+           break;
+         }
+
+       case 7:
+         {
+           int reg;
+
+           /* RRUX: Synthetic unsigned right shift of a register by one bit.  */
+           if (extended & 0xff)
              {
-               imm_op = 0;
-               bfd_putl16 ((bfd_vma) ZEROS, frag + 2 + ((__is == 3) ? 2 : 0));
+               as_bad (_("repeat count cannot be used with %s"), opcode->name);
+               return 0;
+             }
 
-               if (op2.reg)    /* Not PC relative.  */
-                 fix_new_exp (frag_now, where + 2, 2,
-                              &(op2.exp), FALSE, CHECK_RELOC_MSP430);
-               else
-                 fix_new_exp (frag_now, where + 2, 2,
-                              &(op2.exp), TRUE, CHECK_RELOC_MSP430_PCREL);
+           line = extract_operand (line, l1, sizeof (l1));
+           if ((reg = check_reg (l1)) == -1)
+             {
+               as_bad (_("expected register as argument of %s"),
+                       opcode->name);
+               return 0;
+             }
+
+           if (byte_op)
+             {
+               /* Tricky - there is no single instruction that will do this.
+                  Encode as: RRA.B rN { BIC.B #0x80, rN  */
+               op_length = 6;
+               frag = frag_more (op_length);
+               where = frag - frag_now->fr_literal;
+               bin = 0x1140 | reg;
+               bfd_putl16 ((bfd_vma) bin, frag);
+               dwarf2_emit_insn (2);
+               bin = 0xc070 | reg;
+               bfd_putl16 ((bfd_vma) bin, frag + 2);
+               bin = 0x0080;
+               bfd_putl16 ((bfd_vma) bin, frag + 4);
+               dwarf2_emit_insn (4);
+             }
+           else
+             {
+               /* Encode as RRUM[.A] rN.  */
+               bin = opcode->bin_opcode;
+               if (! addr_op)
+                 bin |= 0x10;
+               bin |= reg;
+               op_length = 2;
+               frag = frag_more (op_length);
+               where = frag - frag_now->fr_literal;
+               bfd_putl16 ((bfd_vma) bin, frag);
+               dwarf2_emit_insn (op_length);
              }
            break;
          }
-       case 3:
-         /* Branch instruction => mov dst, r0.  */
-         line = extract_operand (line, l1, sizeof (l1));
 
-         res = msp430_srcoperand (&op1, l1, opcode->bin_opcode, &imm_op);
-         if (res)
+       case 8:
+         {
+           bfd_boolean need_reloc = FALSE;
+           int n;
+           int reg;
+
+           /* ADDA, CMPA and SUBA address instructions.  */
+           if (extended & 0xff)
+             {
+               as_bad (_("repeat count cannot be used with %s"), opcode->name);
+               return 0;
+             }
+
+           line = extract_operand (line, l1, sizeof (l1));
+           line = extract_operand (line, l2, sizeof (l2));
+
+           bin = opcode->bin_opcode;
+
+           if (*l1 == '#')
+             {
+               parse_exp (l1 + 1, &(op1.exp));
+
+               if (op1.exp.X_op == O_constant)
+                 {
+                   n = op1.exp.X_add_number;
+                   if (n > 0xfffff || n < - (0x7ffff))
+                     {
+                       as_bad (_("expected value of first argument of %s to fit into 20-bits"),
+                               opcode->name);
+                       return 0;
+                     }
+
+                   bin |= ((n >> 16) & 0xf) << 8;
+                 }
+               else
+                 {
+                   n = 0;
+                   need_reloc = TRUE;
+                 }
+
+               op_length = 4;
+             }
+           else
+             {
+               if ((n = check_reg (l1)) == -1)
+                 {
+                   as_bad (_("expected register name or constant as first argument of %s"),
+                           opcode->name);
+                   return 0;
+                 }
+
+               bin |= (n << 8) | (1 << 6);
+               op_length = 2;
+             }
+
+           if ((reg = check_reg (l2)) == -1)
+             {
+               as_bad (_("expected register as second argument of %s"),
+                       opcode->name);
+               return 0;
+             }
+
+           frag = frag_more (op_length);
+           where = frag - frag_now->fr_literal;
+           bin |= reg;
+           if (need_reloc)
+             fix_new_exp (frag_now, where, 4, &(op1.exp), FALSE,
+                          BFD_RELOC_MSP430X_ABS20_ADR_SRC);
+
+           bfd_putl16 ((bfd_vma) bin, frag);
+           if (op_length == 4)
+             bfd_putl16 ((bfd_vma) (n & 0xffff), frag + 2);
+           dwarf2_emit_insn (op_length);
            break;
+         }
 
-         byte_op = 0;
+       case 9: /* MOVA, BRA, RETA.  */
          imm_op = 0;
+         bin = opcode->bin_opcode;
 
-         bin |= ((op1.reg << 8) | (op1.am << 4));
-         __is = 1 + op1.ol;
-         frag = frag_more (2 * __is);
-         where = frag - frag_now->fr_literal;
-         bfd_putl16 ((bfd_vma) bin, frag);
-         dwarf2_emit_insn (2 * __is);
+         if (strcmp (opcode->name, "reta") == 0)
+           {
+             /* The RETA instruction does not take any arguments.
+                The implicit first argument is @SP+.
+                The implicit second argument is PC.  */
+             op1.mode = OP_REG;
+             op1.am = 3;
+             op1.reg = 1;
+
+             op2.mode = OP_REG;
+             op2.reg = 0;
+           }
+         else
+           {
+             line = extract_operand (line, l1, sizeof (l1));
+             res = msp430_srcoperand (&op1, l1, opcode->bin_opcode,
+                                      &imm_op, extended_op, FALSE);
 
-         if (op1.mode == OP_EXP)
+             if (strcmp (opcode->name, "bra") == 0)
+               {
+                 /* This is the BRA synthetic instruction.
+                    The second argument is always PC.  */
+                 op2.mode = OP_REG;
+                 op2.reg = 0;
+               }
+             else
+               {
+                 line = extract_operand (line, l2, sizeof (l2));
+                 res += msp430_dstoperand (&op2, l2, opcode->bin_opcode,
+                                           extended_op, TRUE);
+               }
+
+             if (res)
+               break;  /* Error occurred.  All warnings were done before.  */
+           }
+
+         /* Only a restricted subset of the normal MSP430 addressing modes
+            are supported here, so check for the ones that are allowed.  */
+         if ((op_length = try_encode_mova (imm_op, bin, & op1, & op2,
+                                           & error_message)) == 0)
            {
-             where += 2;
-             bfd_putl16 ((bfd_vma) ZEROS, frag + 2);
+             as_bad (error_message, opcode->name);
+             return 0;
+           }
+         dwarf2_emit_insn (op_length);
+         break;
+
+       case 10: /* RPT */
+         line = extract_operand (line, l1, sizeof l1);
+         /* The RPT instruction only accepted immediates and registers.  */
+         if (*l1 == '#')
+           {
+             parse_exp (l1 + 1, &(op1.exp));
+             if (op1.exp.X_op != O_constant)
+               {
+                 as_bad (_("expected constant value as argument to RPT"));
+                 return 0;
+               }
+             if (op1.exp.X_add_number < 1
+                 || op1.exp.X_add_number > (1 << 4))
+               {
+                 as_bad (_("expected constant in the range 2..16"));
+                 return 0;
+               }
+
+             /* We silently accept and ignore a repeat count of 1.  */
+             if (op1.exp.X_add_number > 1)
+               repeat_count = op1.exp.X_add_number;
+           }
+         else
+           {
+             int reg;
 
-             if (op1.reg || (op1.reg == 0 && op1.am == 3))
-               fix_new_exp (frag_now, where, 2,
-                            &(op1.exp), FALSE, CHECK_RELOC_MSP430);
+             if ((reg = check_reg (l1)) != -1)
+               {
+                 if (reg == 0)
+                   as_warn (_("PC used as an argument to RPT"));
+                 else
+                   repeat_count = - reg;
+               }
              else
-               fix_new_exp (frag_now, where, 2,
-                            &(op1.exp), TRUE, CHECK_RELOC_MSP430_PCREL);
+               {
+                 as_bad (_("expected constant or register name as argument to RPT insn"));
+                 return 0;
+               }
            }
          break;
+
+       default:
+         as_bad (_("Illegal emulated instruction "));
+         break;
        }
       break;
 
     case 1:                    /* Format 1, double operand.  */
       line = extract_operand (line, l1, sizeof (l1));
       line = extract_operand (line, l2, sizeof (l2));
-      res = msp430_srcoperand (&op1, l1, opcode->bin_opcode, &imm_op);
-      res += msp430_dstoperand (&op2, l2, opcode->bin_opcode);
+      res = msp430_srcoperand (&op1, l1, opcode->bin_opcode, &imm_op, extended_op, TRUE);
+      res += msp430_dstoperand (&op2, l2, opcode->bin_opcode, extended_op, TRUE);
 
       if (res)
        break;                  /* Error occurred.  All warnings were done before.  */
 
-      bin |= (op2.reg | (op1.reg << 8) | (op1.am << 4) | (op2.am << 7));
+      if (extended_op
+         && strcmp (opcode->name, "movx") == 0
+         && addr_op
+         && msp430_enable_relax)
+       {
+         /* This is the MOVX.A instruction.  See if we can convert
+            it into the MOVA instruction instead.  This saves 2 bytes.  */
+         if ((op_length = try_encode_mova (imm_op, 0x0000, & op1, & op2,
+                                           NULL)) != 0)
+           {
+             dwarf2_emit_insn (op_length);
+             break;
+           }
+       }
+
+      /* Compute the entire length of the instruction in bytes.  */
+      insn_length =
+       (extended_op ? 2 : 0)   /* The extension word.  */
+       + 2                     /* The opcode */
+       + (2 * op1.ol)          /* The first operand. */
+       + (2 * op2.ol);         /* The second operand.  */
 
-      __is = 1 + op1.ol + op2.ol;      /* insn size in words.  */
-      frag = frag_more (2 * __is);
+      frag = frag_more (insn_length);
       where = frag - frag_now->fr_literal;
+
+      if (extended_op)
+       {
+         if (!addr_op)
+           extended |= BYTE_OPERATION;
+
+         if ((op1.ol != 0 || op2.ol != 0) && ((extended & 0xf) != 0))
+           {
+             as_bad (_("repeat instruction used with non-register mode instruction"));
+             extended &= ~ 0xf;
+           }
+
+         /* If necessary, emit a reloc to update the extension word.  */
+         if (op1.mode == OP_EXP)
+           {
+             if (op1.exp.X_op == O_constant)
+               extended |= ((op1.exp.X_add_number >> 16) & 0xf) << 7;
+
+             else  if (op1.reg || (op1.reg == 0 && op1.am == 3))       /* Not PC relative.  */
+               fix_new_exp (frag_now, where, 6, &(op1.exp), FALSE,
+                            BFD_RELOC_MSP430X_ABS20_EXT_SRC);
+             else
+               fix_new_exp (frag_now, where, 6, &(op1.exp), FALSE,
+                            BFD_RELOC_MSP430X_PCR20_EXT_SRC);
+           }
+
+         if (op2.mode == OP_EXP)
+           {
+             if (op2.exp.X_op == O_constant)
+               extended |= (op2.exp.X_add_number >> 16) & 0xf;
+
+             else if (op1.mode == OP_EXP)
+               fix_new_exp (frag_now, where, 8, &(op2.exp), FALSE,
+                            op2.reg ? BFD_RELOC_MSP430X_ABS20_EXT_ODST
+                            : BFD_RELOC_MSP430X_PCR20_EXT_ODST);
+
+             else
+               fix_new_exp (frag_now, where, 6, &(op2.exp), FALSE,
+                            op2.reg ? BFD_RELOC_MSP430X_ABS20_EXT_DST
+                            : BFD_RELOC_MSP430X_PCR20_EXT_DST);
+           }
+
+         /* Emit the extension word.  */
+         bfd_putl16 (extended, frag);
+         where += 2;
+         frag += 2;
+       }
+
+      bin |= (op2.reg | (op1.reg << 8) | (op1.am << 4) | (op2.am << 7));
       bfd_putl16 ((bfd_vma) bin, frag);
-      dwarf2_emit_insn (2 * __is);
+      where += 2;
+      frag += 2;
 
       if (op1.mode == OP_EXP)
        {
-         where += 2;           /* Advance where as we do not know _where_.  */
-         bfd_putl16 ((bfd_vma) ZEROS, frag + 2);
-
-         if (op1.reg || (op1.reg == 0 && op1.am == 3)) /* Not PC relative.  */
-           fix_new_exp (frag_now, where, 2,
-                        &(op1.exp), FALSE, CHECK_RELOC_MSP430);
+         if (op1.exp.X_op == O_constant)
+           {
+             bfd_putl16 (op1.exp.X_add_number & 0xffff, frag);
+           }
          else
-           fix_new_exp (frag_now, where, 2,
-                        &(op1.exp), TRUE, CHECK_RELOC_MSP430_PCREL);
+           {
+             bfd_putl16 ((bfd_vma) ZEROS, frag);
+
+             if (!extended_op)
+               {
+                 if (op1.reg || (op1.reg == 0 && op1.am == 3)) /* Not PC relative.  */
+                   fix_new_exp (frag_now, where, 2,
+                                &(op1.exp), FALSE, CHECK_RELOC_MSP430);
+                 else
+                   fix_new_exp (frag_now, where, 2,
+                                &(op1.exp), TRUE, CHECK_RELOC_MSP430_PCREL);
+               }
+           }
+
+         where += 2;
+         frag += 2;
        }
 
       if (op2.mode == OP_EXP)
        {
-         imm_op = 0;
-         bfd_putl16 ((bfd_vma) ZEROS, frag + 2 + ((__is == 3) ? 2 : 0));
-
-         if (op2.reg)          /* Not PC relative.  */
-           fix_new_exp (frag_now, where + 2, 2,
-                        &(op2.exp), FALSE, CHECK_RELOC_MSP430);
+         if (op2.exp.X_op == O_constant)
+           {
+             bfd_putl16 (op2.exp.X_add_number & 0xffff, frag);
+           }
          else
-           fix_new_exp (frag_now, where + 2, 2,
-                        &(op2.exp), TRUE, CHECK_RELOC_MSP430_PCREL);
+           {
+             bfd_putl16 ((bfd_vma) ZEROS, frag);
+
+             if (!extended_op)
+               {
+                 if (op2.reg)          /* Not PC relative.  */
+                   fix_new_exp (frag_now, where, 2,
+                            &(op2.exp), FALSE, CHECK_RELOC_MSP430);
+                 else
+                   fix_new_exp (frag_now, where, 2,
+                                &(op2.exp), TRUE, CHECK_RELOC_MSP430_PCREL);
+               }
+           }
+       }
+
+      if (gen_interrupt_nops
+         && msp430_mcu->isa == MSP430_ISA_54
+         && (   (strcmp (opcode->name, "bic") == 0 && bin == 0xc232)
+             || (strcmp (opcode->name, "bis") == 0 && bin == 0xd232)
+             || (strcmp (opcode->name, "mov") == 0 && op2.mode == OP_REG && op2.reg == 2)))
+       {
+         /* Emit a NOP following interrupt enable/disable.
+            See 1.3.4.1 of the MSP430x5xx User Guide.  */
+         insn_length += 2;
+         frag = frag_more (2);
+         bfd_putl16 ((bfd_vma) 0x4303 /* NOP */, frag);
        }
+
+      dwarf2_emit_insn (insn_length);
       break;
 
     case 2:                    /* Single-operand mostly instr.  */
       if (opcode->insn_opnumb == 0)
        {
          /* reti instruction.  */
+         insn_length += 2;
          frag = frag_more (2);
          bfd_putl16 ((bfd_vma) bin, frag);
-         dwarf2_emit_insn (2);
+         dwarf2_emit_insn (insn_length);
          break;
        }
 
       line = extract_operand (line, l1, sizeof (l1));
-      res = msp430_srcoperand (&op1, l1, opcode->bin_opcode, &imm_op);
+      res = msp430_srcoperand (&op1, l1, opcode->bin_opcode,
+                              &imm_op, extended_op, TRUE);
       if (res)
        break;          /* Error in operand.  */
 
-      bin |= op1.reg | (op1.am << 4);
-      __is = 1 + op1.ol;
-      frag = frag_more (2 * __is);
+      insn_length = (extended_op ? 2 : 0) + 2 + (op1.ol * 2);
+      frag = frag_more (insn_length);
       where = frag - frag_now->fr_literal;
+
+      if (extended_op)
+       {
+         if (strcmp (opcode->name, "swpbx") == 0
+             || strcmp (opcode->name, "sxtx") == 0)
+           {
+             /* These two instructions use a special
+                encoding of the A/L and B/W bits.  */
+             bin &= ~ BYTE_OPERATION;
+
+             if (byte_op)
+               {
+                 as_bad (_("%s instruction does not accept a .b suffix"),
+                         opcode->name);
+                 return 0;
+               }
+             else if (! addr_op)
+               extended |= BYTE_OPERATION;
+           }
+         else if (! addr_op)
+           extended |= BYTE_OPERATION;
+
+         if (op1.ol != 0 && ((extended & 0xf) != 0))
+           {
+             as_bad (_("repeat instruction used with non-register mode instruction"));
+             extended &= ~ 0xf;
+           }
+
+         if (op1.mode == OP_EXP)
+           {
+             if (op1.exp.X_op == O_constant)
+               extended |= ((op1.exp.X_add_number >> 16) & 0xf) << 7;
+
+             else if (op1.reg || (op1.reg == 0 && op1.am == 3))        /* Not PC relative.  */
+               fix_new_exp (frag_now, where, 6, &(op1.exp), FALSE,
+                            BFD_RELOC_MSP430X_ABS20_EXT_SRC);
+             else
+               fix_new_exp (frag_now, where, 6, &(op1.exp), FALSE,
+                            BFD_RELOC_MSP430X_PCR20_EXT_SRC);
+           }
+
+         /* Emit the extension word.  */
+         bfd_putl16 (extended, frag);
+         frag += 2;
+         where += 2;
+       }
+
+      bin |= op1.reg | (op1.am << 4);
       bfd_putl16 ((bfd_vma) bin, frag);
-      dwarf2_emit_insn (2 * __is);
+      frag += 2;
+      where += 2;
 
       if (op1.mode == OP_EXP)
        {
-         bfd_putl16 ((bfd_vma) ZEROS, frag + 2);
-
-         if (op1.reg || (op1.reg == 0 && op1.am == 3)) /* Not PC relative.  */
-           fix_new_exp (frag_now, where + 2, 2,
-                        &(op1.exp), FALSE, CHECK_RELOC_MSP430);
+         if (op1.exp.X_op == O_constant)
+           {
+             bfd_putl16 (op1.exp.X_add_number & 0xffff, frag);
+           }
          else
-           fix_new_exp (frag_now, where + 2, 2,
-                        &(op1.exp), TRUE, CHECK_RELOC_MSP430_PCREL);
+           {
+             bfd_putl16 ((bfd_vma) ZEROS, frag);
+
+             if (!extended_op)
+               {
+                 if (op1.reg || (op1.reg == 0 && op1.am == 3)) /* Not PC relative.  */
+                   fix_new_exp (frag_now, where, 2,
+                                &(op1.exp), FALSE, CHECK_RELOC_MSP430);
+                 else
+                   fix_new_exp (frag_now, where, 2,
+                                &(op1.exp), TRUE, CHECK_RELOC_MSP430_PCREL);
+               }
+           }
        }
+
+      dwarf2_emit_insn (insn_length);
       break;
 
     case 3:                    /* Conditional jumps instructions.  */
@@ -1634,7 +2824,6 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line)
            m++;
 
          parse_exp (m, &exp);
-         frag = frag_more (2); /* Instr size is 1 word.  */
 
          /* In order to handle something like:
 
@@ -1678,11 +2867,16 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line)
                  break;
                }
 
+             insn_length += 2;
+             frag = frag_more (2);     /* Instr size is 1 word.  */
+
              bin |= x & 0x3ff;
              bfd_putl16 ((bfd_vma) bin, frag);
            }
          else if (exp.X_op == O_symbol && *l1 != '$')
            {
+             insn_length += 2;
+             frag = frag_more (2);     /* Instr size is 1 word.  */
              where = frag - frag_now->fr_literal;
              fix_new_exp (frag_now, where, 2,
                           &exp, TRUE, BFD_RELOC_MSP430_10_PCREL);
@@ -1694,11 +2888,9 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line)
              as_bad (_("instruction requires label sans '$'"));
            }
          else
-           {
-             as_bad (_
-                     ("instruction requires label or value in range -511:512"));
-           }
-         dwarf2_emit_insn (2 * __is);
+           as_bad (_
+                   ("instruction requires label or value in range -511:512"));
+         dwarf2_emit_insn (insn_length);
          break;
        }
       else
@@ -1714,7 +2906,7 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line)
          as_bad (_("polymorphs are not enabled. Use -mP option to enable."));
          break;
        }
-       
+
       line = extract_operand (line, l1, sizeof (l1));
       if (l1[0])
        {
@@ -1731,15 +2923,20 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line)
              /* Relaxation required.  */
              struct rcodes_s rc = msp430_rcodes[opcode->insn_opnumb];
 
-             /* The parameter to dwarf2_emit_insn is actually the offset to the start
-                of the insn from the fix piece of instruction that was emitted.
-                Since next fragments may have variable size we tie debug info
-                to the beginning of the instruction. */
+             if (msp430_mcu->isa == MSP430X_ISA)
+               rc = msp430x_rcodes[opcode->insn_opnumb];
+
+             /* The parameter to dwarf2_emit_insn is actually the offset to
+                the start of the insn from the fix piece of instruction that
+                was emitted.  Since next fragments may have variable size we
+                tie debug info to the beginning of the instruction.  */
+             insn_length += 8;
              frag = frag_more (8);
              dwarf2_emit_insn (0);
              bfd_putl16 ((bfd_vma) rc.sop, frag);
              frag = frag_variant (rs_machine_dependent, 8, 2,
-                                  ENCODE_RELAX (rc.lpos, STATE_BITS10), /* Wild guess.  */
+                                   /* Wild guess.  */
+                                  ENCODE_RELAX (rc.lpos, STATE_BITS10),
                                   exp.X_add_symbol,
                                   0,   /* Offset is zero if jump dist less than 1K.  */
                                   (char *) frag);
@@ -1772,6 +2969,10 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line)
              /* Relaxation required.  */
              struct hcodes_s hc = msp430_hcodes[opcode->insn_opnumb];
 
+             if (msp430_mcu->isa == MSP430X_ISA)
+               hc = msp430x_hcodes[opcode->insn_opnumb];
+
+             insn_length += 8;
              frag = frag_more (8);
              dwarf2_emit_insn (0);
              bfd_putl16 ((bfd_vma) hc.op0, frag);
@@ -1866,16 +3067,22 @@ md_pcrel_from_section (fixS * fixp, segT sec)
 
 /* Replaces standard TC_FORCE_RELOCATION_LOCAL.
    Now it handles the situation when relocations
-   have to be passed to linker. */
+   have to be passed to linker.  */
 int
-msp430_force_relocation_local(fixS *fixp)
+msp430_force_relocation_local (fixS *fixp)
 {
+  if (fixp->fx_r_type == BFD_RELOC_MSP430_10_PCREL)
+    return 1;
+
+  if (fixp->fx_pcrel)
+    return 1;
+
   if (msp430_enable_polys
         && !msp430_enable_relax)
     return 1;
-  else
-    return (!fixp->fx_pcrel
-           || generic_force_reloc(fixp));
+
+  return (!fixp->fx_pcrel
+         || generic_force_reloc (fixp));
 }
 
 
@@ -1928,23 +3135,17 @@ md_apply_fix (fixS * fixp, valueT * valuep, segT seg)
              value -= S_GET_VALUE (fixp->fx_subsy);
              fixp->fx_done = 1;
            }
-         else
-           {
-             /* We don't actually support subtracting a symbol.  */
-             as_bad_where (fixp->fx_file, fixp->fx_line,
-                           _("expression too complex"));
-           }
        }
     }
 
   fixp->fx_no_overflow = 1;
 
-  /* if polymorphs are enabled and relax disabled. 
-     do not kill any relocs and pass them to linker. */
-  if (msp430_enable_polys 
+  /* If polymorphs are enabled and relax disabled.
+     do not kill any relocs and pass them to linker.  */
+  if (msp430_enable_polys
       && !msp430_enable_relax)
     {
-      if (!fixp->fx_addsy || (fixp->fx_addsy 
+      if (!fixp->fx_addsy || (fixp->fx_addsy
          && S_GET_SEGMENT (fixp->fx_addsy) == absolute_section))
        fixp->fx_done = 1;      /* It is ok to kill 'abs' reloc.  */
       else
@@ -1955,7 +3156,6 @@ md_apply_fix (fixS * fixp, valueT * valuep, segT seg)
     {
       /* Fetch the instruction, insert the fully resolved operand
         value, and stuff the instruction back again.  */
-
       where = (unsigned char *) fixp->fx_frag->fr_literal + fixp->fx_where;
 
       insn = bfd_getl16 (where);
@@ -1979,27 +3179,25 @@ md_apply_fix (fixS * fixp, valueT * valuep, segT seg)
          bfd_putl16 ((bfd_vma) (value | insn), where);
          break;
 
+       case BFD_RELOC_MSP430X_PCR16:
        case BFD_RELOC_MSP430_RL_PCREL:
        case BFD_RELOC_MSP430_16_PCREL:
          if (value & 1)
            as_bad_where (fixp->fx_file, fixp->fx_line,
                          _("odd address operand: %ld"), value);
-
-         /* Nothing to be corrected here.  */
-         if (value < -32768 || value > 65536)
-           as_bad_where (fixp->fx_file, fixp->fx_line,
-                         _("operand out of range: %ld"), value);
-
-         value &= 0xffff;      /* Get rid of extended sign.  */
-         bfd_putl16 ((bfd_vma) value, where);
-         break;
+         /* Fall through.  */
 
        case BFD_RELOC_MSP430_16_PCREL_BYTE:
          /* Nothing to be corrected here.  */
          if (value < -32768 || value > 65536)
            as_bad_where (fixp->fx_file, fixp->fx_line,
                          _("operand out of range: %ld"), value);
+         /* Fall through.  */
 
+       case BFD_RELOC_MSP430X_ABS16:
+       case BFD_RELOC_MSP430_16:
+       case BFD_RELOC_16:
+       case BFD_RELOC_MSP430_16_BYTE:
          value &= 0xffff;      /* Get rid of extended sign.  */
          bfd_putl16 ((bfd_vma) value, where);
          break;
@@ -2008,11 +3206,53 @@ md_apply_fix (fixS * fixp, valueT * valuep, segT seg)
          bfd_putl16 ((bfd_vma) value, where);
          break;
 
-       case BFD_RELOC_MSP430_16:
-       case BFD_RELOC_16:
-       case BFD_RELOC_MSP430_16_BYTE:
-         value &= 0xffff;
-         bfd_putl16 ((bfd_vma) value, where);
+       case BFD_RELOC_MSP430_ABS8:
+       case BFD_RELOC_8:
+         bfd_put_8 (NULL, (bfd_vma) value, where);
+         break;
+
+       case BFD_RELOC_MSP430X_ABS20_EXT_SRC:
+       case BFD_RELOC_MSP430X_PCR20_EXT_SRC:
+         bfd_putl16 ((bfd_vma) (value & 0xffff), where + 4);
+         value >>= 16;
+         bfd_putl16 ((bfd_vma) (((value & 0xf) << 7) | insn), where);
+         break;
+
+       case BFD_RELOC_MSP430X_ABS20_ADR_SRC:
+         bfd_putl16 ((bfd_vma) (value & 0xffff), where + 2);
+         value >>= 16;
+         bfd_putl16 ((bfd_vma) (((value & 0xf) << 8) | insn), where);
+         break;
+
+       case BFD_RELOC_MSP430X_ABS20_EXT_ODST:
+         bfd_putl16 ((bfd_vma) (value & 0xffff), where + 6);
+         value >>= 16;
+         bfd_putl16 ((bfd_vma) ((value & 0xf) | insn), where);
+         break;
+
+       case BFD_RELOC_MSP430X_PCR20_CALL:
+         bfd_putl16 ((bfd_vma) (value & 0xffff), where + 2);
+         value >>= 16;
+         bfd_putl16 ((bfd_vma) ((value & 0xf) | insn), where);
+         break;
+
+       case BFD_RELOC_MSP430X_ABS20_EXT_DST:
+       case BFD_RELOC_MSP430X_PCR20_EXT_DST:
+         bfd_putl16 ((bfd_vma) (value & 0xffff), where + 4);
+         value >>= 16;
+         bfd_putl16 ((bfd_vma) ((value & 0xf) | insn), where);
+         break;
+
+       case BFD_RELOC_MSP430X_PCR20_EXT_ODST:
+         bfd_putl16 ((bfd_vma) (value & 0xffff), where + 6);
+         value >>= 16;
+         bfd_putl16 ((bfd_vma) ((value & 0xf) | insn), where);
+         break;
+
+       case BFD_RELOC_MSP430X_ABS20_ADR_DST:
+         bfd_putl16 ((bfd_vma) (value & 0xffff), where + 2);
+         value >>= 16;
+         bfd_putl16 ((bfd_vma) ((value & 0xf) | insn), where);
          break;
 
        default:
@@ -2027,6 +3267,20 @@ md_apply_fix (fixS * fixp, valueT * valuep, segT seg)
     }
 }
 
+static bfd_boolean
+S_IS_GAS_LOCAL (symbolS * s)
+{
+  const char * name;
+  unsigned int len;
+
+  if (s == NULL)
+    return FALSE;
+  name = S_GET_NAME (s);
+  len = strlen (name) - 1;
+
+  return name[len] == 1 || name[len] == 2;
+}
+
 /* GAS will call this to generate a reloc, passing the resulting reloc
    to `bfd_install_relocation'.  This currently works poorly, as
    `bfd_install_relocation' often does the wrong thing, and instances of
@@ -2036,33 +3290,157 @@ md_apply_fix (fixS * fixp, valueT * valuep, segT seg)
 /* If while processing a fixup, a reloc really needs to be created
    then it is done here.  */
 
-arelent *
+arelent **
 tc_gen_reloc (asection * seg ATTRIBUTE_UNUSED, fixS * fixp)
 {
-  arelent * reloc;
+  static arelent * no_relocs = NULL;
+  static arelent * relocs[MAX_RELOC_EXPANSION + 1];
+  arelent *reloc;
 
   reloc = xmalloc (sizeof (arelent));
-
-  reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
-  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
-
   reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
   reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
+
   if (reloc->howto == (reloc_howto_type *) NULL)
     {
       as_bad_where (fixp->fx_file, fixp->fx_line,
                    _("reloc %d not supported by object file format"),
                    (int) fixp->fx_r_type);
-      return NULL;
+      free (reloc);
+      return & no_relocs;
+    }
+
+  relocs[0] = reloc;
+  relocs[1] = NULL;
+
+  if (fixp->fx_subsy
+      && S_GET_SEGMENT (fixp->fx_subsy) == absolute_section)
+    {
+      fixp->fx_offset -= S_GET_VALUE (fixp->fx_subsy);
+      fixp->fx_subsy = NULL;
     }
 
-  if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
-      || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
-    reloc->address = fixp->fx_offset;
+  if (fixp->fx_addsy && fixp->fx_subsy)
+    {
+      asection *asec, *ssec;
+
+      asec = S_GET_SEGMENT (fixp->fx_addsy);
+      ssec = S_GET_SEGMENT (fixp->fx_subsy);
+
+      /* If we have a difference between two different, non-absolute symbols
+        we must generate two relocs (one for each symbol) and allow the
+        linker to resolve them - relaxation may change the distances between
+        symbols, even local symbols defined in the same section.
+
+        Unfortunately we cannot do this with assembler generated local labels
+        because there can be multiple incarnations of the same label, with
+        exactly the same name, in any given section and the linker will have
+        no way to identify the correct one.  Instead we just have to hope
+        that no relaxtion will occur between the local label and the other
+        symbol in the expression.
+
+        Similarly we have to compute differences between symbols in the .eh_frame
+        section as the linker is not smart enough to apply relocations there
+        before attempting to process it.  */
+      if ((ssec != absolute_section || asec != absolute_section)
+         && (fixp->fx_addsy != fixp->fx_subsy)
+         && strcmp (ssec->name, ".eh_frame") != 0
+         && ! S_IS_GAS_LOCAL (fixp->fx_addsy)
+         && ! S_IS_GAS_LOCAL (fixp->fx_subsy))
+       {
+         arelent * reloc2 = xmalloc (sizeof * reloc);
 
-  reloc->addend = fixp->fx_offset;
+         relocs[0] = reloc2;
+         relocs[1] = reloc;
 
-  return reloc;
+         reloc2->address = reloc->address;
+         reloc2->howto = bfd_reloc_type_lookup (stdoutput,
+                                                BFD_RELOC_MSP430_SYM_DIFF);
+         reloc2->addend = - S_GET_VALUE (fixp->fx_subsy);
+
+         if (ssec == absolute_section)
+           reloc2->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
+         else
+           {
+             reloc2->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
+             *reloc2->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_subsy);
+           }
+
+         reloc->addend = fixp->fx_offset;
+         if (asec == absolute_section)
+           {
+             reloc->addend += S_GET_VALUE (fixp->fx_addsy);
+             reloc->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
+           }
+         else
+           {
+             reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
+             *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
+           }
+
+         fixp->fx_pcrel = 0;
+         fixp->fx_done = 1;
+         return relocs;
+       }
+      else
+       {
+         char *fixpos = fixp->fx_where + fixp->fx_frag->fr_literal;
+
+         reloc->addend = (S_GET_VALUE (fixp->fx_addsy)
+                          - S_GET_VALUE (fixp->fx_subsy) + fixp->fx_offset);
+
+         switch (fixp->fx_r_type)
+           {
+           case BFD_RELOC_8:
+             md_number_to_chars (fixpos, reloc->addend, 1);
+             break;
+
+           case BFD_RELOC_16:
+             md_number_to_chars (fixpos, reloc->addend, 2);
+             break;
+
+           case BFD_RELOC_24:
+             md_number_to_chars (fixpos, reloc->addend, 3);
+             break;
+
+           case BFD_RELOC_32:
+             md_number_to_chars (fixpos, reloc->addend, 4);
+             break;
+
+           default:
+             reloc->sym_ptr_ptr
+               = (asymbol **) bfd_abs_section_ptr->symbol_ptr_ptr;
+             return relocs;
+           }
+
+         free (reloc);
+         return & no_relocs;
+       }
+    }
+  else
+    {
+#if 0
+      if (fixp->fx_r_type == BFD_RELOC_MSP430X_ABS16
+         && S_GET_SEGMENT (fixp->fx_addsy) == absolute_section)
+       {
+         bfd_vma amount = S_GET_VALUE (fixp->fx_addsy);
+         char *fixpos = fixp->fx_where + fixp->fx_frag->fr_literal;
+
+         md_number_to_chars (fixpos, amount, 2);
+         free (reloc);
+         return & no_relocs;
+       }
+#endif
+      reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
+      *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
+      reloc->addend = fixp->fx_offset;
+
+      if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
+         || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+       reloc->address = fixp->fx_offset;
+    }
+
+  return relocs;
 }
 
 int
@@ -2122,6 +3500,8 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED,
     case ENCODE_RELAX (STATE_UNCOND_BRANCH, STATE_UNDEF):
       /* Convert uncond branch jmp lab -> br lab.  */
       cc = & msp430_rcodes[7];
+      if (msp430_mcu->isa == MSP430X_ISA)
+       cc = msp430x_rcodes + 7;
       where = fragP->fr_literal + fragP->fr_fix;
       bfd_putl16 (cc->lop0, where);
       rela = BFD_RELOC_MSP430_RL_PCREL;
@@ -2136,9 +3516,19 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED,
 
        insn &= 0xffff;
        /* Find actual instruction.  */
-       for (i = 0; i < 7 && !cc; i++)
-         if (msp430_rcodes[i].sop == insn)
-           cc = & msp430_rcodes[i];
+       if (msp430_mcu->isa == MSP430X_ISA)
+         {
+           for (i = 0; i < 7 && !cc; i++)
+             if (msp430x_rcodes[i].sop == insn)
+               cc = msp430x_rcodes + i;
+         }
+       else
+         {
+           for (i = 0; i < 7 && !cc; i++)
+             if (msp430_rcodes[i].sop == insn)
+               cc = & msp430_rcodes[i];
+         }
+
        if (!cc || !cc->name)
          as_fatal (_("internal inconsistency problem in %s: insn %04lx"),
                    __FUNCTION__, (long) insn);
@@ -2153,6 +3543,10 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED,
     case ENCODE_RELAX (STATE_NOOV_BRANCH, STATE_WORD):
     case ENCODE_RELAX (STATE_NOOV_BRANCH, STATE_UNDEF):
       cc = & msp430_rcodes[6];
+
+      if (msp430_mcu->isa == MSP430X_ISA)
+       cc = msp430x_rcodes + 6;
+
       where = fragP->fr_literal + fragP->fr_fix;
       bfd_putl16 (cc->lop0, where);
       bfd_putl16 (cc->lop1, where + 2);
@@ -2166,9 +3560,19 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED,
        int insn = bfd_getl16 (fragP->fr_opcode + 2);
 
        insn &= 0xffff;
-       for (i = 0; i < 4 && !hc; i++)
-         if (msp430_hcodes[i].op1 == insn)
-           hc = &msp430_hcodes[i];
+       if (msp430_mcu->isa == MSP430X_ISA)
+         {
+           for (i = 0; i < 4 && !hc; i++)
+             if (msp430x_hcodes[i].op1 == insn)
+               hc = msp430x_hcodes + i;
+         }
+       else
+         {
+           for (i = 0; i < 4 && !hc; i++)
+             if (msp430_hcodes[i].op1 == insn)
+               hc = &msp430_hcodes[i];
+         }
+
        if (!hc || !hc->name)
          as_fatal (_("internal inconsistency problem in %s: ext. insn %04lx"),
              __FUNCTION__, (long) insn);
@@ -2177,7 +3581,7 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED,
           another fix will be applied to the next word of insn anyway.  */
        if (hc->tlab == 2)
          fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol,
-             fragP->fr_offset, TRUE, rela);
+                  fragP->fr_offset, TRUE, rela);
        fragP->fr_fix += 2;
       }
 
@@ -2189,9 +3593,18 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED,
        int insn = bfd_getl16 (fragP->fr_opcode + 2);
 
        insn &= 0xffff;
-       for (i = 0; i < 4 && !hc; i++)
-         if (msp430_hcodes[i].op1 == insn)
-           hc = & msp430_hcodes[i];
+       if (msp430_mcu->isa == MSP430X_ISA)
+         {
+           for (i = 0; i < 4 && !hc; i++)
+             if (msp430x_hcodes[i].op1 == insn)
+               hc = msp430x_hcodes + i;
+         }
+       else
+         {
+           for (i = 0; i < 4 && !hc; i++)
+             if (msp430_hcodes[i].op1 == insn)
+               hc = & msp430_hcodes[i];
+         }
        if (!hc || !hc->name)
          as_fatal (_("internal inconsistency problem in %s: ext. insn %04lx"),
              __FUNCTION__, (long) insn);
@@ -2251,10 +3664,10 @@ msp430_relax_frag (segT seg ATTRIBUTE_UNUSED, fragS * fragP,
   if (!msp430_enable_relax)
     {
       /* Relaxation is not enabled. So, make all jump as long ones
-         by setting 'aim' to quite high value. */
+         by setting 'aim' to quite high value.  */
       aim = 0x7fff;
     }
-  
+
   this_state = fragP->fr_subtype;
   start_type = this_type = table + this_state;
 
@@ -2292,3 +3705,58 @@ msp430_relax_frag (segT seg ATTRIBUTE_UNUSED, fragS * fragP,
     fragP->fr_subtype = this_state;
   return growth;
 }
+
+/* Return FALSE if the fixup in fixp should be left alone and not
+   adjusted.   We return FALSE here so that linker relaxation will
+   work.  */
+
+bfd_boolean
+msp430_fix_adjustable (struct fix *fixp ATTRIBUTE_UNUSED)
+{
+  /* If the symbol is in a non-code section then it should be OK.  */
+  if (fixp->fx_addsy
+      && ((S_GET_SEGMENT (fixp->fx_addsy)->flags & SEC_CODE) == 0))
+    return TRUE;
+
+  return FALSE;
+}
+
+/* Set the contents of the .MSP430.attributes section.  */
+
+void
+msp430_md_end (void)
+{
+  bfd_elf_add_proc_attr_int (stdoutput, OFBA_MSPABI_Tag_ISA,
+                            msp430_mcu->isa == MSP430X_ISA ? 2 : 1);
+
+  bfd_elf_add_proc_attr_int (stdoutput, OFBA_MSPABI_Tag_Code_Model,
+                            large_model ? 2 : 1);
+
+  bfd_elf_add_proc_attr_int (stdoutput, OFBA_MSPABI_Tag_Data_Model,
+                            large_model ? 2 : 1);
+}
+
+/* Returns FALSE if there is a msp430 specific reason why the
+   subtraction of two same-section symbols cannot be computed by
+   the assembler.  */
+
+bfd_boolean
+msp430_allow_local_subtract (expressionS * left,
+                            expressionS * right,
+                            segT section)
+{
+  /* If the symbols are not in a code section then they are OK.  */
+  if ((section->flags & SEC_CODE) == 0)
+    return TRUE;
+
+  if (S_IS_GAS_LOCAL (left->X_add_symbol) || S_IS_GAS_LOCAL (right->X_add_symbol))
+    return TRUE;
+
+  if (left->X_add_symbol == right->X_add_symbol)
+    return TRUE;
+
+  /* We have to assume that there may be instructions between the
+     two symbols and that relaxation may increase the distance between
+     them.  */
+  return FALSE;
+}
index 118b46d3f9d1ed68d315474ba7074d0b94bd1907..f805f666df35866a3e09098e0b3a39ed8d841deb 100644 (file)
@@ -1,5 +1,5 @@
 /* This file is tc-msp430.h
-   Copyright (C) 2002, 2004, 2005, 2007 Free Software Foundation, Inc.
+   Copyright (C) 2002-2013 Free Software Foundation, Inc.
 
    Contributed by Dmitry Diky <diwil@mail.ru>
 
@@ -99,8 +99,9 @@ extern long md_pcrel_from_section (struct fix *, segT);
      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
-/* MSP430 port does not use `$' as a logical line separator */
+/* Support symbols like: C$$IO$$.  */
+#undef  LEX_DOLLAR
+#define LEX_DOLLAR 1
 
 #define TC_IMPLICIT_LCOMM_ALIGNMENT(SIZE, P2VAR) (P2VAR) = 0
 /*   An `.lcomm' directive with no explicit alignment parameter will
@@ -116,9 +117,52 @@ extern long md_pcrel_from_section (struct fix *, segT);
 extern long msp430_relax_frag (segT, fragS *, long);
 
 #define TC_FORCE_RELOCATION_LOCAL(FIX) \
-   msp430_force_relocation_local(FIX)
-extern int msp430_force_relocation_local(struct fix *);
-
+   msp430_force_relocation_local (FIX)
+extern int msp430_force_relocation_local (struct fix *);
 
 extern int msp430_enable_relax;
 extern int msp430_enable_polys;
+
+#define tc_fix_adjustable(FIX) msp430_fix_adjustable (FIX)
+extern bfd_boolean             msp430_fix_adjustable (struct fix *);
+
+/* Allow hexadeciaml numbers with 'h' suffix.  Note that if the number
+   starts with a letter it will be interpreted as a symbol name not a
+   constant.  Thus "beach" is a symbol not the hex value 0xbeac.  So
+   is A5A5h...  */
+#define NUMBERS_WITH_SUFFIX 1
+
+#define md_end msp430_md_end
+extern void    msp430_md_end (void);
+
+/* Do not allow call frame debug info optimization as otherwise we could
+   generate the DWARF directives without the relocs necessary to patch
+   them up.  */
+#define md_allow_eh_opt 0
+
+/* The difference between same-section symbols may be affected by linker
+   relaxation, so do not resolve such expressions in the assembler.  */
+#define md_allow_local_subtract(l,r,s) msp430_allow_local_subtract (l, r, s)
+extern bfd_boolean msp430_allow_local_subtract (expressionS *, expressionS *, segT);
+
+#define RELOC_EXPANSION_POSSIBLE
+#define MAX_RELOC_EXPANSION 2
+
+#define DIFF_EXPR_OK
+
+/* Do not adjust relocations involving symbols in code sections,
+   because it breaks linker relaxations.  This could be fixed in the
+   linker, but this fix is simpler, and it pretty much only affects
+   object size a little bit.  */
+#define TC_FORCE_RELOCATION_SUB_SAME(FIX, SEC) \
+  (((SEC)->flags & SEC_CODE) != 0              \
+   || ! SEG_NORMAL (SEC)                       \
+   || TC_FORCE_RELOCATION (FIX))
+
+/* We validate subtract arguments within tc_gen_reloc(),
+   so don't report errors at this point.  */
+#define TC_VALIDATE_FIX_SUB(FIX, SEG) 1
+
+#define DWARF2_USE_FIXED_ADVANCE_PC 1
+
+#define TC_LINKRELAX_FIXUP(seg) (seg->flags & SEC_CODE)
index 4beb90a0bf1ff39f073ee32ab306fa8c88211fc0..06e4137cd4f215b71806b96c1035507cc43947c5 100644 (file)
@@ -1,4 +1,4 @@
-@c Copyright 2002, 2004, 2005, 2011 Free Software Foundation, Inc.
+@c Copyright 2002-2013 Free Software Foundation, Inc.
 @c This is part of the GAS manual.
 @c For copying conditions, see the file as.texinfo.
 @ifset GENERIC
@@ -36,6 +36,20 @@ enables polymorph instructions handler.
 @item -mQ
 enables relaxation at assembly time. DANGEROUS!
 
+@item -ml
+indicates that the input uses the large code model.
+
+@item -mN
+disables the generation of a NOP instruction following any instruction
+that might change the interrupts enabled/disabled state.  For the
+MSP430x5xx series the instructions: @code{EINT}, @code{DINT}, @code{BIC
+#8, SR}, @code{BIS #8, SR} and @code{MOV.W <>, SR} must be followed by
+a NOP instruction in order to ensure the correct processing of
+interrupts.  By default generation of the NOP instruction happens
+automatically, but this command line option disables this behaviour.
+It is then up to the programmer to ensure that interrupts are enabled
+and disabled correctly.
+
 @end table
 
 @node MSP430 Syntax
index ea5d8d3a8eec4685d50876be92b45bd34ec76b47..bd015c69952c27b74feec444c49d02ac2d1f1866 100644 (file)
@@ -1,3 +1,22 @@
+2013-05-02  Nick Clifton  <nickc@redhat.com>
+
+       * gas/all/gas.exp: Skip the DIFF1 test for the MSP430.
+       Expect the FORWARD test to pass for the MSP430.
+       Skip the REDEF tests for the MSP430.
+       Expect the 930509A test to fail for the MSP430.
+       * gas/all/sleb128-4.d: Skip for the MSP430.
+       * gas/elf/elf.exp: Set target_machine to msp430 for the MSP430.
+       Skip the EHOPT0 test for the MSP430.
+       Skip the REDEF and EQU-RELOC tests for the MSP430.
+       * gas/elf/section2.e-msp430: New file.
+       * gas/lns/lns-big-delta.d: Remove expectation of 20-bit
+       addresses.
+       * gas/lns/lns.exp: Use alternate LNS COMMON test for the MSP430.
+       * gas/msp430/msp430x.s: New test.
+       * gas/msp430/msp430x.d: Expected disassembly.
+       * gas/msp430/msp430.exp: Run new test.
+       * gas/msp430/opcode.d: Update expected disassembly.
+
 2013-04-30  Chao-ying Fu  <Chao-ying.Fu@imgtec.com>
 
        * gas/mips/ext-ill.s: New file.
index 709b448701e470431aba12ae9efdd5510aa92af7..f604ac9430cbb57086c32006f98ccd1f6035db99 100644 (file)
@@ -61,6 +61,7 @@ if { ![istarget hppa*-*-*]
      && ![istarget alpha*-*-*vms*]
      && ![istarget rx-*-*]
      && ![istarget mn10300-*-*]
+     && ![istarget msp430*-*-*]
      && ![istarget am3*-*-*] } then {
     gas_test_error "diff1.s" "" "difference of two undefined symbols"
 }
@@ -99,7 +100,7 @@ case $target_triplet in {
     default {
        # Some targets don't manage to resolve BFD_RELOC_8 for constants.
        setup_xfail "alpha*-*-*" "*c30*-*-*" "*c4x*-*-*" \
-           "d\[13\]0v*-*-*" "i860-*-*" "mips*-*-*" "msp430-*-*" \
+           "d\[13\]0v*-*-*" "i860-*-*" "mips*-*-*" \
            "pdp11-*-*" "xtensa*-*-*"
        run_dump_test forward
     }
@@ -139,6 +140,7 @@ case $target_triplet in {
     { mips*-*-* } { }
     { mn10200-*-* } { }
     { mn10300-*-* } { }
+    { msp430*-*-* } { }
     { pdp11-*-* } { }
     { tic30*-*-* } { }
     { tic4x*-*-* } { }
@@ -266,8 +268,8 @@ if { ![istarget hppa*-*-*] &&
      ![istarget *c54x*-*-*] } then {
     # the vax fails because VMS can apparently actually handle this
     # case in relocs, so gas doesn't handle it itself.
-    # mn10300 emits two relocs to handle the difference of two symbols.
-    setup_xfail "mn10300*-*-*" "vax*-*-vms*"
+    # msp430 and mn10300 emit two relocs to handle the difference of two symbols.
+    setup_xfail "mn10300*-*-*" "msp430*-*-*" "vax*-*-vms*"
     do_930509a
 }
 
index 0c56696d8e11e06285fea7ae1a6c3eee7a6cb89b..89b95653018640fb01545549765d5c81af49f179 100644 (file)
@@ -1,5 +1,6 @@
 #objdump : -s -j .data -j "\$DATA\$"
 #name : .sleb128 tests (4)
+#skip: msp430*-*-*
 
 .*: .*
 
index 9ffd257334dcd53d9c57f93f7b7912cdfad3e82a..4196fd7da1b0c852520b04ec206560b09ec2636e 100644 (file)
@@ -1,5 +1,4 @@
-# Copyright 2012
-# Free Software Foundation, Inc.
+# Copyright 2012-2013 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
@@ -62,6 +61,9 @@ if { [is_elf_format] } then {
     if {[istarget m32r*-*-*]} then {
        set target_machine -m32r
     }
+    if {[istarget "msp430-*-*"]} then {
+       set target_machine -msp430
+    }
     if {[istarget "score-*-*"]} then {
        set target_machine -score
     }
@@ -91,6 +93,7 @@ if { [is_elf_format] } then {
     # function prologues.
     if {![istarget "mn10300-*-*"]
        && ![istarget "xtensa*-*-*"]
+       && ![istarget "msp430*-*-*"]
        && ![istarget "am3*-*-*"]} then {
       run_dump_test "ehopt0"
     }
@@ -136,6 +139,7 @@ if { [is_elf_format] } then {
        { mips*-*-* } { }
        { mn10200-*-* } { }
        { mn10300-*-* } { }
+       { msp43*-*-* } { }
        { *c54x*-*-* } { }
        { rx-*-* } { }
        default {
index b6a113e811aa19ab3778510deaa1c7fc4758cef6..f4bdcf43b33e2cafa043c0ebf9a43a5bd1f3bdc5 100644 (file)
@@ -10,8 +10,8 @@ Raw dump of debug contents of section \.debug_line:
   Advance PC by fixed size amount 0 to 0x0
   Copy
   Advance Line by 1 to 3
-  Extended opcode 2: set Address to 0x.....
+  Extended opcode 2: set Address to 0x.*
   Copy
-  Advance PC by fixed size amount . to 0x.....
+  Advance PC by fixed size amount . to 0x.*
   Extended opcode 1: End of Sequence
 #pass
index 0febe0be7c56074148452066206b9d60a0faefb0..f1d7f98b1ed8f518d1253b6ac8aed51a215f0ef2 100644 (file)
@@ -38,6 +38,7 @@ if {
         || [istarget am3*-*-*]
         || [istarget cr16-*-*]
         || [istarget crx-*-*]
+        || [istarget msp430-*-*]
         || [istarget mn10*-*-*] } {
       run_dump_test "lns-common-1-alt"
       run_dump_test "lns-big-delta"
index 27df90098903310d4fb030f0668068eafbf565b8..656ace82670f7bde573b2e906bbaf9bad4e6b9dd 100644 (file)
@@ -1,5 +1,4 @@
-# Copyright 2012
-# Free Software Foundation, Inc.
+# Copyright 2012-2013 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
@@ -21,4 +20,5 @@
 
 if [expr [istarget "msp430-*-*"]]  then {
     run_dump_test "opcode"
+    run_dump_test "msp430x"
 }
index 22df51c52d9c50081ef9c7bbf4c26208fb771ee2..9212d89e69d1d510c43617f0f51fecfa3abb4530 100644 (file)
@@ -22,14 +22,14 @@ Disassembly of section .text:
 0+024 <[^>]*> 8c 10            swpb    r12             ;
 0+026 <[^>]*> 0d 10            rrc     r13             ;
 0+028 <[^>]*> 30 41            ret                     
-0+02a <[^>]*> 31 40 00 00      mov     #0,     r1      ;#0x0000
-0+02e <[^>]*> b0 12 00 00      call    #0              ;#0x0000
+0+02a <[^>]*> 31 40 00 00      mov     #0,     r1      ;
+0+02e <[^>]*> b0 12 00 00      call    #0              ;
 0+032 <[^>]*> 1e 42 00 00      mov     &0x0000,r14     ;0x0000
 0+036 <[^>]*> 0f 4e            mov     r14,    r15     ;
 0+038 <[^>]*> 0f 5f            rla     r15             ;
 0+03a <[^>]*> 0f 7f            subc    r15,    r15     ;
 0+03c <[^>]*> 3f e3            inv     r15             ;
-0+03e <[^>]*> b0 12 00 00      call    #0              ;#0x0000
+0+03e <[^>]*> b0 12 00 00      call    #0              ;
 0+042 <[^>]*> 82 4e 00 00      mov     r14,    &0x0000 ;
 0+046 <[^>]*> 82 4f 00 00      mov     r15,    &0x0000 ;
 0+04a <[^>]*> 1e 42 00 00      mov     &0x0000,r14     ;0x0000
@@ -37,7 +37,7 @@ Disassembly of section .text:
 0+050 <[^>]*> 0f 5f            rla     r15             ;
 0+052 <[^>]*> 0f 7f            subc    r15,    r15     ;
 0+054 <[^>]*> 3f e3            inv     r15             ;
-0+056 <[^>]*> b0 12 00 00      call    #0              ;#0x0000
+0+056 <[^>]*> b0 12 00 00      call    #0              ;
 0+05a <[^>]*> 82 4e 00 00      mov     r14,    &0x0000 ;
 0+05e <[^>]*> 82 4f 00 00      mov     r15,    &0x0000 ;
 0+062 <[^>]*> 3f 40 f0 00      mov     #240,   r15     ;#0x00f0
index c726592077030206b0c9e4d642fccc0e94313ac9..1eb581b5b6b2922d087217230bbfdcc6fe3fdd5c 100644 (file)
@@ -1,3 +1,9 @@
+2013-05-02  Nick Clifton  <nickc@redhat.com>
+
+       * msp430.h: Add MSP430X relocs.
+       Add some more MSP430 machine numbers.
+       Add values used by .MSP430.attributes section.
+
 2013-03-21  Michael Schewe  <michael.schewe@gmx.net>
 
        * h8.h: Add new reloc R_H8_DISP32A16 for relaxation of
index 44f5c51a70431bf868937b56ea455bea7ef8da79..ac8e28c31e7920ceda898b79ac4a3e3d73eb4ece 100644 (file)
@@ -1,5 +1,5 @@
 /* MSP430 ELF support for BFD.
-   Copyright (C) 2002, 2003, 2004, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2002-2013 Free Software Foundation, Inc.
    Contributed by Dmitry Diky <diwil@mail.ru>
 
    This file is part of BFD, the Binary File Descriptor library.
 #define E_MSP430_MACH_MSP430x14  14
 #define E_MSP430_MACH_MSP430x15  15
 #define E_MSP430_MACH_MSP430x16  16
+#define E_MSP430_MACH_MSP430x20  20
+#define E_MSP430_MACH_MSP430x22  22
+#define E_MSP430_MACH_MSP430x23  23
+#define E_MSP430_MACH_MSP430x24  24
+#define E_MSP430_MACH_MSP430x26  26
 #define E_MSP430_MACH_MSP430x31  31
 #define E_MSP430_MACH_MSP430x32  32
 #define E_MSP430_MACH_MSP430x33  33
 #define E_MSP430_MACH_MSP430x42  42
 #define E_MSP430_MACH_MSP430x43  43
 #define E_MSP430_MACH_MSP430x44  44
+#define E_MSP430_MACH_MSP430X    45
+#define E_MSP430_MACH_MSP430x46  46
+#define E_MSP430_MACH_MSP430x47  47
+#define E_MSP430_MACH_MSP430x54  54
+
+#define SHT_MSP430_ATTRIBUTES  0x70000003      /* Section holds ABI attributes.  */
+#define SHT_MSP430_SEC_FLAGS   0x7f000005      /* Holds TI compiler's section flags.  */
+#define SHT_MSP430_SYM_ALIASES 0x7f000006      /* Holds TI compiler's symbol aliases.  */
+
+/* Tag values for an attribute section.  */
+#define OFBA_MSPABI_Tag_ISA            4
+#define OFBA_MSPABI_Tag_Code_Model     6
+#define OFBA_MSPABI_Tag_Data_Model     8
 
 /* Relocations.  */
 START_RELOC_NUMBERS (elf_msp430_reloc_type)
@@ -52,7 +70,32 @@ START_RELOC_NUMBERS (elf_msp430_reloc_type)
      RELOC_NUMBER (R_MSP430_16_PCREL_BYTE,     6)
      RELOC_NUMBER (R_MSP430_2X_PCREL,          7)
      RELOC_NUMBER (R_MSP430_RL_PCREL,          8)
-
+     RELOC_NUMBER (R_MSP430_8,                 9)
+     RELOC_NUMBER (R_MSP430_SYM_DIFF,          10)
 END_RELOC_NUMBERS (R_MSP430_max)
 
+START_RELOC_NUMBERS (elf_msp430x_reloc_type)
+     RELOC_NUMBER (R_MSP430_ABS32, 1)          /* aka R_MSP430_32 */
+     RELOC_NUMBER (R_MSP430_ABS16, 2)          /* aka R_MSP430_16 */
+     RELOC_NUMBER (R_MSP430_ABS8, 3)
+     RELOC_NUMBER (R_MSP430_PCR16, 4)          /* aka R_MSP430_16_PCREL */
+     RELOC_NUMBER (R_MSP430X_PCR20_EXT_SRC, 5)
+     RELOC_NUMBER (R_MSP430X_PCR20_EXT_DST, 6)
+     RELOC_NUMBER (R_MSP430X_PCR20_EXT_ODST, 7)
+     RELOC_NUMBER (R_MSP430X_ABS20_EXT_SRC, 8)
+     RELOC_NUMBER (R_MSP430X_ABS20_EXT_DST, 9)
+     RELOC_NUMBER (R_MSP430X_ABS20_EXT_ODST, 10)
+     RELOC_NUMBER (R_MSP430X_ABS20_ADR_SRC, 11)
+     RELOC_NUMBER (R_MSP430X_ABS20_ADR_DST, 12)
+     RELOC_NUMBER (R_MSP430X_PCR16, 13)                /* Like R_MSP430_PCR16 but with overflow checking.  */
+     RELOC_NUMBER (R_MSP430X_PCR20_CALL, 14)
+     RELOC_NUMBER (R_MSP430X_ABS16, 15)                /* Like R_MSP430_ABS16 but with overflow checking.  */
+     RELOC_NUMBER (R_MSP430_ABS_HI16, 16)
+     RELOC_NUMBER (R_MSP430_PREL31, 17)
+     RELOC_NUMBER (R_MSP430_EHTYPE, 18)                /* Mentioned in ABI.  */
+     RELOC_NUMBER (R_MSP430X_10_PCREL, 19)     /* Red Hat invention.  Used for Jump instructions.  */
+     RELOC_NUMBER (R_MSP430X_2X_PCREL, 20)     /* Red Hat invention.  Used for relaxing jumps.  */
+     RELOC_NUMBER (R_MSP430X_SYM_DIFF, 21)     /* Red Hat invention.  Used for relaxing debug info.  */
+END_RELOC_NUMBERS (R_MSP430x_max)
+
 #endif /* _ELF_MSP430_H */
index 9eed10498717d348cb43fdbd6c3d1ef9db8dee8a..2b76a3643ae80ac539d261268c23b7ae21910ad7 100644 (file)
@@ -1,3 +1,7 @@
+2013-05-02  Nick Clifton  <nickc@redhat.com>
+
+       * msp430.h: Add patterns for MSP430X instructions.
+
 2013-04-06  David S. Miller  <davem@davemloft.net>
 
        * sparc.h (F_PREFERRED): Define.
index d3bf130ee098916fb905b71cd1377533cb380a4c..caddc42db1cb6cc00b4bfb78e8e1dab2b95c8168 100644 (file)
@@ -1,6 +1,6 @@
 /* Opcode table for the TI MSP430 microcontrollers
 
-   Copyright 2002, 2004, 2010 Free Software Foundation, Inc.
+   Copyright 2002-2013 Free Software Foundation, Inc.
    Contributed by Dmitry Diky <diwil@mail.ru>
    
    This program is free software; you can redistribute it and/or modify
@@ -119,6 +119,74 @@ static struct msp430_opcode_s msp430_opcodes[] =
   MSP_INSN (bleu,  5, 2, 0, 0xffff),
   MSP_INSN (ble,   5, 3, 0, 0xffff),
 
+  /* MSP430X instructions - these ones use an extension word.
+     A negative format indicates an MSP430X instruction.  */
+  MSP_INSN (addcx, -2, 2, 0x6000, 0xf000),
+  MSP_INSN (addx,  -2, 2, 0x5000, 0xf000),
+  MSP_INSN (andx,  -2, 2, 0xf000, 0xf000),
+  MSP_INSN (bicx,  -2, 2, 0xc000, 0xf000),
+  MSP_INSN (bisx,  -2, 2, 0xd000, 0xf000),
+  MSP_INSN (bitx,  -2, 2, 0xb000, 0xf000),
+  MSP_INSN (cmpx,  -2, 2, 0x9000, 0xf000),
+  MSP_INSN (daddx, -2, 2, 0xa000, 0xf000),
+  MSP_INSN (movx,  -2, 2, 0x4000, 0xf000),
+  MSP_INSN (subcx, -2, 2, 0x7000, 0xf000),
+  MSP_INSN (subx,  -2, 2, 0x8000, 0xf000),
+  MSP_INSN (xorx,  -2, 2, 0xe000, 0xf000),
+
+  /* MSP430X Synthetic instructions.  */
+  MSP_INSN (adcx,  -1, 1, 0x6300, 0xff30),
+  MSP_INSN (clra,  -1, 1, 0x4300, 0xff30),
+  MSP_INSN (clrx,  -1, 1, 0x4300, 0xff30),
+  MSP_INSN (dadcx, -1, 1, 0xa300, 0xff30),
+  MSP_INSN (decx,  -1, 1, 0x8310, 0xff30),  
+  MSP_INSN (decda, -1, 1, 0x8320, 0xff30),
+  MSP_INSN (decdx, -1, 1, 0x8320, 0xff30),
+  MSP_INSN (incx,  -1, 1, 0x5310, 0xff30),  
+  MSP_INSN (incda, -1, 1, 0x5320, 0xff30),
+  MSP_INSN (incdx, -1, 1, 0x5320, 0xff30),
+  MSP_INSN (invx,  -1, 1, 0xe330, 0xfff0),
+  MSP_INSN (popx,  -1, 1, 0x4130, 0xff30),
+  MSP_INSN (rlax,  -1, 2, 0x5000, 0xf000),  
+  MSP_INSN (rlcx,  -1, 2, 0x6000, 0xf000),
+  MSP_INSN (sbcx,  -1, 1, 0x7300, 0xff30),
+  MSP_INSN (tsta,  -1, 1, 0x9300, 0xff30),
+  MSP_INSN (tstx,  -1, 1, 0x9300, 0xff30),
+
+  MSP_INSN (pushx, -3, 1, 0x1200, 0xff80),
+  MSP_INSN (rrax,  -3, 1, 0x1100, 0xff80),
+  MSP_INSN (rrcx,  -3, 1, 0x1000, 0xff80),
+  MSP_INSN (swpbx, -3, 1, 0x1080, 0xffc0),
+  MSP_INSN (sxtx,  -3, 1, 0x1180, 0xffc0),
+
+  /* MSP430X Address instructions - no extension word needed.
+     The insn_opnumb field is used to encode the nature of the
+     instruction for assembly and disassembly purposes.  */
+  MSP_INSN (calla, -1, 4, 0x1300, 0xff00),
+
+  MSP_INSN (popm,  -1, 5, 0x1600, 0xfe00),
+  MSP_INSN (pushm, -1, 5, 0x1400, 0xfe00),
+
+  MSP_INSN (rrcm,  -1, 6, 0x0040, 0xf3e0),
+  MSP_INSN (rram,  -1, 6, 0x0140, 0xf3e0),
+  MSP_INSN (rlam,  -1, 6, 0x0240, 0xf3e0),
+  MSP_INSN (rrum,  -1, 6, 0x0340, 0xf3e0),
+
+  MSP_INSN (rrux,  -1, 7, 0x0340, 0xffe0), /* Synthesized in terms of RRUM.  */
+
+  MSP_INSN (adda,  -1, 8, 0x00a0, 0xf0b0),
+  MSP_INSN (cmpa,  -1, 8, 0x0090, 0xf0b0),
+  MSP_INSN (suba,  -1, 8, 0x00b0, 0xf0b0),
+
+  MSP_INSN (reta,  -1, 9, 0x0110, 0xffff),
+  MSP_INSN (bra,   -1, 9, 0x0000, 0xf0cf),
+  MSP_INSN (mova,  -1, 9, 0x0000, 0xf080),
+  MSP_INSN (mova,  -1, 9, 0x0080, 0xf0b0),
+  MSP_INSN (mova,  -1, 9, 0x00c0, 0xf0f0),
+
+  /* Pseudo instruction to set the repeat field in the extension word.  */
+  MSP_INSN (rpt,   -1, 10, 0x0000, 0x0000),
+
   /* End of instruction set.  */
   { NULL, 0, 0, 0, 0 }
 };
index 62dd0257ddd998331d98033a382c08d695e8c2de..5bb24f966d45e1051b7e18d2fe50ba8fcf44b09f 100644 (file)
@@ -1,3 +1,19 @@
+2013-05-02  Nick Clifton  <nickc@redhat.com>
+
+       * Makefile.am: Add emsp430X.c
+       * Makefine.in: Regenerate.
+       * configure.tgt (msp430): Add msp430X emulation.
+       * ldmain.c (multiple_definition): Only disable relaxation if it
+       was enabled by the user.
+       * ldmain.h (RELAXATION_ENABLED_BY_USER): New macro.
+       * emulparams/msp430all.sh: Add support for MSP430X.
+       * emultempl/generic.em: (before_parse): Enable relaxation for the
+       MSP430.
+       * scripttempl/msp430.sc: Reorganize sections.  Add .rodata
+       section.
+       * scripttempl/msp430_3.sc: Likewise.
+       * NEWS: Mention support for MSP430X.
+
 2013-05-01  Maciej W. Rozycki  <macro@codesourcery.com>
 
        * configure.tgt: Replace alpha*-*-linuxecoff* pattern with
index e0366f366581caa8e3e1f1f96b6600a999fd5327..0eba8a9d3ee5c2765c51f2f7a43e163d13f42443 100644 (file)
@@ -424,6 +424,7 @@ ALL_EMULATION_SOURCES = \
        emsp430xW423.c \
        emsp430xW425.c \
        emsp430xW427.c \
+       emsp430X.c \
        enews.c \
        ens32knbsd.c \
        eor32.c \
@@ -1773,6 +1774,10 @@ emsp430xW427.c: $(srcdir)/emulparams/msp430all.sh \
   $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \
   ${GEN_DEPENDS}
        ${GENSCRIPTS} msp430xW427 "$(tdir_msp430xW427)" msp430all
+emsp430X.c: $(srcdir)/emulparams/msp430all.sh \
+  $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \
+  ${GEN_DEPENDS}
+       ${GENSCRIPTS} msp430X "$(tdir_msp430X)" msp430all
 enews.c: $(srcdir)/emulparams/news.sh \
   $(srcdir)/emultempl/generic.em $(srcdir)/scripttempl/aout.sc ${GEN_DEPENDS}
        ${GENSCRIPTS} news "$(tdir_news)"
index 042e9f23a2aa276cd8aa8a56ba0801eea20b3d30..9140c73500234c72953f7cf34d55b511211e77d5 100644 (file)
@@ -732,6 +732,7 @@ ALL_EMULATION_SOURCES = \
        emsp430xW423.c \
        emsp430xW425.c \
        emsp430xW427.c \
+       emsp430X.c \
        enews.c \
        ens32knbsd.c \
        eor32.c \
@@ -1343,6 +1344,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emmo.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emn10200.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emn10300.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430X.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x110.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x1101.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x1111.Po@am__quote@
@@ -3259,6 +3261,10 @@ emsp430xW427.c: $(srcdir)/emulparams/msp430all.sh \
   $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \
   ${GEN_DEPENDS}
        ${GENSCRIPTS} msp430xW427 "$(tdir_msp430xW427)" msp430all
+emsp430X.c: $(srcdir)/emulparams/msp430all.sh \
+  $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \
+  ${GEN_DEPENDS}
+       ${GENSCRIPTS} msp430X "$(tdir_msp430X)" msp430all
 enews.c: $(srcdir)/emulparams/news.sh \
   $(srcdir)/emultempl/generic.em $(srcdir)/scripttempl/aout.sc ${GEN_DEPENDS}
        ${GENSCRIPTS} news "$(tdir_news)"
diff --git a/ld/NEWS b/ld/NEWS
index 5217e4c7c27bfad12f0ccc546c8ab054169636b1..fa11d2d9f22127972c2a53dbc40961d7e2d80abc 100644 (file)
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -1,5 +1,7 @@
 -*- text -*-
 
+* Add support for the Texas Instruments MSP430X processor.
+
 * Add support for Altera Nios II.
 
 * Add support for the V850E3V5 architecture.
index 8d7aec431c8694434b2abb74a3bd6fe6b4775d73..56945808c988d7e7a68ceae5677d132965b989cd 100644 (file)
@@ -519,7 +519,7 @@ mn10300-*-*)                targ_emul=mn10300
 mt-*elf)                targ_emul=elf32mt
                        ;;
 msp430-*-*)             targ_emul=msp430x110
-                        targ_extra_emuls="msp430x112 msp430x1101 msp430x1111 msp430x1121 msp430x1122 msp430x1132 msp430x122 msp430x123 msp430x1222 msp430x1232 msp430x133 msp430x135 msp430x1331 msp430x1351 msp430x147 msp430x148 msp430x149 msp430x155 msp430x156 msp430x157 msp430x167 msp430x168 msp430x169 msp430x1610 msp430x1611 msp430x1612 msp430x2101 msp430x2111 msp430x2121 msp430x2131 msp430x311 msp430x312 msp430x313 msp430x314 msp430x315 msp430x323 msp430x325 msp430x336 msp430x337 msp430x412 msp430x413 msp430x415 msp430x417 msp430xE423 msp430xE425 msp430xE427 msp430xW423 msp430xW425 msp430xW427 msp430xG437 msp430xG438 msp430xG439 msp430x435 msp430x436 msp430x437 msp430x447 msp430x448 msp430x449"
+                        targ_extra_emuls="msp430x112 msp430x1101 msp430x1111 msp430x1121 msp430x1122 msp430x1132 msp430x122 msp430x123 msp430x1222 msp430x1232 msp430x133 msp430x135 msp430x1331 msp430x1351 msp430x147 msp430x148 msp430x149 msp430x155 msp430x156 msp430x157 msp430x167 msp430x168 msp430x169 msp430x1610 msp430x1611 msp430x1612 msp430x2101 msp430x2111 msp430x2121 msp430x2131 msp430x311 msp430x312 msp430x313 msp430x314 msp430x315 msp430x323 msp430x325 msp430x336 msp430x337 msp430x412 msp430x413 msp430x415 msp430x417 msp430xE423 msp430xE425 msp430xE427 msp430xW423 msp430xW425 msp430xW427 msp430xG437 msp430xG438 msp430xG439 msp430x435 msp430x436 msp430x437 msp430x447 msp430x448 msp430x449 msp430X"
                        ;;
 nios2*-*-*)            targ_emul=nios2elf ;;
 ns32k-pc532-mach* | ns32k-pc532-ux*)  targ_emul=pc532macha ;;
index 57d21c2d409c326ecb62eeb3a0206c49b84e0ec8..3a2f79dc3a2e6403d13b7002105c778fc95790d6 100644 (file)
@@ -551,3 +551,12 @@ RAM_START=0x0200
 RAM_SIZE=0x400
 STACK=0x600
 fi
+
+if [ "${MSP430_NAME}" = "msp430X" ] ; then
+ARCH=msp:43
+ROM_START=0x02000
+ROM_SIZE=0x0dfe0
+RAM_START=0x10000
+RAM_SIZE=0x30000
+STACK=0x600
+fi
index 20ec35613ab640fc0e067d2cf7f5243fe06b3d8d..dce2bffd1e8714678e0b795a014d9734915875cd 100644 (file)
@@ -57,6 +57,18 @@ gld${EMULATION_NAME}_before_parse (void)
 #ifndef TARGET_                        /* I.e., if not generic.  */
   ldfile_set_output_arch ("`echo ${ARCH}`", bfd_arch_unknown);
 #endif /* not TARGET_ */
+EOF
+  # The MSP430 port *needs* linker relaxtion in order to cope with large
+  # functions where conditional branches do not fit into a +/- 1024 byte range.
+  case ${target} in
+    msp430-*-* )
+fragment <<EOF
+  if (! link_info.relocatable)
+    TARGET_ENABLE_RELAXATION;
+EOF
+    ;;
+  esac
+fragment <<EOF
 }
 
 EOF
index c23c55444e4a7edc198da151dc1e9f990ef43db5..20d892010f416ab4a94f6a84235192335f03f2bd 100644 (file)
@@ -1,7 +1,5 @@
 /* Main program of GNU linker.
-   Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
-   2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
-   Free Software Foundation, Inc.
+   Copyright 1991-2013 Free Software Foundation, Inc.
    Written by Steve Chamberlain steve@cygnus.com
 
    This file is part of the GNU Binutils.
@@ -953,10 +951,10 @@ multiple_definition (struct bfd_link_info *info,
   if (obfd != NULL)
     einfo (_("%D: first defined here\n"), obfd, osec, oval);
 
-  if (RELAXATION_ENABLED)
+  if (RELAXATION_ENABLED_BY_USER)
     {
       einfo (_("%P: Disabling relaxation: it will not work with multiple definitions\n"));
-      link_info.disable_target_specific_optimizations = -1;
+      DISABLE_RELAXATION;
     }
 
   return TRUE;
index 69928f820793a1fdf81d3b8e65a1a2f84e2ee712..90558a1ff17e0518e628db518a0766ef3d4ecdfc 100644 (file)
@@ -1,6 +1,5 @@
 /* ldmain.h -
-   Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1999, 2002, 2003, 2004,
-   2005, 2007, 2008, 2009, 2012 Free Software Foundation, Inc.
+   Copyright 1991-2013 Free Software Foundation, Inc.
 
    This file is part of the GNU Binutils.
 
@@ -42,11 +41,16 @@ extern int overflow_cutoff_limit;
 #define RELAXATION_DISABLED_BY_DEFAULT \
   (link_info.disable_target_specific_optimizations < 0)
 #define RELAXATION_DISABLED_BY_USER    \
-  (link_info.disable_target_specific_optimizations > 0)
+  (link_info.disable_target_specific_optimizations > 1)
 #define RELAXATION_ENABLED             \
+  (link_info.disable_target_specific_optimizations == 0 \
+   || link_info.disable_target_specific_optimizations == 1)
+#define RELAXATION_ENABLED_BY_USER             \
   (link_info.disable_target_specific_optimizations == 0)
-#define DISABLE_RELAXATION             \
+#define TARGET_ENABLE_RELAXATION               \
   do { link_info.disable_target_specific_optimizations = 1; } while (0)
+#define DISABLE_RELAXATION             \
+  do { link_info.disable_target_specific_optimizations = 2; } while (0)
 #define ENABLE_RELAXATION              \
   do { link_info.disable_target_specific_optimizations = 0; } while (0)
 
index 53a87b8524d6dbb84f40a7dd636e3fae41b447d5..c699a9163b42548e9e567863dc5970761ad6b404 100644 (file)
@@ -35,6 +35,31 @@ MEMORY
 
 SECTIONS
 {
+  /* Bootloader.  */
+  .bootloader ${RELOCATING-0} :
+  {
+    ${RELOCATING+ PROVIDE (__boot_start = .) ; }
+    *(.bootloader)
+    ${RELOCATING+. = ALIGN(2);}
+    *(.bootloader.*)
+  } ${RELOCATING+ > bootloader}
+  
+  /* Information memory.  */
+  .infomem ${RELOCATING-0} :
+  {
+    *(.infomem)
+    ${RELOCATING+. = ALIGN(2);}
+    *(.infomem.*)
+  } ${RELOCATING+ > infomem}
+
+  /* Information memory (not loaded into MPU).  */
+  .infomemnobits ${RELOCATING-0} :
+  {
+    *(.infomemnobits)
+    ${RELOCATING+. = ALIGN(2);}
+    *(.infomemnobits.*)
+  } ${RELOCATING+ > infomemnobits}
+
   /* Read-only sections, merged into text segment.  */
   ${TEXT_DYNAMIC+${DYNAMIC}}
   .hash        ${RELOCATING-0} : { *(.hash)             }
@@ -122,6 +147,8 @@ SECTIONS
     *(.text)
     ${RELOCATING+. = ALIGN(2);}
     *(.text.*)
+    ${RELOCATING+. = ALIGN(2);}
+    *(.text:*)
 
     ${RELOCATING+. = ALIGN(2);}
     *(SORT_NONE(.fini9))
@@ -139,42 +166,84 @@ SECTIONS
     _etext = .;
   } ${RELOCATING+ > text}
 
-  .data ${RELOCATING-0} : ${RELOCATING+AT (ADDR (.text) + SIZEOF (.text))}
+  .rodata :
+  {
+    . = ALIGN(2);
+    *(.plt)
+    *(.rodata .rodata.* .gnu.linkonce.r.* .const .const:*)
+    *(.rodata1)
+
+    *(.eh_frame_hdr)
+    KEEP (*(.eh_frame))
+
+    KEEP (*(.gcc_except_table)) *(.gcc_except_table.*)
+
+    PROVIDE (__preinit_array_start = .);
+    KEEP (*(.preinit_array))
+    PROVIDE (__preinit_array_end = .);
+
+    PROVIDE (__init_array_start = .);
+    KEEP (*(SORT(.init_array.*)))
+    KEEP (*(.init_array))
+    PROVIDE (__init_array_end = .);
+
+    PROVIDE (__fini_array_start = .);
+    KEEP (*(.fini_array))
+    KEEP (*(SORT(.fini_array.*)))
+    PROVIDE (__fini_array_end = .);
+    LONG(0); /* Sentinel.  */
+
+    /* gcc uses crtbegin.o to find the start of the constructors, so
+       we make sure it is first.  Because this is a wildcard, it
+       doesn't matter if the user does not actually link against
+       crtbegin.o; the linker won't look for a file to match a
+       wildcard.  The wildcard also means that it doesn't matter which
+       directory crtbegin.o is in.  */
+    KEEP (*crtbegin*.o(.ctors))
+
+    /* We don't want to include the .ctor section from from the
+       crtend.o file until after the sorted ctors.  The .ctor section
+       from the crtend file contains the end of ctors marker and it
+       must be last */
+    KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors))
+    KEEP (*(SORT(.ctors.*)))
+    KEEP (*(.ctors))
+
+    KEEP (*crtbegin*.o(.dtors))
+    KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors))
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+  } ${RELOCATING+ > text}
+
+  .vectors ${RELOCATING-0}:
+  {
+    ${RELOCATING+ PROVIDE (__vectors_start = .) ; }
+    *(.vectors*)
+    ${RELOCATING+ _vectors_end = . ; }
+  } ${RELOCATING+ > vectors}
+
+  .data ${RELOCATING-0} : ${RELOCATING+AT (ADDR (.text) + SIZEOF (.text) + SIZEOF (.rodata))}
   {  
     ${RELOCATING+ PROVIDE (__data_start = .) ; }
+    ${RELOCATING+ PROVIDE (__datastart = .) ; }
     ${RELOCATING+. = ALIGN(2);}
+
+    KEEP (*(.jcr))
+    *(.data.rel.ro.local) *(.data.rel.ro*)
+    *(.dynamic)
+
     *(.data)
     *(.data.*)
     *(.gnu.linkonce.d*)
+    KEEP (*(.gnu.linkonce.d.*personality*))
+    *(.data1)
+    *(.got.plt) *(.got)
+    ${RELOCATING+. = ALIGN(2);}
+    *(.sdata .sdata.* .gnu.linkonce.s.*)
     ${RELOCATING+. = ALIGN(2);}
     ${RELOCATING+ _edata = . ; }
   } ${RELOCATING+ > data}
   
-  /* Bootloader.  */
-  .bootloader ${RELOCATING-0} :
-  {
-    ${RELOCATING+ PROVIDE (__boot_start = .) ; }
-    *(.bootloader)
-    ${RELOCATING+. = ALIGN(2);}
-    *(.bootloader.*)
-  } ${RELOCATING+ > bootloader}
-  
-  /* Information memory.  */
-  .infomem ${RELOCATING-0} :
-  {
-    *(.infomem)
-    ${RELOCATING+. = ALIGN(2);}
-    *(.infomem.*)
-  } ${RELOCATING+ > infomem}
-
-  /* Information memory (not loaded into MPU).  */
-  .infomemnobits ${RELOCATING-0} :
-  {
-    *(.infomemnobits)
-    ${RELOCATING+. = ALIGN(2);}
-    *(.infomemnobits.*)
-  } ${RELOCATING+ > infomemnobits}
-
   .bss ${RELOCATING+ SIZEOF(.data) + ADDR(.data)} :
   {
     ${RELOCATING+. = ALIGN(2);}
@@ -194,13 +263,6 @@ SECTIONS
     ${RELOCATING+ _end = . ;  }
   } ${RELOCATING+ > data}
 
-  .vectors ${RELOCATING-0}:
-  {
-    ${RELOCATING+ PROVIDE (__vectors_start = .) ; }
-    *(.vectors*)
-    ${RELOCATING+ _vectors_end = . ; }
-  } ${RELOCATING+ > vectors}
-
   ${HEAP_SECTION_MSP430}
 
   /* Stabs for profiling information*/
@@ -214,12 +276,18 @@ SECTIONS
   .stab.index 0 : { *(.stab.index) }
   .stab.indexstr 0 : { *(.stab.indexstr) }
   .comment 0 : { *(.comment) }
 EOF
 
-. $srcdir/scripttempl/DWARF.sc
+source $srcdir/scripttempl/DWARF.sc
 
 cat <<EOF
+  .MP430.attributes 0 :
+  {
+    KEEP (*(.MSP430.attributes))
+    KEEP (*(.gnu.attributes))
+    KEEP (*(__TI_build_attributes))
+  }
+
   PROVIDE (__stack = ${STACK}) ;
   PROVIDE (__data_start_rom = _etext) ;
   PROVIDE (__data_end_rom   = _etext + SIZEOF (.data)) ;
index 9a23d02ff3606af79065a12a31b77f7a2c4db846..ade5fcb08992cd956faca7863f58ecad226f23a8 100644 (file)
@@ -98,6 +98,8 @@ SECTIONS
     *(.text)
     ${RELOCATING+. = ALIGN(2);}
     *(.text.*)
+    ${RELOCATING+. = ALIGN(2);}
+    *(.text:*)
 
     ${RELOCATING+. = ALIGN(2);}
     *(SORT_NONE(.fini9))
@@ -115,6 +117,13 @@ SECTIONS
     ${RELOCATING+ _etext = . ; }
   } ${RELOCATING+ > text}
 
+  .rodata :
+  {
+    *(.rodata .rodata.* .gnu.linkonce.r.*)
+    *(.const)
+    *(.const:*)
+  } ${RELOCATING+ > text}
+
   .data ${RELOCATING-0} : ${RELOCATING+AT (ADDR (.text) + SIZEOF (.text))}
   {  
     ${RELOCATING+ PROVIDE (__data_start = .) ; }
@@ -152,6 +161,13 @@ SECTIONS
     ${RELOCATING+ _vectors_end = . ; }
   } ${RELOCATING+ > vectors}
 
+  .MP430.attributes 0 :
+  {
+    KEEP (*(.MSP430.attributes))
+    KEEP (*(.gnu.attributes))
+    KEEP (*(__TI_build_attributes))
+  }
+
   /* Stabs debugging sections.  */
   .stab 0 : { *(.stab) } 
   .stabstr 0 : { *(.stabstr) }
index 664b33e4eb577e17f5fb29ace836ad54ff505991..7b2e5067a1c24d5a854b64dbd0317e7e5bff3c5a 100644 (file)
@@ -1,3 +1,15 @@
+2013-05-02  Nick Clifton  <nickc@redhat.com>
+
+       * ld-elf/flags1.d: Expect this test to pass on the MSP430.
+       * ld-elf/init-fini-arrays.d: Expect this test to fail on the
+       MSP430.
+       * ld-elf/merge.d: Expect this test to pass on the MSP430.
+       * ld-elf/sec64k.exp: Skip these tests for the MSP430.
+       * ld-gc/pr13683.d: Expect this test to fail on the MSP430.
+       * ld-srec/srec.exp: Expect these tests to fail on the MSP430.
+       * ld-undefined/undefined.exp: Expect the UNDEFINED LINE test to
+       fail on the MSP430.
+
 2013-05-01  Maciej W. Rozycki  <macro@codesourcery.com>
 
        * lib/ld-lib.exp (check_shared_lib_support): Also exclude
index ab8facc99378bdc40d48297a1ab56b4782499714..63c2e3a049271a20ca799670ae44f812bca2543e 100644 (file)
@@ -3,9 +3,9 @@
 #objcopy_linked_file: --set-section-flags .post_text_reserve=contents,alloc,load,readonly,code
 #readelf: -l --wide
 #xfail: "avr-*-*" "dlx-*-*" "h8300-*-*" "i960-*-*" "ip2k-*-*" "m32r-*-*"
-#xfail: "moxie-*-*" "mt-*-*" "msp430-*-*" "*-*-nacl*"
+#xfail: "moxie-*-*" "mt-*-*" "*-*-nacl*"
 #xfail: "*-*-hpux*" "hppa*64*-*-*"
-# Fails on the AVR, DLX, H8300, I960, IP2K, M32R, MOXIE, MT, and MSP430,
+# Fails on the AVR, DLX, H8300, I960, IP2K, M32R, MOXIE, MT,
 #  and all NaCl targets,
 #  because the two sections are not merged into one segment.
 #  (There is no good reason why they have to be).
index 1b182b94538817e7205ffe2b6d3a7bf8c88f917e..46b536c9c5a01122af4e7baa7f4fccab5eb4e058 100644 (file)
@@ -1,9 +1,10 @@
 #source: init-fini-arrays.s
 #ld: -r
 #readelf: -S --wide
-#xfail: cr16-*-* crx-*-*
+#xfail: cr16-*-* crx-*-* msp430-*-*
+# msp430 puts the init_array and fini_array inside the .rodata section.
 # cr16 and crx use non-standard scripts with memory regions, which don't play
-# well with unique group sections under ld -r.
+#  well with unique group sections under ld -r.
 
 #...
   \[[ 0-9]+\] \.init_array\.01000[ \t]+PROGBITS[ \t0-9a-f]+WA?.*
index 3593f9676efb81974674a2dea2b300361705cf4f..c50de10300d0aa1ef75b257285cc9dfe83e1e8d9 100644 (file)
@@ -4,7 +4,7 @@
 #xfail: "arc-*-*" "avr-*-*" "bfin-*-*" "cr16-*-*" "cris*-*-*" "crx-*-*" "d10v-*-*" "d30v-*-*"
 #xfail: "dlx-*-*" "fr30-*-*" "frv-*-*" "hppa*64*-*-*" "h8300-*-*" "score-*-*"
 #xfail: "i370-*-*" "i860-*-*" "i960-*-*" "ip2k-*-*" "iq2000-*-*" "lm32-*-*"
-#xfail: "mcore-*-*" "mn102*-*-*" "mips*-*-*" "ms1-*-*" "msp430-*-*" "mep-*-*"
+#xfail: "mcore-*-*" "mn102*-*-*" "mips*-*-*" "ms1-*-*" "mep-*-*"
 #xfail: "or32-*-*" "pj-*-*" "sparc*-*-*" "tic6x-*-*" "vax-*-*" "xstormy16-*-*"
 #xfail: "xtensa*-*-*" "metag-*-*"
 
index 7c04c9b87296b67535942ea0033e5bf40f9284d3..7c9f2929cbe0895588a3adb58f629211756ba37d 100644 (file)
@@ -34,6 +34,7 @@ if { [istarget "arc-*-*"]
      || [istarget "d30v-*-*"]
      || [istarget "dlx-*-*"]
      || [istarget "i960-*-*"]
+     || [istarget "msp430*-*-*"]
      || [istarget "or32-*-*"]
      || [istarget "pj*-*-*"]
      || [istarget "m32r-*-*"] } {
index 19b2598e4330884da439ab8ff939e8f57fbec33f..b38b9d1642fb53969f70ed5f7ccf47d49674497b 100644 (file)
@@ -2,7 +2,7 @@
 #source: dummy.s
 #ld: --gc-sections -e main --defsym foo=foo2 tmpdir/pr13683.o
 #nm: --format=bsd
-#xfail: sh64*-*-* iq2000-*-* lm32-*-* epiphany-*-* mips64vr-*-* frv-*-* m32c-*-* rl78-*-* rx-*-* sh-*-* powerpc*-*-eabivle
+#xfail: sh64*-*-* iq2000-*-* lm32-*-* epiphany-*-* mips64vr-*-* frv-*-* m32c-*-* rl78-*-* rx-*-* sh-*-* powerpc*-*-eabivle msp430-*-*
 
 # Note - look for both "foo" and "foo2" being defined, non-zero function symbols
 
index 001fb2e1655950350850980b7be02c2dbd769d55..4a433d1f3e7253beca4073003e93a53a04d4b511 100644 (file)
@@ -1,7 +1,6 @@
 # Test linking directly to S-records.
 # By Ian Lance Taylor, Cygnus Support.
-#   Copyright 1999, 2000, 2001, 2002, 2003, 2005, 2006, 2007, 2009, 2011, 2012
-#   Free Software Foundation, Inc.
+#   Copyright 1999-2013 Free Software Foundation, Inc.
 #
 # This file is part of the GNU Binutils.
 #
@@ -269,6 +268,11 @@ proc run_srec_test { test objs } {
        set flags "$flags -no-relax"
     }
 
+    # MSP430 targets always relax.
+    if [istarget msp430*-*-*] {
+       setup_xfail "msp430*-*-*"
+    }
+
     # Epiphany needs some help too
     if [istarget epiphany*-*-*] {
        set flags "$flags --defsym _start=00000060"
index 65fbc4b4d71acf39c98f0bf340e8bb29b000a13d..49af737e35305f80899b57667e4108a3b218f2e1 100644 (file)
@@ -128,6 +128,11 @@ setup_xfail mcore-*-elf
 setup_xfail mep-*-*
 setup_xfail mips-sgi-irix6*
 setup_xfail "sh64-*-*"
+# Fails for the MSP430 because it uses SYM_DIFF relocs but it does
+# not provide a special_function for handling them.  If optimization
+# is enabled then this test passes because function()'s prologue is
+# eliminated.
+setup_xfail "msp430-*-*"
 
 # The undefined test fails on 31 bit s/390 because the address of the 
 # function `this_function_is_not_defined' is stored in the literal pool of
index 291276511a3507c49cb20974ce9934126a9135c6..88f9294fe2f9f0235db5dd061be73f75414fa055 100644 (file)
@@ -1,3 +1,7 @@
+2013-05-02  Nick Clifton  <nickc@redhat.com>
+
+       * msp430-dis.c: Add support for MSP430X instructions.
+
 2013-04-24  Sandra Loosemore  <sandra@codesourcery.com>
 
        * nios2-opc.c (nios2_builtin_reg): Rename "fstatus" control register
index 71690a3c62b8c60b492fd5f0a9a0dcdbfb683e3e..46da3ccc653eba259b1a60c92149e0bde9691518 100644 (file)
@@ -1,7 +1,6 @@
 /* Disassemble MSP430 instructions.
-   Copyright (C) 2002, 2004, 2005, 2007, 2009, 2010, 2012
-   Free Software Foundation, Inc.
-   
+   Copyright (C) 2002-2013 Free Software Foundation, Inc.
+
    Contributed by Dmitry Diky <diwil@mail.ru>
         
    This file is part of the GNU opcodes library.
@@ -82,6 +81,52 @@ msp430_nooperands (struct msp430_opcode_s *opcode,
   return 2;
 }
 
+static int
+print_as2_reg_name (int regno, char * op1, char * comm1,
+                   int c2, int c3, int cd)
+{
+  switch (regno)
+    {
+    case 2:
+      sprintf (op1, "#4");
+      sprintf (comm1, "r2 As==10");
+      return c2;
+
+    case 3:
+      sprintf (op1, "#2");
+      sprintf (comm1, "r3 As==10");
+      return c3;
+
+    default:
+      /* Indexed register mode @Rn.  */
+      sprintf (op1, "@r%d", regno);
+      return cd;
+    }
+}
+
+static int
+print_as3_reg_name (int regno, char * op1, char * comm1,
+                   int c2, int c3, int cd)
+{
+  switch (regno)
+    {
+    case 2:
+      sprintf (op1, "#8");
+      sprintf (comm1, "r2 As==11");
+      return c2;
+
+    case 3:
+      sprintf (op1, "#-1");
+      sprintf (comm1, "r3 As==11");
+      return c3;
+
+    default:
+      /* Post incremented @Rn+.  */
+      sprintf (op1, "@r%d+", regno);
+      return cd;
+    }
+}
+
 static int
 msp430_singleoperand (disassemble_info *info,
                      struct msp430_opcode_s *opcode,
@@ -89,20 +134,28 @@ msp430_singleoperand (disassemble_info *info,
                      unsigned short insn,
                      char *op,
                      char *comm,
+                     unsigned short extension_word,
                      int *cycles)
 {
   int regs = 0, regd = 0;
   int ad = 0, as = 0;
   int where = 0;
   int cmd_len = 2;
-  short dst = 0;
+  int dst = 0;
+  int fmt;
+  int extended_dst = extension_word & 0xf;
 
   regd = insn & 0x0f;
   regs = (insn & 0x0f00) >> 8;
   as = (insn & 0x0030) >> 4;
   ad = (insn & 0x0080) >> 7;
 
-  switch (opcode->fmt)
+  if (opcode->fmt < 0)
+    fmt = (- opcode->fmt) - 1;
+  else
+    fmt = opcode->fmt;
+
+  switch (fmt)
     {
     case 0:                    /* Emulated work with dst register.  */
       if (regs != 2 && regs != 3 && regs != 1)
@@ -146,6 +199,13 @@ msp430_singleoperand (disassemble_info *info,
              sprintf (op, "0x%04x", dst);
              sprintf (comm, "PC rel. abs addr 0x%04x",
                       PS ((short) (addr + 2) + dst));
+             if (extended_dst)
+               {
+                 dst |= extended_dst << 16;
+                 sprintf (op, "0x%05x", dst);
+                 sprintf (comm, "PC rel. abs addr 0x%05lx",
+                          (long)((addr + 2 + dst) & 0xfffff));
+               }
            }
          else if (regd == 2)
            {
@@ -154,12 +214,25 @@ msp430_singleoperand (disassemble_info *info,
              cmd_len += 2;
              *cycles = 4;
              sprintf (op, "&0x%04x", PS (dst));
+             if (extended_dst)
+               {
+                 dst |= extended_dst << 16;
+                 sprintf (op, "&0x%05x", dst & 0xfffff);
+               }
            }
          else
            {
              dst = msp430dis_opcode (addr + 2, info);
              cmd_len += 2;
              *cycles = 4;
+             if (extended_dst)
+               {
+                 dst |= extended_dst << 16;
+                 if (dst & 0x80000)
+                   dst |= -1 << 20;
+               }
+             else if (dst & 0x8000)
+               dst |= -1 << 16;
              sprintf (op, "%d(r%d)", dst, regd);
            }
        }
@@ -183,51 +256,31 @@ msp430_singleoperand (disassemble_info *info,
        }
       else if (as == 2)
        {
-         *cycles = 1;
-         if (regd == 2)
-           {
-             sprintf (op, "#4");
-             sprintf (comm, "r2 As==10");
-           }
-         else if (regd == 3)
-           {
-             sprintf (op, "#2");
-             sprintf (comm, "r3 As==10");
-           }
-         else
-           {
-             *cycles = 3;
-             /* Indexed register mode @Rn.  */
-             sprintf (op, "@r%d", regd);
-           }
+         * cycles = print_as2_reg_name (regd, op, comm, 1, 1, 3);
        }
       else if (as == 3)
        {
-         *cycles = 1;
-         if (regd == 2)
-           {
-             sprintf (op, "#8");
-             sprintf (comm, "r2 As==11");
-           }
-         else if (regd == 3)
-           {
-             sprintf (op, "#-1");
-             sprintf (comm, "r3 As==11");
-           }
-         else if (regd == 0)
+         if (regd == 0)
            {
              *cycles = 3;
              /* absolute. @pc+ */
              dst = msp430dis_opcode (addr + 2, info);
              cmd_len += 2;
              sprintf (op, "#%d", dst);
-             sprintf (comm, "#0x%04x", PS (dst));
+             if (dst > 9 || dst < 0)
+               sprintf (comm, "#0x%04x", PS (dst));
+             if (extended_dst)
+               {
+                 dst |= extended_dst << 16;
+                 if (dst & 0x80000)
+                   dst |= -1 << 20;
+                 sprintf (op, "#%d", dst);
+                 if (dst > 9 || dst < 0)
+                   sprintf (comm, "#0x%05x", dst);
+               }
            }
          else
-           {
-             *cycles = 3;
-             sprintf (op, "@r%d+", regd);
-           }
+           * cycles = print_as3_reg_name (regd, op, comm, 1, 1, 3);
        }
       else if (as == 1)
        {
@@ -240,6 +293,13 @@ msp430_singleoperand (disassemble_info *info,
              sprintf (op, "0x%04x", PS (dst));
              sprintf (comm, "PC rel. 0x%04x",
                       PS ((short) addr + 2 + dst));
+             if (extended_dst)
+               {
+                 dst |= extended_dst << 16;
+                 sprintf (op, "0x%05x", dst & 0xffff);
+                 sprintf (comm, "PC rel. 0x%05lx",
+                          (long)((addr + 2 + dst) & 0xfffff));
+               }
            }
          else if (regd == 2)
            {
@@ -247,6 +307,11 @@ msp430_singleoperand (disassemble_info *info,
              dst = msp430dis_opcode (addr + 2, info);
              cmd_len += 2;
              sprintf (op, "&0x%04x", PS (dst));
+             if (extended_dst)
+               {
+                 dst |= extended_dst << 16;
+                 sprintf (op, "&0x%05x", dst & 0xfffff);
+               }
            }
          else if (regd == 3)
            {
@@ -256,10 +321,20 @@ msp430_singleoperand (disassemble_info *info,
            }
          else
            {
-             /* Indexd.  */
+             /* Indexed.  */
              dst = msp430dis_opcode (addr + 2, info);
              cmd_len += 2;
+             if (extended_dst)
+               {
+                 dst |= extended_dst << 16;
+                 if (dst & 0x80000)
+                   dst |= -1 << 20;
+               }
+             else if (dst & 0x8000)
+               dst |= -1 << 16;
              sprintf (op, "%d(r%d)", dst, regd);
+             if (dst > 9 || dst < 0)
+               sprintf (comm, "%05x", dst);
            }
        }
       break;
@@ -273,7 +348,7 @@ msp430_singleoperand (disassemble_info *info,
 
       where *= 2;
       sprintf (op, "$%+-8d", where + 2);
-      sprintf (comm, "abs 0x%x", PS ((short) (addr) + 2 + where));
+      sprintf (comm, "abs 0x%lx", (long) (addr + 2 + where));
       *cycles = 2;
       return 2;
       break;
@@ -293,19 +368,28 @@ msp430_doubleoperand (disassemble_info *info,
                      char *op2,
                      char *comm1,
                      char *comm2,
+                     unsigned short extension_word,
                      int *cycles)
 {
   int regs = 0, regd = 0;
   int ad = 0, as = 0;
   int cmd_len = 2;
-  short dst = 0;
+  int dst = 0;
+  int fmt;
+  int extended_dst = extension_word & 0xf;
+  int extended_src = (extension_word >> 7) & 0xf;
 
   regd = insn & 0x0f;
   regs = (insn & 0x0f00) >> 8;
   as = (insn & 0x0030) >> 4;
   ad = (insn & 0x0080) >> 7;
 
-  if (opcode->fmt == 0)
+  if (opcode->fmt < 0)
+    fmt = (- opcode->fmt) - 1;
+  else
+    fmt = opcode->fmt;
+
+  if (fmt == 0)
     {
       /* Special case: rla and rlc are the only 2 emulated instructions that
         fall into two operand instructions.  */
@@ -343,7 +427,15 @@ msp430_doubleoperand (disassemble_info *info,
              sprintf (op1, "0x%04x", PS (dst));
              sprintf (comm1, "PC rel. 0x%04x",
                       PS ((short) addr + 2 + dst));
-
+             if (extended_dst)
+               {
+                 dst |= extended_dst << 16;
+                 if (dst & 0x80000)
+                   dst |= -1 << 20;
+                 sprintf (op1, "0x%05x", dst & 0xfffff);
+                 sprintf (comm1, "PC rel. 0x%05lx",
+                          (long)((addr + 2 + dst) & 0xfffff));
+               }
            }
          else if (regd == 2)
            {
@@ -356,19 +448,35 @@ msp430_doubleoperand (disassemble_info *info,
              cmd_len += 4;
              *cycles = 6;
              sprintf (op1, "&0x%04x", PS (dst));
+             if (extended_dst)
+               {
+                 dst |= extended_dst << 16;
+                 sprintf (op1, "&0x%05x", dst & 0xfffff);
+               }
            }
          else
            {
              /* Indexed.  */
              dst = msp430dis_opcode (addr + 2, info);
+             if (extended_dst)
+               {
+                 dst |= extended_dst << 16;
+                 if (dst & 0x80000)
+                   dst |= -1 << 20;
+               }
+             else if (dst & 0x8000)
+               dst |= -1 << 16;
              cmd_len += 4;
              *cycles = 6;
              sprintf (op1, "%d(r%d)", dst, regd);
+             if (dst > 9 || dst < -9)
+               sprintf (comm1, "#0x%05x", dst);
            }
        }
 
       *op2 = 0;
       *comm2 = 0;
+
       return cmd_len;
     }
 
@@ -386,7 +494,7 @@ msp430_doubleoperand (disassemble_info *info,
       *cycles = 1;
       if (regs == 3)
        {
-         /* Constsnts.  */
+         /* Constants.  */
          sprintf (op1, "#0");
          sprintf (comm1, "r3 As==00");
        }
@@ -398,56 +506,31 @@ msp430_doubleoperand (disassemble_info *info,
     }
   else if (as == 2)
     {
-      *cycles = 1;
-
-      if (regs == 2)
-       {
-         sprintf (op1, "#4");
-         sprintf (comm1, "r2 As==10");
-       }
-      else if (regs == 3)
-       {
-         sprintf (op1, "#2");
-         sprintf (comm1, "r3 As==10");
-       }
-      else
-       {
-         *cycles = 2;
-
-         /* Indexed register mode @Rn.  */
-         sprintf (op1, "@r%d", regs);
-       }
-      if (!regs)
-       *cycles = 3;
+      * cycles = print_as2_reg_name (regs, op1, comm1, 1, 1, regs == 0 ? 3 : 2);
     }
   else if (as == 3)
     {
-      if (regs == 2)
-       {
-         sprintf (op1, "#8");
-         sprintf (comm1, "r2 As==11");
-         *cycles = 1;
-       }
-      else if (regs == 3)
-       {
-         sprintf (op1, "#-1");
-         sprintf (comm1, "r3 As==11");
-         *cycles = 1;
-       }
-      else if (regs == 0)
+      if (regs == 0)
        {
          *cycles = 3;
          /* Absolute. @pc+.  */
          dst = msp430dis_opcode (addr + 2, info);
          cmd_len += 2;
          sprintf (op1, "#%d", dst);
-         sprintf (comm1, "#0x%04x", PS (dst));
+         if (dst > 9 || dst < 0)
+           sprintf (comm1, "#0x%04x", PS (dst));
+         if (extended_src)
+           {
+             dst |= extended_src << 16;
+             if (dst & 0x80000)
+               dst |= -1 << 20;
+             sprintf (op1, "#%d", dst);
+             if (dst > 9 || dst < 0)
+               sprintf (comm1, "0x%05x", dst & 0xfffff);
+           }
        }
       else
-       {
-         *cycles = 2;
-         sprintf (op1, "@r%d+", regs);
-       }
+       * cycles = print_as3_reg_name (regs, op1, comm1, 1, 1, 2);
     }
   else if (as == 1)
     {
@@ -460,6 +543,15 @@ msp430_doubleoperand (disassemble_info *info,
          sprintf (op1, "0x%04x", PS (dst));
          sprintf (comm1, "PC rel. 0x%04x",
                   PS ((short) addr + 2 + dst));
+         if (extended_src)
+           {
+             dst |= extended_src << 16;
+             if (dst & 0x80000)
+               dst |= -1 << 20;
+             sprintf (op1, "0x%05x", dst & 0xfffff);
+             sprintf (comm1, "PC rel. 0x%05lx",
+                      (long) ((addr + 2 + dst) & 0xfffff));
+           }
        }
       else if (regs == 2)
        {
@@ -469,6 +561,12 @@ msp430_doubleoperand (disassemble_info *info,
          cmd_len += 2;
          sprintf (op1, "&0x%04x", PS (dst));
          sprintf (comm1, "0x%04x", PS (dst));
+         if (extended_src)
+           {
+             dst |= extended_src << 16;
+             sprintf (op1, "&0x%05x", dst & 0xfffff);
+             * comm1 = 0;
+           }
        }
       else if (regs == 3)
        {
@@ -482,7 +580,17 @@ msp430_doubleoperand (disassemble_info *info,
          /* Indexed.  */
          dst = msp430dis_opcode (addr + 2, info);
          cmd_len += 2;
+         if (extended_src)
+           {
+             dst |= extended_src << 16;
+             if (dst & 0x80000)
+               dst |= -1 << 20;
+           }
+         else if (dst & 0x8000)
+           dst |= -1 << 16;
          sprintf (op1, "%d(r%d)", dst, regs);
+         if (dst > 9 || dst < -9)
+           sprintf (comm1, "0x%05x", dst);
        }
     }
 
@@ -517,6 +625,15 @@ msp430_doubleoperand (disassemble_info *info,
          sprintf (op2, "0x%04x", PS (dst));
          sprintf (comm2, "PC rel. 0x%04x",
                   PS ((short) addr + cmd_len + dst));
+         if (extended_dst)
+           {
+             dst |= extended_dst << 16;
+             if (dst & 0x80000)
+               dst |= -1 << 20;
+             sprintf (op2, "0x%05x", dst & 0xfffff);
+             sprintf (comm2, "PC rel. 0x%05lx",
+                      (long)((addr + cmd_len + dst) & 0xfffff));
+           }
          cmd_len += 2;
        }
       else if (regd == 2)
@@ -525,11 +642,28 @@ msp430_doubleoperand (disassemble_info *info,
          dst = msp430dis_opcode (addr + cmd_len, info);
          cmd_len += 2;
          sprintf (op2, "&0x%04x", PS (dst));
+         if (extended_dst)
+           {
+             dst |= extended_dst << 16;
+             sprintf (op2, "&0x%05x", dst & 0xfffff);
+           }
        }
       else
        {
          dst = msp430dis_opcode (addr + cmd_len, info);
          cmd_len += 2;
+         if (dst & 0x8000)
+           dst |= -1 << 16;
+         if (dst > 9 || dst < 0)
+           sprintf (comm2, "0x%04x", PS (dst));
+         if (extended_dst)
+           {
+             dst |= extended_dst << 16;
+             if (dst & 0x80000)
+               dst |= -1 << 20;
+             if (dst > 9 || dst < 0)
+               sprintf (comm2, "0x%05x", dst & 0xfffff);
+           }
          sprintf (op2, "%d(r%d)", dst, regd);
        }
     }
@@ -577,40 +711,11 @@ msp430_branchinstr (disassemble_info *info,
     }
   else if (as == 2)
     {
-      if (regs == 2)
-       {
-         *cycles = 2;
-         sprintf (op1, "#4");
-         sprintf (comm1, "r2 As==10");
-       }
-      else if (regs == 3)
-       {
-         *cycles = 1;
-         sprintf (op1, "#2");
-         sprintf (comm1, "r3 As==10");
-       }
-      else
-       {
-         /* Indexed register mode @Rn.  */
-         *cycles = 2;
-         sprintf (op1, "@r%d", regs);
-       }
+      * cycles = print_as2_reg_name (regs, op1, comm1, 2, 1, 2);
     }
   else if (as == 3)
     {
-      if (regs == 2)
-       {
-         *cycles = 1;
-         sprintf (op1, "#8");
-         sprintf (comm1, "r2 As==11");
-       }
-      else if (regs == 3)
-       {
-         *cycles = 1;
-         sprintf (op1, "#-1");
-         sprintf (comm1, "r3 As==11");
-       }
-      else if (regs == 0)
+      if (regs == 0)
        {
          /* Absolute. @pc+  */
          *cycles = 3;
@@ -619,10 +724,7 @@ msp430_branchinstr (disassemble_info *info,
          sprintf (op1, "#0x%04x", PS (dst));
        }
       else
-       {
-         *cycles = 2;
-         sprintf (op1, "@r%d+", regs);
-       }
+       * cycles = print_as3_reg_name (regs, op1, comm1, 1, 1, 2);
     }
   else if (as == 1)
     {
@@ -653,9 +755,11 @@ msp430_branchinstr (disassemble_info *info,
        }
       else
        {
-         /* Indexd.  */
+         /* Indexed.  */
          dst = msp430dis_opcode (addr + 2, info);
          cmd_len += 2;
+         if (dst & 0x8000)
+           dst |= -1 << 16;
          sprintf (op1, "%d(r%d)", dst, regs);
        }
     }
@@ -663,6 +767,82 @@ msp430_branchinstr (disassemble_info *info,
   return cmd_len;
 }
 
+static int
+msp430x_calla_instr (disassemble_info * info,
+                    bfd_vma            addr,
+                    unsigned short     insn,
+                    char *             op1,
+                    char *             comm1,
+                    int *              cycles)
+{
+  unsigned int   ureg = insn & 0xf;
+  int            reg = insn & 0xf;
+  int            am = (insn & 0xf0) >> 4;
+  int            cmd_len = 2;
+  unsigned short udst = 0;
+  short          dst = 0;
+
+  switch (am)
+    {
+    case 4: /* CALLA Rdst */
+      *cycles = 1;
+      sprintf (op1, "r%d", reg);
+      break;
+
+    case 5: /* CALLA x(Rdst) */
+      *cycles = 3;
+      dst = msp430dis_opcode (addr + 2, info);
+      cmd_len += 2;
+      sprintf (op1, "%d(r%d)", dst, reg);
+      if (reg == 0)
+       sprintf (comm1, "PC rel. 0x%05lx", (long) (addr + 2 + dst));
+      else
+       sprintf (comm1, "0x%05x", dst);
+      break;
+
+    case 6: /* CALLA @Rdst */
+      *cycles = 2;
+      sprintf (op1, "@r%d", reg);
+      break;
+
+    case 7: /* CALLA @Rdst+ */
+      *cycles = 2;
+      sprintf (op1, "@r%d+", reg);
+      break;
+
+    case 8: /* CALLA &abs20 */
+      udst = msp430dis_opcode (addr + 2, info);
+      cmd_len += 2;
+      *cycles = 4;
+      sprintf (op1, "&%d", (ureg << 16) + udst);
+      sprintf (comm1, "0x%05x", (ureg << 16) + udst);
+      break;
+
+    case 9: /* CALLA pcrel-sym */
+      dst = msp430dis_opcode (addr + 2, info);
+      cmd_len += 2;
+      *cycles = 4;
+      sprintf (op1, "%d(PC)", (reg << 16) + dst);
+      sprintf (comm1, "PC rel. 0x%05lx",
+              (long) (addr + 2 + dst + (reg << 16)));
+      break;
+
+    case 11: /* CALLA #imm20 */
+      udst = msp430dis_opcode (addr + 2, info);
+      cmd_len += 2;
+      *cycles = 4;
+      sprintf (op1, "#%d", (ureg << 16) + udst);
+      sprintf (comm1, "0x%05x", (ureg << 16) + udst);
+      break;
+
+    default:
+      strcpy (comm1, _("unercognised CALLA addressing mode"));
+      return -1;
+    }
+
+  return cmd_len;
+}
+
 int
 print_insn_msp430 (bfd_vma addr, disassemble_info *info)
 {
@@ -674,10 +854,14 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
   unsigned short insn;
   int cycles = 0;
   char *bc = "";
-  char dinfo[32];              /* Debug purposes.  */
+  unsigned short extension_word = 0;
 
   insn = msp430dis_opcode (addr, info);
-  sprintf (dinfo, "0x%04x", insn);
+  if (insn == (unsigned short) -1)
+    {
+      prin (stream, ".word     0xffff; ????");
+      return 2;
+    }
 
   if (((int) addr & 0xffff) > 0xffdf)
     {
@@ -688,6 +872,20 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
   *comm1 = 0;
   *comm2 = 0;
 
+  /* Check for an extension word.  */
+  if ((insn & 0xf800) == 0x1800)
+    {
+      extension_word = insn;
+      addr += 2;
+      insn = msp430dis_opcode (addr, info);
+      if (insn == (unsigned short) -1)
+       {
+         prin (stream, ".word  0x%04x, 0xffff; ????",
+               extension_word);
+         return 4;
+       }
+   }
+
   for (opcode = msp430_opcodes; opcode->name; opcode++)
     {
       if ((insn & opcode->bin_mask) == opcode->bin_opcode
@@ -699,34 +897,257 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
          *comm2 = 0;
 
          /* r0 as destination. Ad should be zero.  */
-         if (opcode->insn_opnumb == 3 && (insn & 0x000f) == 0
-             && (0x0080 & insn) == 0)
+         if (opcode->insn_opnumb == 3
+             && (insn & 0x000f) == 0
+             && (insn & 0x0080) == 0)
            {
-             cmd_len =
+             cmd_len +=
                msp430_branchinstr (info, opcode, addr, insn, op1, comm1,
                                    &cycles);
              if (cmd_len)
                break;
            }
 
+         switch (opcode->insn_opnumb)
+           {
+             int n;
+             int reg;
+
+           case 4:
+             cmd_len += msp430x_calla_instr (info, addr, insn,
+                                             op1, comm1, & cycles);
+             break;
+
+           case 5: /* PUSHM/POPM */
+             n = (insn & 0xf0) >> 4;
+             reg = (insn & 0xf);
+
+             sprintf (op1, "#%d", n + 1);
+             if (opcode->bin_opcode == 0x1400)
+               /* PUSHM */
+               sprintf (op2, "r%d", reg);
+             else
+               /* POPM */
+               sprintf (op2, "r%d", reg + n);
+             if (insn & 0x100)
+               sprintf (comm1, "16-bit words");
+             else
+               {
+                 sprintf (comm1, "20-bit words");
+                 bc =".a";
+               }
+             
+             cycles = 2; /*FIXME*/
+             cmd_len = 2;
+             break;
+
+           case 6: /* RRAM, RRCM, RRUM, RLAM.  */
+             n = ((insn >> 10) & 0x3) + 1;
+             reg = (insn & 0xf);
+             if ((insn & 0x10) == 0)
+               bc =".a";
+             sprintf (op1, "#%d", n);
+             sprintf (op2, "r%d", reg);
+             cycles = 2; /*FIXME*/
+             cmd_len = 2;
+             break;
+
+           case 8: /* ADDA, CMPA, SUBA.  */
+             reg = (insn & 0xf);
+             n = (insn >> 8) & 0xf;
+             if (insn & 0x40)
+               {
+                 sprintf (op1, "r%d", n);
+                 cmd_len = 2;
+               }
+             else
+               {
+                 n <<= 16;
+                 n |= msp430dis_opcode (addr + 2, info);
+                 sprintf (op1, "#%d", n);
+                 if (n > 9 || n < 0)
+                   sprintf (comm1, "0x%05x", n);
+                 cmd_len = 4;
+               }
+             sprintf (op2, "r%d", reg);
+             cycles = 2; /*FIXME*/
+             break;
+
+           case 9: /* MOVA */
+             reg = (insn & 0xf);
+             n = (insn >> 8) & 0xf;
+             switch ((insn >> 4) & 0xf)
+               {
+               case 0: /* MOVA @Rsrc, Rdst */
+                 cmd_len = 2;
+                 sprintf (op1, "@r%d", n);
+                 if (strcmp (opcode->name, "bra") != 0)
+                   sprintf (op2, "r%d", reg);
+                 break;
+                 
+               case 1: /* MOVA @Rsrc+, Rdst */
+                 cmd_len = 2;
+                 if (strcmp (opcode->name, "reta") != 0)
+                   {
+                     sprintf (op1, "@r%d+", n);
+                     if (strcmp (opcode->name, "bra") != 0)
+                       sprintf (op2, "r%d", reg);
+                   }
+                 break;
+                 
+               case 2: /* MOVA &abs20, Rdst */
+                 cmd_len = 4;
+                 n <<= 16;
+                 n |= msp430dis_opcode (addr + 2, info);
+                 sprintf (op1, "&%d", n);
+                 if (n > 9 || n < 0)
+                   sprintf (comm1, "0x%05x", n);
+                 if (strcmp (opcode->name, "bra") != 0)
+                   sprintf (op2, "r%d", reg);
+                 break;
+                 
+               case 3: /* MOVA x(Rsrc), Rdst */
+                 cmd_len = 4;
+                 if (strcmp (opcode->name, "bra") != 0)
+                   sprintf (op2, "r%d", reg);
+                 reg = n;
+                 n = msp430dis_opcode (addr + 2, info);
+                 if (n & 0x8000)
+                   n |= -1 << 16;
+                 sprintf (op1, "%d(r%d)", n, reg);
+                 if (n > 9 || n < 0)
+                   {
+                     if (reg == 0)
+                       sprintf (comm1, "PC rel. 0x%05lx",
+                                (long) (addr + 2 + n));
+                     else
+                       sprintf (comm1, "0x%05x", n);
+                   }
+                 break;
+
+               case 6: /* MOVA Rsrc, &abs20 */
+                 cmd_len = 4;
+                 reg <<= 16;
+                 reg |= msp430dis_opcode (addr + 2, info);
+                 sprintf (op1, "r%d", n);
+                 sprintf (op2, "&%d", reg);
+                 if (reg > 9 || reg < 0)
+                   sprintf (comm2, "0x%05x", reg);
+                 break;
+
+               case 7: /* MOVA Rsrc, x(Rdst) */
+                 cmd_len = 4;
+                 sprintf (op1, "r%d", n);
+                 n = msp430dis_opcode (addr + 2, info);
+                 if (n & 0x8000)
+                   n |= -1 << 16;
+                 sprintf (op2, "%d(r%d)", n, reg);
+                 if (n > 9 || n < 0)
+                   {
+                     if (reg == 0)
+                       sprintf (comm2, "PC rel. 0x%05lx",
+                                (long) (addr + 2 + n));
+                     else
+                       sprintf (comm2, "0x%05x", n);
+                   }
+                 break;
+                 
+               case 8: /* MOVA #imm20, Rdst */
+                 cmd_len = 4;
+                 n <<= 16;
+                 n |= msp430dis_opcode (addr + 2, info);
+                 if (n & 0x80000)
+                   n |= -1 << 20;
+                 sprintf (op1, "#%d", n);
+                 if (n > 9 || n < 0)
+                   sprintf (comm1, "0x%05x", n);
+                 if (strcmp (opcode->name, "bra") != 0)
+                   sprintf (op2, "r%d", reg);
+                 break;
+                 
+               case 12: /* MOVA Rsrc, Rdst */
+                 cmd_len = 2;
+                 sprintf (op1, "r%d", n);
+                 if (strcmp (opcode->name, "bra") != 0)
+                   sprintf (op2, "r%d", reg);
+                 break;
+
+               default:
+                 break;
+               }
+             cycles = 2; /* FIXME */
+             break;
+           }
+
+         if (cmd_len)
+           break;
+
          switch (opcode->insn_opnumb)
            {
            case 0:
-             cmd_len = msp430_nooperands (opcode, addr, insn, comm1, &cycles);
+             cmd_len += msp430_nooperands (opcode, addr, insn, comm1, &cycles);
              break;
            case 2:
-             cmd_len =
+             cmd_len +=
                msp430_doubleoperand (info, opcode, addr, insn, op1, op2,
-                                     comm1, comm2, &cycles);
+                                     comm1, comm2,
+                                     extension_word,
+                                     &cycles);
              if (insn & BYTE_OPERATION)
-               bc = ".b";
+               {
+                 if (extension_word != 0 && ((extension_word & BYTE_OPERATION) == 0))
+                   bc = ".a";
+                 else
+                   bc = ".b";
+               }
+             else if (extension_word)
+               {
+                 if (extension_word & (1 << 6))
+                   bc = ".w";
+                 else
+                   {
+                     bc = ".?";
+                     sprintf (comm2, _("Reserved use of A/L and B/W bits detected"));
+                   }
+               }
+             
              break;
            case 1:
-             cmd_len =
+             cmd_len +=
                msp430_singleoperand (info, opcode, addr, insn, op1, comm1,
+                                     extension_word,
                                      &cycles);
-             if (insn & BYTE_OPERATION && opcode->fmt != 3)
-               bc = ".b";
+             if (extension_word
+                 && (strcmp (opcode->name, "swpb") == 0
+                     || strcmp (opcode->name, "sxt") == 0))
+               {
+                 if (insn & BYTE_OPERATION)
+                   {
+                     bc = ".?";
+                     sprintf (comm2, _("Reserved use of A/L and B/W bits detected"));
+                   }
+                 else if (extension_word & BYTE_OPERATION)
+                   bc = ".w";
+                 else
+                   bc = ".a";
+               }
+             else if (insn & BYTE_OPERATION && opcode->fmt != 3)
+               {
+                 if (extension_word != 0 && ((extension_word & BYTE_OPERATION) == 0))
+                   bc = ".a";
+                 else
+                   bc = ".b";
+               }
+             else if (extension_word)
+               {
+                 if (extension_word & (1 << 6))
+                   bc = ".w";
+                 else
+                   {
+                     bc = ".?";
+                     sprintf (comm2, _("Reserved use of A/L and B/W bits detected"));
+                   }
+               }
              break;
            default:
              break;
@@ -737,16 +1158,33 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
        break;
     }
 
-  dinfo[5] = 0;
-
   if (cmd_len < 1)
     {
       /* Unknown opcode, or invalid combination of operands.  */
+      if (extension_word)
+       {
+         prin (stream, ".word  0x%04x, 0x%04x; ????", extension_word, PS (insn));
+         if (*comm1)
+           prin (stream, "\t %s", comm1);
+         return 4;
+       }
       (*prin) (stream, ".word  0x%04x; ????", PS (insn));
       return 2;
     }
 
-  (*prin) (stream, "%s%s", opcode->name, bc);
+  /* Display the repeat count (if set) for extended register mode.  */
+  if (cmd_len == 2 && ((extension_word & 0xf) != 0))
+    {
+      if (extension_word & (1 << 7))
+       prin (stream, "rpt r%d { ", extension_word & 0xf);
+      else
+       prin (stream, "rpt #%d { ", (extension_word & 0xf) + 1);
+    }
+
+  if (extension_word && opcode->name[strlen (opcode->name) - 1] != 'x')
+    (*prin) (stream, "%sx%s", opcode->name, bc);
+  else
+    (*prin) (stream, "%s%s", opcode->name, bc);
 
   if (*op1)
     (*prin) (stream, "\t%s", op1);
@@ -783,5 +1221,9 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
     (*prin) (stream, ",");
   if (*comm2)
     (*prin) (stream, " %s", comm2);
+
+  if (extension_word)
+    cmd_len += 2;
+
   return cmd_len;
 }
This page took 0.118766 seconds and 4 git commands to generate.