aboutsummaryrefslogtreecommitdiff
path: root/gas/config
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 /gas/config
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.
Diffstat (limited to 'gas/config')
-rw-r--r--gas/config/tc-v850.c48
-rw-r--r--gas/config/tc-v850.h5
2 files changed, 43 insertions, 10 deletions
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