aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Clifton <nickc@redhat.com>2014-05-20 10:28:42 +0100
committerNick Clifton <nickc@redhat.com>2014-05-20 10:28:42 +0100
commit00b32ff21f710a5eed92c9fdf51c32103bcc4176 (patch)
treeb26adf9e6654280500869f1749f0d239f59da1c0
parent273dc279306c2b69fbc1407cc695397e4b015152 (diff)
downloadgdb-00b32ff21f710a5eed92c9fdf51c32103bcc4176.zip
gdb-00b32ff21f710a5eed92c9fdf51c32103bcc4176.tar.gz
gdb-00b32ff21f710a5eed92c9fdf51c32103bcc4176.tar.bz2
Fix MSP430 assembler to support #hi(<symbol>).
* config/tc-msp430.c (CHECK_RELOC_MSP430): Add OP parameter. Generate BFD_RELOC_MSP430_ABS_HI16 if vshift is 1. (msp430_srcoperand): Store vshift value in operand. * msp430.h (struct msp430_operand_s): Add vshift field. * gas/elf/struct.d: Expect extra output from some toolchains. * gas/symver/symver0.d: Likewise. * gas/symver/symver1.d: Likewise.
-rw-r--r--gas/ChangeLog6
-rw-r--r--gas/config/tc-msp430.c76
-rw-r--r--gas/testsuite/ChangeLog6
-rw-r--r--gas/testsuite/gas/elf/struct.d5
-rw-r--r--gas/testsuite/gas/symver/symver0.d1
-rw-r--r--gas/testsuite/gas/symver/symver1.d1
-rw-r--r--include/opcode/ChangeLog4
-rw-r--r--include/opcode/msp430.h3
8 files changed, 73 insertions, 29 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 26cef7f..f873e2b 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,9 @@
+2014-05-20 Nick Clifton <nickc@redhat.com>
+
+ * config/tc-msp430.c (CHECK_RELOC_MSP430): Add OP parameter.
+ Generate BFD_RELOC_MSP430_ABS_HI16 if vshift is 1.
+ (msp430_srcoperand): Store vshift value in operand.
+
2014-05-19 Nick Clifton <nickc@redhat.com>
PR gas/16858
diff --git a/gas/config/tc-msp430.c b/gas/config/tc-msp430.c
index 948117c..2db0fc0 100644
--- a/gas/config/tc-msp430.c
+++ b/gas/config/tc-msp430.c
@@ -278,16 +278,22 @@ target_is_430xv2 (void)
return selected_isa == MSP_ISA_430Xv2;
}
-/* 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.
+/* Generate an absolute 16-bit relocation.
+ For the 430X we generate a relocation without linker range checking
+ if the value is being used in an extended (ie 20-bit) instruction,
+ otherwise if have a shifted expression we use a HI reloc.
For the 430 we generate a relocation without assembler range checking
- if we are handling an immediate value or a byte-width instruction. */
+ if we are handling an immediate value or a byte-width instruction. */
+
#undef CHECK_RELOC_MSP430
-#define CHECK_RELOC_MSP430 \
- (target_is_430x () \
- ? (extended_op ? BFD_RELOC_16 : BFD_RELOC_MSP430X_ABS16) \
- : ((imm_op || byte_op) \
+#define CHECK_RELOC_MSP430(OP) \
+ (target_is_430x () \
+ ? (extended_op \
+ ? BFD_RELOC_16 \
+ : ((OP).vshift == 1) \
+ ? BFD_RELOC_MSP430_ABS_HI16 \
+ : BFD_RELOC_MSP430X_ABS16) \
+ : ((imm_op || byte_op) \
? BFD_RELOC_MSP430_16_BYTE : BFD_RELOC_MSP430_16))
/* Generate a 16-bit pc-relative relocation.
@@ -1038,7 +1044,7 @@ static int
msp430_srcoperand (struct msp430_operand_s * op,
char * l,
int bin,
- int * imm_op,
+ bfd_boolean * imm_op,
bfd_boolean allow_20bit_values,
bfd_boolean constants_allowed)
{
@@ -1058,7 +1064,7 @@ msp430_srcoperand (struct msp430_operand_s * op,
hhi(x) - x = (x >> 48) & 0xffff
The value _MUST_ be constant expression: #hlo(1231231231). */
- *imm_op = 1;
+ *imm_op = TRUE;
if (strncasecmp (h, "#llo(", 5) == 0)
{
@@ -1096,6 +1102,7 @@ msp430_srcoperand (struct msp430_operand_s * op,
op->ol = 1; /* Immediate will follow an instruction. */
__tl = h + 1 + rval;
op->mode = OP_EXP;
+ op->vshift = vshift;
parse_exp (__tl, &(op->exp));
if (op->exp.X_op == O_constant)
@@ -1111,6 +1118,7 @@ msp430_srcoperand (struct msp430_operand_s * op,
{
x = (x >> 16) & 0xffff;
op->exp.X_add_number = x;
+ op->vshift = 0;
}
else if (vshift > 1)
{
@@ -1119,6 +1127,7 @@ msp430_srcoperand (struct msp430_operand_s * op,
else
op->exp.X_add_number = 0; /* Nothing left. */
x = op->exp.X_add_number;
+ op->vshift = 0;
}
if (allow_20bit_values)
@@ -1208,6 +1217,8 @@ msp430_srcoperand (struct msp430_operand_s * op,
}
else if (op->exp.X_op == O_symbol)
{
+ if (vshift > 1)
+ as_bad (_("error: unsupported #foo() directive used on symbol"));
op->mode = OP_EXP;
}
else if (op->exp.X_op == O_big)
@@ -1219,6 +1230,7 @@ msp430_srcoperand (struct msp430_operand_s * op,
op->exp.X_op = O_constant;
op->exp.X_add_number = 0xffff & generic_bignum[vshift];
x = op->exp.X_add_number;
+ op->vshift = 0;
}
else
{
@@ -1292,6 +1304,7 @@ msp430_srcoperand (struct msp430_operand_s * op,
__tl = h + 1;
parse_exp (__tl, &(op->exp));
op->mode = OP_EXP;
+ op->vshift = 0;
if (op->exp.X_op == O_constant)
{
int x = op->exp.X_add_number;
@@ -1366,7 +1379,7 @@ msp430_srcoperand (struct msp430_operand_s * op,
char *m = strrchr (l, ')');
char *t;
- *imm_op = 1;
+ *imm_op = TRUE;
if (!h)
break;
@@ -1399,6 +1412,7 @@ msp430_srcoperand (struct msp430_operand_s * op,
__tl = l;
*h = 0;
op->mode = OP_EXP;
+ op->vshift = 0;
parse_exp (__tl, &(op->exp));
if (op->exp.X_op == O_constant)
{
@@ -1460,6 +1474,7 @@ msp430_srcoperand (struct msp430_operand_s * op,
/* An expression starting with a minus sign is a constant, not an address. */
op->am = (*l == '-' ? 3 : 1);
op->ol = 1;
+ op->vshift = 0;
__tl = l;
parse_exp (__tl, &(op->exp));
return 0;
@@ -1494,6 +1509,7 @@ msp430_dstoperand (struct msp430_operand_s * op,
op->mode = OP_EXP;
op->am = 1;
op->ol = 1;
+ op->vshift = 0;
parse_exp (__tl, &(op->exp));
if (op->exp.X_op != O_constant || op->exp.X_add_number != 0)
@@ -1791,7 +1807,7 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line)
struct msp430_operand_s op1, op2;
int res = 0;
static short ZEROS = 0;
- int byte_op, imm_op;
+ bfd_boolean byte_op, imm_op;
int op_length = 0;
int fmt;
int extended = 0x1800;
@@ -1808,7 +1824,7 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line)
or
.b @r2+, 5(R1). */
- byte_op = 0;
+ byte_op = FALSE;
addr_op = FALSE;
if (*line == '.')
{
@@ -1820,7 +1836,7 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line)
case 'b':
/* Byte operation. */
bin |= BYTE_OPERATION;
- byte_op = 1;
+ byte_op = TRUE;
check = TRUE;
break;
@@ -1902,7 +1918,7 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line)
memset (&op1, 0, sizeof (op1));
memset (&op2, 0, sizeof (op2));
- imm_op = 0;
+ imm_op = FALSE;
if ((fmt = opcode->fmt) < 0)
{
@@ -2073,7 +2089,7 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line)
{
if (op1.reg)
fix_new_exp (frag_now, where, 2,
- &(op1.exp), FALSE, CHECK_RELOC_MSP430);
+ &(op1.exp), FALSE, CHECK_RELOC_MSP430 (op1));
else
fix_new_exp (frag_now, where, 2,
&(op1.exp), TRUE, CHECK_RELOC_MSP430_PCREL);
@@ -2175,7 +2191,7 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line)
{
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);
+ &(op1.exp), FALSE, CHECK_RELOC_MSP430 (op1));
else
fix_new_exp (frag_now, where, 2,
&(op1.exp), TRUE, CHECK_RELOC_MSP430_PCREL);
@@ -2199,7 +2215,7 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line)
{
if (op2.reg) /* Not PC relative. */
fix_new_exp (frag_now, where, 2,
- &(op2.exp), FALSE, CHECK_RELOC_MSP430);
+ &(op2.exp), FALSE, CHECK_RELOC_MSP430 (op2));
else
fix_new_exp (frag_now, where, 2,
&(op2.exp), TRUE, CHECK_RELOC_MSP430_PCREL);
@@ -2223,8 +2239,8 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line)
if (res)
break;
- byte_op = 0;
- imm_op = 0;
+ byte_op = FALSE;
+ imm_op = FALSE;
bin |= ((op1.reg << 8) | (op1.am << 4));
op_length = 2 + 2 * op1.ol;
frag = frag_more (op_length);
@@ -2245,7 +2261,7 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line)
if (op1.reg || (op1.reg == 0 && op1.am == 3))
fix_new_exp (frag_now, where, 2,
- &(op1.exp), FALSE, CHECK_RELOC_MSP430);
+ &(op1.exp), FALSE, CHECK_RELOC_MSP430 (op1));
else
fix_new_exp (frag_now, where, 2,
&(op1.exp), TRUE, CHECK_RELOC_MSP430_PCREL);
@@ -2260,14 +2276,14 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line)
fix_emitted = FALSE;
line = extract_operand (line, l1, sizeof (l1));
- imm_op = 0;
+ imm_op = FALSE;
res = msp430_srcoperand (&op1, l1, opcode->bin_opcode, &imm_op,
extended_op, FALSE);
if (res)
break;
- byte_op = 0;
+ byte_op = FALSE;
op_length = 2 + 2 * op1.ol;
frag = frag_more (op_length);
@@ -2594,7 +2610,7 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line)
}
case 9: /* MOVA, BRA, RETA. */
- imm_op = 0;
+ imm_op = FALSE;
bin = opcode->bin_opcode;
if (is_opcode ("reta"))
@@ -2819,7 +2835,7 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line)
{
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);
+ &(op1.exp), FALSE, CHECK_RELOC_MSP430 (op1));
else
fix_new_exp (frag_now, where, 2,
&(op1.exp), TRUE, CHECK_RELOC_MSP430_PCREL);
@@ -2844,7 +2860,7 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line)
{
if (op2.reg) /* Not PC relative. */
fix_new_exp (frag_now, where, 2,
- &(op2.exp), FALSE, CHECK_RELOC_MSP430);
+ &(op2.exp), FALSE, CHECK_RELOC_MSP430 (op2));
else
fix_new_exp (frag_now, where, 2,
&(op2.exp), TRUE, CHECK_RELOC_MSP430_PCREL);
@@ -2952,7 +2968,7 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line)
{
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);
+ &(op1.exp), FALSE, CHECK_RELOC_MSP430 (op1));
else
fix_new_exp (frag_now, where, 2,
&(op1.exp), TRUE, CHECK_RELOC_MSP430_PCREL);
@@ -3352,6 +3368,12 @@ md_apply_fix (fixS * fixp, valueT * valuep, segT seg)
bfd_putl16 ((bfd_vma) value, where);
break;
+ case BFD_RELOC_MSP430_ABS_HI16:
+ value >>= 16;
+ value &= 0xffff; /* Get rid of extended sign. */
+ bfd_putl16 ((bfd_vma) value, where);
+ break;
+
case BFD_RELOC_32:
bfd_putl16 ((bfd_vma) value, where);
break;
diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog
index db8eb2e..a9c1a8a 100644
--- a/gas/testsuite/ChangeLog
+++ b/gas/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2014-05-20 Nick Clifton <nickc@redhat.com>
+
+ * gas/elf/struct.d: Expect extra output from some toolchains.
+ * gas/symver/symver0.d: Likewise.
+ * gas/symver/symver1.d: Likewise.
+
2014-05-09 H.J. Lu <hongjiu.lu@intel.com>
* gas/i386/nops-1-core2.d: Replace data32 with data16.
diff --git a/gas/testsuite/gas/elf/struct.d b/gas/testsuite/gas/elf/struct.d
index 420c6e5..dac6b56 100644
--- a/gas/testsuite/gas/elf/struct.d
+++ b/gas/testsuite/gas/elf/struct.d
@@ -1,8 +1,11 @@
#nm: --extern-only
#name: ELF struct
-
+#
# Test the .struct pseudo-op.
+# The #... is there to match extra symbols inserted by
+# some toolchains, eg msp430-elf will add _crt0_movedata.
+#...
0+0 D l1
0+4 D l2
0+2 A w1
diff --git a/gas/testsuite/gas/symver/symver0.d b/gas/testsuite/gas/symver/symver0.d
index 9ad6c88..c7accc7 100644
--- a/gas/testsuite/gas/symver/symver0.d
+++ b/gas/testsuite/gas/symver/symver0.d
@@ -4,6 +4,7 @@
# The #... and #pass are there to match extra symbols inserted by
# some toolchains, eg arm-elf toolchain will add $d.
+#...
[ ]+U foo@version1
#...
0+0000000 D foo1
diff --git a/gas/testsuite/gas/symver/symver1.d b/gas/testsuite/gas/symver/symver1.d
index ab9b949..b480e37 100644
--- a/gas/testsuite/gas/symver/symver1.d
+++ b/gas/testsuite/gas/symver/symver1.d
@@ -4,6 +4,7 @@
# The #... and #pass are there to match extra symbols inserted by
# some toolchains, eg arm-elf toolchain will add $d.
+#...
[ ]+U foo@version1
#...
0+0000000 D foo1@@version1
diff --git a/include/opcode/ChangeLog b/include/opcode/ChangeLog
index e76a4fd..754933b 100644
--- a/include/opcode/ChangeLog
+++ b/include/opcode/ChangeLog
@@ -1,3 +1,7 @@
+2014-05-19 Nick Clifton <nickc@redhat.com>
+
+ * msp430.h (struct msp430_operand_s): Add vshift field.
+
2014-05-07 Andrew Bennett <andrew.bennett@imgtec.com>
* mips.h (INSN_ISA_MASK): Updated.
diff --git a/include/opcode/msp430.h b/include/opcode/msp430.h
index 910565c..0e73815 100644
--- a/include/opcode/msp430.h
+++ b/include/opcode/msp430.h
@@ -26,7 +26,8 @@ struct msp430_operand_s
int ol; /* Operand length words. */
int am; /* Addr mode. */
int reg; /* Register. */
- int mode; /* Pperand mode. */
+ int mode; /* Operand mode. */
+ int vshift; /* Number of bytes to shift operand down. */
#define OP_REG 0
#define OP_EXP 1
#ifndef DASM_SECTION