aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Clifton <nickc@redhat.com>2005-05-17 11:56:13 +0000
committerNick Clifton <nickc@redhat.com>2005-05-17 11:56:13 +0000
commit2d034539b1365c8d25be0be70c16c84c9288a088 (patch)
tree10737f73c49a538017c9dc13e3eca58af13d5514
parent641bd09305df4cd893788b2b10b3aa5bced813ac (diff)
downloadgdb-2d034539b1365c8d25be0be70c16c84c9288a088.zip
gdb-2d034539b1365c8d25be0be70c16c84c9288a088.tar.gz
gdb-2d034539b1365c8d25be0be70c16c84c9288a088.tar.bz2
* config/tc-v850,h (TC_FIX_TYPE): Define. (TC_INIT_FIX_TYPE): Define.
* config/tc-v850.c (md_assemble): When creating a fix record the operand in the tc_fix_data field. (md_apply_fix3): When applying a resolved fix use the operand's insertion procedure to store the value, if the operand has been recorded. * gas/v850/split-lo16.s: Add test for a lo() pseudo reloc corrupting an ld.w instruction. * gas/v850/split-lo16.d: Add expected, correct (ie not corrupt) output.
-rw-r--r--gas/ChangeLog10
-rw-r--r--gas/config/tc-v850.c48
-rw-r--r--gas/config/tc-v850.h5
-rw-r--r--gas/symbols.c26
-rw-r--r--gas/testsuite/ChangeLog7
-rw-r--r--gas/testsuite/gas/v850/split-lo16.d2
-rw-r--r--gas/testsuite/gas/v850/split-lo16.s3
7 files changed, 83 insertions, 18 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 67a4a1e..df1def0 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,13 @@
+2005-05-17 Nick Clifton <nickc@redhat.com>
+
+ * config/tc-v850,h (TC_FIX_TYPE): Define.
+ (TC_INIT_FIX_TYPE): Define.
+ * config/tc-v850.c (md_assemble): When creating a fix record the
+ operand in the tc_fix_data field.
+ (md_apply_fix3): When applying a resolved fix use the operand's
+ insertion procedure to store the value, if the operand has been
+ recorded.
+
2005-05-15 Daniel Jacobowitz <dan@codesourcery.com>
* Makefile.am (m68k-parse.c, itbl-parse.c): Update ylwrap
diff --git a/gas/config/tc-v850.c b/gas/config/tc-v850.c
index 33eef58..1828396 100644
--- a/gas/config/tc-v850.c
+++ b/gas/config/tc-v850.c
@@ -2125,6 +2125,8 @@ md_assemble (char *str)
reloc_howto->pc_relative,
reloc);
+ fixP->tc_fix_data = (void *) operand;
+
switch (reloc)
{
case BFD_RELOC_LO16:
@@ -2319,16 +2321,42 @@ md_apply_fix3 (fixS *fixP, valueT *valueP, segT seg ATTRIBUTE_UNUSED)
/* We still have to insert the value into memory! */
where = fixP->fx_frag->fr_literal + fixP->fx_where;
- if (fixP->fx_r_type == BFD_RELOC_V850_LO16_SPLIT_OFFSET)
- bfd_putl32 (((value << 16) & 0xfffe0000)
- | ((value << 5) & 0x20)
- | (bfd_getl32 (where) & ~0xfffe0020), where);
- else if (fixP->fx_size == 1)
- *where = value & 0xff;
- else if (fixP->fx_size == 2)
- bfd_putl16 (value & 0xffff, (unsigned char *) where);
- else if (fixP->fx_size == 4)
- bfd_putl32 (value, (unsigned char *) where);
+ if (fixP->tc_fix_data != NULL)
+ {
+ struct v850_operand * operand = (struct v850_operand *) fixP->tc_fix_data;
+ unsigned long insn;
+
+ /* The variable "where" currently points at the exact point inside
+ the insn where we need to insert the value. But we need to
+ extract the entire insn so we probably need to move "where"
+ back a few bytes. */
+ if (fixP->fx_size == 2)
+ where -= 2;
+ else if (fixP->fx_size == 1)
+ where -= 3;
+
+ insn = bfd_getl32 ((unsigned char *) where);
+
+ /* Use the operand's insertion procedure, if present, in order to
+ make sure that the value is correctly stored in the insn. */
+ insn = v850_insert_operand (insn, operand, (offsetT) value,
+ fixP->fx_file, fixP->fx_line, NULL);
+
+ bfd_putl32 ((bfd_vma) insn, (unsigned char *) where);
+ }
+ else
+ {
+ if (fixP->fx_r_type == BFD_RELOC_V850_LO16_SPLIT_OFFSET)
+ bfd_putl32 (((value << 16) & 0xfffe0000)
+ | ((value << 5) & 0x20)
+ | (bfd_getl32 (where) & ~0xfffe0020), where);
+ else if (fixP->fx_size == 1)
+ *where = value & 0xff;
+ else if (fixP->fx_size == 2)
+ bfd_putl16 (value & 0xffff, (unsigned char *) where);
+ else if (fixP->fx_size == 4)
+ bfd_putl32 (value, (unsigned char *) where);
+ }
}
}
diff --git a/gas/config/tc-v850.h b/gas/config/tc-v850.h
index 5db1141..4dd3c7e 100644
--- a/gas/config/tc-v850.h
+++ b/gas/config/tc-v850.h
@@ -78,3 +78,8 @@ extern void v850_handle_align (fragS *);
extern long v850_pcrel_from_section (struct fix *, asection *);
#define DWARF2_LINE_MIN_INSN_LENGTH 2
+
+/* We need to record the operand involved when a pseudo-reloc is
+ processed so that the resulting value can be inserted correctly. */
+#define TC_FIX_TYPE void *
+#define TC_INIT_FIX_DATA(fixP) (fixP)->tc_fix_data = NULL
diff --git a/gas/symbols.c b/gas/symbols.c
index 5341c6a..ebcad5b 100644
--- a/gas/symbols.c
+++ b/gas/symbols.c
@@ -906,6 +906,7 @@ resolve_symbol_value (symbolS *symp)
offsetT left, right;
segT seg_left, seg_right;
operatorT op;
+ int move_seg_ok;
symp->sy_resolving = 1;
@@ -1091,18 +1092,15 @@ resolve_symbol_value (symbolS *symp)
}
}
+ move_seg_ok = 1;
/* Equality and non-equality tests are permitted on anything.
Subtraction, and other comparison operators are permitted if
both operands are in the same section. Otherwise, both
operands must be absolute. We already handled the case of
addition or subtraction of a constant above. This will
probably need to be changed for an object file format which
- supports arbitrary expressions, such as IEEE-695.
-
- Don't emit messages unless we're finalizing the symbol value,
- otherwise we may get the same message multiple times. */
- if (finalize_syms
- && !(seg_left == absolute_section
+ supports arbitrary expressions, such as IEEE-695. */
+ if (!(seg_left == absolute_section
&& seg_right == absolute_section)
&& !(op == O_eq || op == O_ne)
&& !((op == O_subtract
@@ -1110,9 +1108,21 @@ resolve_symbol_value (symbolS *symp)
&& seg_left == seg_right
&& (seg_left != undefined_section
|| add_symbol == op_symbol)))
- report_op_error (symp, add_symbol, op_symbol);
+ {
+ /* Don't emit messages unless we're finalizing the symbol value,
+ otherwise we may get the same message multiple times. */
+ if (finalize_syms)
+ report_op_error (symp, add_symbol, op_symbol);
+ /* However do not move the symbol into the absolute section
+ if it cannot currently be resolved - this would confuse
+ other parts of the assembler into believing that the
+ expression had been evaluated to zero. */
+ else
+ move_seg_ok = 0;
+ }
- if (final_seg == expr_section || final_seg == undefined_section)
+ if (move_seg_ok
+ && (final_seg == expr_section || final_seg == undefined_section))
final_seg = absolute_section;
/* Check for division by zero. */
diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog
index d221045..4322c26 100644
--- a/gas/testsuite/ChangeLog
+++ b/gas/testsuite/ChangeLog
@@ -1,3 +1,10 @@
+2005-05-17 Nick Clifton <nickc@redhat.com>
+
+ * gas/v850/split-lo16.s: Add test for a lo() pseudo reloc
+ corrupting an ld.w instruction.
+ * gas/v850/split-lo16.d: Add expected, correct (ie not corrupt)
+ output.
+
2005-05-10 Michael Matz <matz@suse.de>
* gas/hppa/parse/block1.s: Use official limit (0x3fffffff) for
diff --git a/gas/testsuite/gas/v850/split-lo16.d b/gas/testsuite/gas/v850/split-lo16.d
index 9503ac9..5ed195c 100644
--- a/gas/testsuite/gas/v850/split-lo16.d
+++ b/gas/testsuite/gas/v850/split-lo16.d
@@ -13,4 +13,6 @@
c: R_V850_LO16_SPLIT_OFFSET foo
10: a1 17 45 23 ld\.bu 9029\[r1\],r2
14: 81 17 57 34 ld\.bu 13398\[r1\],r2
+ 18: 20 57 01 00 ld.w 0\[r0\],r10
+ 1c: 20 57 79 56 ld.w 22136\[r0\],r10
#pass
diff --git a/gas/testsuite/gas/v850/split-lo16.s b/gas/testsuite/gas/v850/split-lo16.s
index fc3afd1..bb6fb66 100644
--- a/gas/testsuite/gas/v850/split-lo16.s
+++ b/gas/testsuite/gas/v850/split-lo16.s
@@ -5,3 +5,6 @@
ld.bu lo(0x12345),r1,r2
ld.bu lo(0x123456),r1,r2
+
+ ld.w lo(0)[r0], r10
+ ld.w lo(0x12345678)[r0], r10