diff options
author | Nick Clifton <nickc@redhat.com> | 2005-05-17 11:56:13 +0000 |
---|---|---|
committer | Nick Clifton <nickc@redhat.com> | 2005-05-17 11:56:13 +0000 |
commit | 2d034539b1365c8d25be0be70c16c84c9288a088 (patch) | |
tree | 10737f73c49a538017c9dc13e3eca58af13d5514 /gas/config | |
parent | 641bd09305df4cd893788b2b10b3aa5bced813ac (diff) | |
download | gdb-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.c | 48 | ||||
-rw-r--r-- | gas/config/tc-v850.h | 5 |
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 |