[committed] Fix handling of lo16() in v850e ld.bu instructions
Richard Sandiford
rsandifo@redhat.com
Thu Dec 16 17:02:00 GMT 2004
The lo16() in the following v850e instruction:
ld.bu lo(foo)[rn],rm
produces an R_V850_LO16 relocation. That doesn't work because the
ld.bu offset is split into two separate fields, one for the high 15
bits and one for the low bit.
This patch adds a new relocation, R_V850_LO16_SPLIT_OFFSET, which works
in a similar way to the existing R_V850_[STZ]DA_16_16_SPLIT_OFFSET relocs.
Tested against the v850-elf testsuite (binutils & gcc). Approved off-line
by Nick and applied.
Richard
include/elf/
* v850.h (R_V850_LO16_SPLIT_OFFSET): New reloc.
bfd/
* reloc.c (BFD_RELOC_V850_LO16_SPLIT_OFFSET): New bfd_reloc_code_type.
* elf32-v850.c (v850_elf_howto_table): Add entry for
R_V850_LO16_SPLIT_OFFSET.
(v850_elf_reloc_map): Map it to BFD_RELOC_V850_LO16_SPLIT_OFFSET.
(v850_elf_perform_lo16_relocation): New function, extracted from...
(v850_elf_perform_relocation): ...here. Use it to handle
R_V850_LO16_SPLIT_OFFSET.
(v850_elf_check_relocs, v850_elf_final_link_relocate): Handle
R_V850_LO16_SPLIT_OFFSET.
* libbfd.h, bfd-in2.h: Regenerate.
gas/
* config/tc-v850.c (handle_lo16): New function.
(v850_reloc_prefix): Use it to check lo().
(md_assemble, md_apply_fix3): Handle BFD_RELOC_V850_LO16_SPLIT_OFFSET.
gas/testsuite/
* gas/v850/split-lo16.{s,d}: New test.
* gas/v850/v850.exp: Run it.
ld/testsuite/
* ld-v850: New directory.
Index: include/elf/v850.h
===================================================================
RCS file: /cvs/src/src/include/elf/v850.h,v
retrieving revision 1.9
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.9 v850.h
*** include/elf/v850.h 4 Sep 2003 11:04:37 -0000 1.9
--- include/elf/v850.h 16 Dec 2004 16:25:27 -0000
*************** START_RELOC_NUMBERS (v850_reloc_type)
*** 79,84 ****
--- 79,85 ----
RELOC_NUMBER (R_V850_LONGJUMP, 26)
RELOC_NUMBER (R_V850_ALIGN, 27)
RELOC_NUMBER (R_V850_REL32, 28)
+ RELOC_NUMBER (R_V850_LO16_SPLIT_OFFSET, 29) /* For ld.bu */
END_RELOC_NUMBERS (R_V850_max)
Index: bfd/reloc.c
===================================================================
RCS file: /cvs/src/src/bfd/reloc.c,v
retrieving revision 1.117
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.117 reloc.c
*** bfd/reloc.c 4 Nov 2004 14:57:44 -0000 1.117
--- bfd/reloc.c 16 Dec 2004 16:25:28 -0000
*************** ENUM
*** 3099,3104 ****
--- 3099,3109 ----
ENUMDOC
Used to maintain alignment whilst relaxing.
ENUM
+ BFD_RELOC_V850_LO16_SPLIT_OFFSET
+ ENUMDOC
+ This is a variation of BFD_RELOC_LO16 that can be used in v850e ld.bu
+ instructions.
+ ENUM
BFD_RELOC_MN10300_32_PCREL
ENUMDOC
This is a 32bit pcrel reloc for the mn10300, offset by two bytes in the
Index: bfd/elf32-v850.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-v850.c,v
retrieving revision 1.47
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.47 elf32-v850.c
*** bfd/elf32-v850.c 21 Oct 2004 15:28:25 -0000 1.47
--- bfd/elf32-v850.c 16 Dec 2004 16:25:29 -0000
*************** static reloc_howto_type v850_elf_howto_t
*** 533,538 ****
--- 533,553 ----
0xffffffff, /* src_mask */
0xffffffff, /* dst_mask */
FALSE), /* pcrel_offset */
+
+ /* An ld.bu version of R_V850_LO16. */
+ HOWTO (R_V850_LO16_SPLIT_OFFSET, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ v850_elf_reloc, /* special_function */
+ "R_V850_LO16_SPLIT_OFFSET", /* name */
+ FALSE, /* partial_inplace */
+ 0xfffe0020, /* src_mask */
+ 0xfffe0020, /* dst_mask */
+ FALSE), /* pcrel_offset */
};
/* Map BFD reloc types to V850 ELF reloc types. */
*************** static const struct v850_elf_reloc_map v
*** 567,572 ****
--- 582,588 ----
{ BFD_RELOC_V850_TDA_16_16_OFFSET, R_V850_TDA_16_16_OFFSET },
{ BFD_RELOC_V850_TDA_4_5_OFFSET, R_V850_TDA_4_5_OFFSET },
{ BFD_RELOC_V850_TDA_4_4_OFFSET, R_V850_TDA_4_4_OFFSET },
+ { BFD_RELOC_V850_LO16_SPLIT_OFFSET, R_V850_LO16_SPLIT_OFFSET },
{ BFD_RELOC_V850_SDA_16_16_SPLIT_OFFSET, R_V850_SDA_16_16_SPLIT_OFFSET },
{ BFD_RELOC_V850_ZDA_16_16_SPLIT_OFFSET, R_V850_ZDA_16_16_SPLIT_OFFSET },
{ BFD_RELOC_V850_CALLT_6_7_OFFSET, R_V850_CALLT_6_7_OFFSET },
*************** v850_elf_check_relocs (abfd, info, sec,
*** 687,692 ****
--- 703,709 ----
case R_V850_HI16_S:
case R_V850_HI16:
case R_V850_LO16:
+ case R_V850_LO16_SPLIT_OFFSET:
case R_V850_ABS32:
case R_V850_REL32:
case R_V850_16:
*************** find_remembered_hi16s_reloc (addend, alr
*** 902,907 ****
--- 919,1103 ----
return addr;
}
+ /* Calculate the sum of the value stored in the instruction and the
+ addend and check for overflow from the low 16 bits into the high
+ 16 bits. The assembler has already done some of this: If the
+ value stored in the instruction has its 15th bit set, (counting
+ from zero) then the assembler will have added 1 to the value
+ stored in the associated HI16S reloc. So for example, these
+ relocations:
+
+ movhi hi( fred ), r0, r1
+ movea lo( fred ), r1, r1
+
+ will store 0 in the value fields for the MOVHI and MOVEA instructions
+ and addend will be the address of fred, but for these instructions:
+
+ movhi hi( fred + 0x123456), r0, r1
+ movea lo( fred + 0x123456), r1, r1
+
+ the value stored in the MOVHI instruction will be 0x12 and the value
+ stored in the MOVEA instruction will be 0x3456. If however the
+ instructions were:
+
+ movhi hi( fred + 0x10ffff), r0, r1
+ movea lo( fred + 0x10ffff), r1, r1
+
+ then the value stored in the MOVHI instruction would be 0x11 (not
+ 0x10) and the value stored in the MOVEA instruction would be 0xffff.
+ Thus (assuming for the moment that the addend is 0), at run time the
+ MOVHI instruction loads 0x110000 into r1, then the MOVEA instruction
+ adds 0xffffffff (sign extension!) producing 0x10ffff. Similarly if
+ the instructions were:
+
+ movhi hi( fred - 1), r0, r1
+ movea lo( fred - 1), r1, r1
+
+ then 0 is stored in the MOVHI instruction and -1 is stored in the
+ MOVEA instruction.
+
+ Overflow can occur if the addition of the value stored in the
+ instruction plus the addend sets the 15th bit when before it was clear.
+ This is because the 15th bit will be sign extended into the high part,
+ thus reducing its value by one, but since the 15th bit was originally
+ clear, the assembler will not have added 1 to the previous HI16S reloc
+ to compensate for this effect. For example:
+
+ movhi hi( fred + 0x123456), r0, r1
+ movea lo( fred + 0x123456), r1, r1
+
+ The value stored in HI16S reloc is 0x12, the value stored in the LO16
+ reloc is 0x3456. If we assume that the address of fred is 0x00007000
+ then the relocations become:
+
+ HI16S: 0x0012 + (0x00007000 >> 16) = 0x12
+ LO16: 0x3456 + (0x00007000 & 0xffff) = 0xa456
+
+ but when the instructions are executed, the MOVEA instruction's value
+ is signed extended, so the sum becomes:
+
+ 0x00120000
+ + 0xffffa456
+ ------------
+ 0x0011a456 but 'fred + 0x123456' = 0x0012a456
+
+ Note that if the 15th bit was set in the value stored in the LO16
+ reloc, then we do not have to do anything:
+
+ movhi hi( fred + 0x10ffff), r0, r1
+ movea lo( fred + 0x10ffff), r1, r1
+
+ HI16S: 0x0011 + (0x00007000 >> 16) = 0x11
+ LO16: 0xffff + (0x00007000 & 0xffff) = 0x6fff
+
+ 0x00110000
+ + 0x00006fff
+ ------------
+ 0x00116fff = fred + 0x10ffff = 0x7000 + 0x10ffff
+
+ Overflow can also occur if the computation carries into the 16th bit
+ and it also results in the 15th bit having the same value as the 15th
+ bit of the original value. What happens is that the HI16S reloc
+ will have already examined the 15th bit of the original value and
+ added 1 to the high part if the bit is set. This compensates for the
+ sign extension of 15th bit of the result of the computation. But now
+ there is a carry into the 16th bit, and this has not been allowed for.
+
+ So, for example if fred is at address 0xf000:
+
+ movhi hi( fred + 0xffff), r0, r1 [bit 15 of the offset is set]
+ movea lo( fred + 0xffff), r1, r1
+
+ HI16S: 0x0001 + (0x0000f000 >> 16) = 0x0001
+ LO16: 0xffff + (0x0000f000 & 0xffff) = 0xefff (carry into bit 16 is lost)
+
+ 0x00010000
+ + 0xffffefff
+ ------------
+ 0x0000efff but 'fred + 0xffff' = 0x0001efff
+
+ Similarly, if the 15th bit remains clear, but overflow occurs into
+ the 16th bit then (assuming the address of fred is 0xf000):
+
+ movhi hi( fred + 0x7000), r0, r1 [bit 15 of the offset is clear]
+ movea lo( fred + 0x7000), r1, r1
+
+ HI16S: 0x0000 + (0x0000f000 >> 16) = 0x0000
+ LO16: 0x7000 + (0x0000f000 & 0xffff) = 0x6fff (carry into bit 16 is lost)
+
+ 0x00000000
+ + 0x00006fff
+ ------------
+ 0x00006fff but 'fred + 0x7000' = 0x00016fff
+
+ Note - there is no need to change anything if a carry occurs, and the
+ 15th bit changes its value from being set to being clear, as the HI16S
+ reloc will have already added in 1 to the high part for us:
+
+ movhi hi( fred + 0xffff), r0, r1 [bit 15 of the offset is set]
+ movea lo( fred + 0xffff), r1, r1
+
+ HI16S: 0x0001 + (0x00007000 >> 16)
+ LO16: 0xffff + (0x00007000 & 0xffff) = 0x6fff (carry into bit 16 is lost)
+
+ 0x00010000
+ + 0x00006fff (bit 15 not set, so the top half is zero)
+ ------------
+ 0x00016fff which is right (assuming that fred is at 0x7000)
+
+ but if the 15th bit goes from being clear to being set, then we must
+ once again handle overflow:
+
+ movhi hi( fred + 0x7000), r0, r1 [bit 15 of the offset is clear]
+ movea lo( fred + 0x7000), r1, r1
+
+ HI16S: 0x0000 + (0x0000ffff >> 16)
+ LO16: 0x7000 + (0x0000ffff & 0xffff) = 0x6fff (carry into bit 16)
+
+ 0x00000000
+ + 0x00006fff (bit 15 not set, so the top half is zero)
+ ------------
+ 0x00006fff which is wrong (assuming that fred is at 0xffff). */
+
+ static bfd_boolean
+ v850_elf_perform_lo16_relocation (bfd *abfd, unsigned long *insn,
+ unsigned long addend)
+ {
+ #define BIT15_SET(x) ((x) & 0x8000)
+ #define OVERFLOWS(a,i) ((((a) & 0xffff) + (i)) > 0xffff)
+ if ((BIT15_SET (*insn + addend) && ! BIT15_SET (addend))
+ || (OVERFLOWS (addend, *insn)
+ && ((! BIT15_SET (*insn)) || (BIT15_SET (addend)))))
+ {
+ bfd_boolean already_updated;
+ bfd_byte *hi16s_address = find_remembered_hi16s_reloc
+ (addend, & already_updated);
+
+ /* Amend the matching HI16_S relocation. */
+ if (hi16s_address != NULL)
+ {
+ if (! already_updated)
+ {
+ unsigned long hi_insn = bfd_get_16 (abfd, hi16s_address);
+ hi_insn += 1;
+ bfd_put_16 (abfd, hi_insn, hi16s_address);
+ }
+ }
+ else
+ {
+ fprintf (stderr, _("FAILED to find previous HI16 reloc\n"));
+ return FALSE;
+ }
+ }
+ #undef OVERFLOWS
+ #undef BIT15_SET
+
+ /* Do not complain if value has top bit set, as this has been
+ anticipated. */
+ *insn = (*insn + addend) & 0xffff;
+ return TRUE;
+ }
+
/* FIXME: The code here probably ought to be removed and the code in reloc.c
allowed to do its stuff instead. At least for most of the relocs, anyway. */
*************** v850_elf_perform_relocation (abfd, r_typ
*** 913,918 ****
--- 1109,1115 ----
bfd_byte *address;
{
unsigned long insn;
+ unsigned long result;
bfd_signed_vma saddend = (bfd_signed_vma) addend;
switch (r_type)
*************** v850_elf_perform_relocation (abfd, r_typ
*** 972,1154 ****
break;
case R_V850_LO16:
! /* Calculate the sum of the value stored in the instruction and the
! addend and check for overflow from the low 16 bits into the high
! 16 bits. The assembler has already done some of this: If the
! value stored in the instruction has its 15th bit set, (counting
! from zero) then the assembler will have added 1 to the value
! stored in the associated HI16S reloc. So for example, these
! relocations:
!
! movhi hi( fred ), r0, r1
! movea lo( fred ), r1, r1
!
! will store 0 in the value fields for the MOVHI and MOVEA instructions
! and addend will be the address of fred, but for these instructions:
!
! movhi hi( fred + 0x123456), r0, r1
! movea lo( fred + 0x123456), r1, r1
!
! the value stored in the MOVHI instruction will be 0x12 and the value
! stored in the MOVEA instruction will be 0x3456. If however the
! instructions were:
!
! movhi hi( fred + 0x10ffff), r0, r1
! movea lo( fred + 0x10ffff), r1, r1
!
! then the value stored in the MOVHI instruction would be 0x11 (not
! 0x10) and the value stored in the MOVEA instruction would be 0xffff.
! Thus (assuming for the moment that the addend is 0), at run time the
! MOVHI instruction loads 0x110000 into r1, then the MOVEA instruction
! adds 0xffffffff (sign extension!) producing 0x10ffff. Similarly if
! the instructions were:
!
! movhi hi( fred - 1), r0, r1
! movea lo( fred - 1), r1, r1
!
! then 0 is stored in the MOVHI instruction and -1 is stored in the
! MOVEA instruction.
!
! Overflow can occur if the addition of the value stored in the
! instruction plus the addend sets the 15th bit when before it was clear.
! This is because the 15th bit will be sign extended into the high part,
! thus reducing its value by one, but since the 15th bit was originally
! clear, the assembler will not have added 1 to the previous HI16S reloc
! to compensate for this effect. For example:
!
! movhi hi( fred + 0x123456), r0, r1
! movea lo( fred + 0x123456), r1, r1
!
! The value stored in HI16S reloc is 0x12, the value stored in the LO16
! reloc is 0x3456. If we assume that the address of fred is 0x00007000
! then the relocations become:
!
! HI16S: 0x0012 + (0x00007000 >> 16) = 0x12
! LO16: 0x3456 + (0x00007000 & 0xffff) = 0xa456
!
! but when the instructions are executed, the MOVEA instruction's value
! is signed extended, so the sum becomes:
!
! 0x00120000
! + 0xffffa456
! ------------
! 0x0011a456 but 'fred + 0x123456' = 0x0012a456
!
! Note that if the 15th bit was set in the value stored in the LO16
! reloc, then we do not have to do anything:
!
! movhi hi( fred + 0x10ffff), r0, r1
! movea lo( fred + 0x10ffff), r1, r1
!
! HI16S: 0x0011 + (0x00007000 >> 16) = 0x11
! LO16: 0xffff + (0x00007000 & 0xffff) = 0x6fff
!
! 0x00110000
! + 0x00006fff
! ------------
! 0x00116fff = fred + 0x10ffff = 0x7000 + 0x10ffff
!
! Overflow can also occur if the computation carries into the 16th bit
! and it also results in the 15th bit having the same value as the 15th
! bit of the original value. What happens is that the HI16S reloc
! will have already examined the 15th bit of the original value and
! added 1 to the high part if the bit is set. This compensates for the
! sign extension of 15th bit of the result of the computation. But now
! there is a carry into the 16th bit, and this has not been allowed for.
!
! So, for example if fred is at address 0xf000:
!
! movhi hi( fred + 0xffff), r0, r1 [bit 15 of the offset is set]
! movea lo( fred + 0xffff), r1, r1
!
! HI16S: 0x0001 + (0x0000f000 >> 16) = 0x0001
! LO16: 0xffff + (0x0000f000 & 0xffff) = 0xefff (carry into bit 16 is lost)
!
! 0x00010000
! + 0xffffefff
! ------------
! 0x0000efff but 'fred + 0xffff' = 0x0001efff
!
! Similarly, if the 15th bit remains clear, but overflow occurs into
! the 16th bit then (assuming the address of fred is 0xf000):
!
! movhi hi( fred + 0x7000), r0, r1 [bit 15 of the offset is clear]
! movea lo( fred + 0x7000), r1, r1
!
! HI16S: 0x0000 + (0x0000f000 >> 16) = 0x0000
! LO16: 0x7000 + (0x0000f000 & 0xffff) = 0x6fff (carry into bit 16 is lost)
!
! 0x00000000
! + 0x00006fff
! ------------
! 0x00006fff but 'fred + 0x7000' = 0x00016fff
!
! Note - there is no need to change anything if a carry occurs, and the
! 15th bit changes its value from being set to being clear, as the HI16S
! reloc will have already added in 1 to the high part for us:
!
! movhi hi( fred + 0xffff), r0, r1 [bit 15 of the offset is set]
! movea lo( fred + 0xffff), r1, r1
!
! HI16S: 0x0001 + (0x00007000 >> 16)
! LO16: 0xffff + (0x00007000 & 0xffff) = 0x6fff (carry into bit 16 is lost)
!
! 0x00010000
! + 0x00006fff (bit 15 not set, so the top half is zero)
! ------------
! 0x00016fff which is right (assuming that fred is at 0x7000)
!
! but if the 15th bit goes from being clear to being set, then we must
! once again handle overflow:
!
! movhi hi( fred + 0x7000), r0, r1 [bit 15 of the offset is clear]
! movea lo( fred + 0x7000), r1, r1
!
! HI16S: 0x0000 + (0x0000ffff >> 16)
! LO16: 0x7000 + (0x0000ffff & 0xffff) = 0x6fff (carry into bit 16)
!
! 0x00000000
! + 0x00006fff (bit 15 not set, so the top half is zero)
! ------------
! 0x00006fff which is wrong (assuming that fred is at 0xffff). */
! {
! long result;
!
! insn = bfd_get_16 (abfd, address);
! result = insn + addend;
!
! #define BIT15_SET(x) ((x) & 0x8000)
! #define OVERFLOWS(a,i) ((((a) & 0xffff) + (i)) > 0xffff)
!
! if ((BIT15_SET (result) && ! BIT15_SET (addend))
! || (OVERFLOWS (addend, insn)
! && ((! BIT15_SET (insn)) || (BIT15_SET (addend)))))
! {
! bfd_boolean already_updated;
! bfd_byte *hi16s_address = find_remembered_hi16s_reloc
! (addend, & already_updated);
!
! /* Amend the matching HI16_S relocation. */
! if (hi16s_address != NULL)
! {
! if (! already_updated)
! {
! insn = bfd_get_16 (abfd, hi16s_address);
! insn += 1;
! bfd_put_16 (abfd, (bfd_vma) insn, hi16s_address);
! }
! }
! else
! {
! fprintf (stderr, _("FAILED to find previous HI16 reloc\n"));
! return bfd_reloc_overflow;
! }
! }
!
! /* Do not complain if value has top bit set, as this has been anticipated. */
! insn = result & 0xffff;
! break;
! }
case R_V850_8:
addend += (char) bfd_get_8 (abfd, address);
--- 1169,1178 ----
break;
case R_V850_LO16:
! insn = bfd_get_16 (abfd, address);
! if (! v850_elf_perform_lo16_relocation (abfd, &insn, addend))
! return bfd_reloc_overflow;
! break;
case R_V850_8:
addend += (char) bfd_get_8 (abfd, address);
*************** #define OVERFLOWS(a,i) ((((a) & 0xffff)
*** 1278,1283 ****
--- 1302,1318 ----
insn |= addend;
break;
+ case R_V850_LO16_SPLIT_OFFSET:
+ insn = bfd_get_32 (abfd, address);
+ result = ((insn & 0xfffe0000) >> 16) | ((insn & 0x20) >> 5);
+ if (! v850_elf_perform_lo16_relocation (abfd, &result, addend))
+ return bfd_reloc_overflow;
+ insn = (((result << 16) & 0xfffe0000)
+ | ((result << 5) & 0x20)
+ | (insn & ~0xfffe0020));
+ bfd_put_32 (abfd, insn, address);
+ return bfd_reloc_ok;
+
case R_V850_ZDA_16_16_SPLIT_OFFSET:
case R_V850_SDA_16_16_SPLIT_OFFSET:
insn = bfd_get_32 (abfd, address);
*************** v850_elf_final_link_relocate (howto, inp
*** 1492,1497 ****
--- 1527,1533 ----
case R_V850_HI16_S:
case R_V850_HI16:
case R_V850_LO16:
+ case R_V850_LO16_SPLIT_OFFSET:
case R_V850_16:
case R_V850_ABS32:
case R_V850_8:
Index: bfd/libbfd.h
===================================================================
RCS file: /cvs/src/src/bfd/libbfd.h,v
retrieving revision 1.130
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.130 libbfd.h
*** bfd/libbfd.h 4 Nov 2004 14:57:45 -0000 1.130
--- bfd/libbfd.h 16 Dec 2004 16:25:29 -0000
*************** static const char *const bfd_reloc_code_
*** 1299,1304 ****
--- 1299,1305 ----
"BFD_RELOC_V850_LONGCALL",
"BFD_RELOC_V850_LONGJUMP",
"BFD_RELOC_V850_ALIGN",
+ "BFD_RELOC_V850_LO16_SPLIT_OFFSET",
"BFD_RELOC_MN10300_32_PCREL",
"BFD_RELOC_MN10300_16_PCREL",
"BFD_RELOC_TIC30_LDP",
Index: bfd/bfd-in2.h
===================================================================
RCS file: /cvs/src/src/bfd/bfd-in2.h,v
retrieving revision 1.309
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.309 bfd-in2.h
*** bfd/bfd-in2.h 9 Dec 2004 06:08:45 -0000 1.309
--- bfd/bfd-in2.h 16 Dec 2004 16:25:30 -0000
*************** bits placed non-contiguously in the inst
*** 2967,2972 ****
--- 2967,2976 ----
/* Used to maintain alignment whilst relaxing. */
BFD_RELOC_V850_ALIGN,
+ /* This is a variation of BFD_RELOC_LO16 that can be used in v850e ld.bu
+ instructions. */
+ BFD_RELOC_V850_LO16_SPLIT_OFFSET,
+
/* This is a 32bit pcrel reloc for the mn10300, offset by two bytes in the
instruction. */
BFD_RELOC_MN10300_32_PCREL,
Index: gas/config/tc-v850.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-v850.c,v
retrieving revision 1.39
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.39 tc-v850.c
*** gas/config/tc-v850.c 17 Aug 2004 12:19:57 -0000 1.39
--- gas/config/tc-v850.c 16 Dec 2004 16:25:31 -0000
*************** md_begin ()
*** 1375,1380 ****
--- 1375,1399 ----
bfd_set_arch_mach (stdoutput, TARGET_ARCH, machine);
}
+ static bfd_reloc_code_real_type
+ handle_lo16 (const struct v850_operand *operand)
+ {
+ if (operand != NULL)
+ {
+ if (operand->bits == -1)
+ return BFD_RELOC_V850_LO16_SPLIT_OFFSET;
+
+ if (!(operand->bits == 16 && operand->shift == 16)
+ && !(operand->bits == 15 && operand->shift == 17))
+ {
+ as_bad (_("lo() relocation used on an instruction which does "
+ "not support it"));
+ return BFD_RELOC_64; /* Used to indicate an error condition. */
+ }
+ }
+ return BFD_RELOC_LO16;
+ }
+
static bfd_reloc_code_real_type handle_ctoff
PARAMS ((const struct v850_operand *));
*************** #define CHECK_(name, reloc) \
*** 1516,1522 ****
CHECK_ ("hi0", BFD_RELOC_HI16 );
CHECK_ ("hi", BFD_RELOC_HI16_S );
! CHECK_ ("lo", BFD_RELOC_LO16 );
CHECK_ ("sdaoff", handle_sdaoff (operand));
CHECK_ ("zdaoff", handle_zdaoff (operand));
CHECK_ ("tdaoff", handle_tdaoff (operand));
--- 1535,1541 ----
CHECK_ ("hi0", BFD_RELOC_HI16 );
CHECK_ ("hi", BFD_RELOC_HI16_S );
! CHECK_ ("lo", handle_lo16 (operand) );
CHECK_ ("sdaoff", handle_sdaoff (operand));
CHECK_ ("zdaoff", handle_zdaoff (operand));
CHECK_ ("tdaoff", handle_tdaoff (operand));
*************** md_assemble (str)
*** 1755,1760 ****
--- 1774,1780 ----
/* Fall through. */
case BFD_RELOC_LO16:
+ case BFD_RELOC_V850_LO16_SPLIT_OFFSET:
{
/* Truncate, then sign extend the value. */
ex.X_add_number = SEXT16 (ex.X_add_number);
*************** md_assemble (str)
*** 2199,2204 ****
--- 2219,2225 ----
switch (reloc)
{
case BFD_RELOC_LO16:
+ case BFD_RELOC_V850_LO16_SPLIT_OFFSET:
case BFD_RELOC_HI16:
case BFD_RELOC_HI16_S:
fixP->fx_no_overflow = 1;
*************** md_apply_fix3 (fixP, valueP, seg)
*** 2405,2411 ****
/* We still have to insert the value into memory! */
where = fixP->fx_frag->fr_literal + fixP->fx_where;
! if (fixP->fx_size == 1)
*where = value & 0xff;
else if (fixP->fx_size == 2)
bfd_putl16 (value & 0xffff, (unsigned char *) where);
--- 2426,2436 ----
/* 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);
Index: gas/testsuite/gas/v850/basic.exp
===================================================================
RCS file: /cvs/src/src/gas/testsuite/gas/v850/basic.exp,v
retrieving revision 1.3
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.3 basic.exp
*** gas/testsuite/gas/v850/basic.exp 4 Sep 2003 11:04:36 -0000 1.3
--- gas/testsuite/gas/v850/basic.exp 16 Dec 2004 16:25:31 -0000
*************** if [istarget v850*-*-*] then {
*** 436,439 ****
--- 436,440 ----
gas_test_error "range.s" "-mwarn-signed-overflow" "Check for range error on byte load/store"
run_dump_test "v850e1"
+ run_dump_test "split-lo16"
}
diff -c /dev/null gas/testsuite/gas/v850/split-lo16.d
*** /dev/null Fri Apr 23 00:21:55 2004
--- gas/testsuite/gas/v850/split-lo16.d Thu Dec 16 16:25:08 2004
***************
*** 0 ****
--- 1,16 ----
+ #objdump: -dr
+ #name: V850E split LO16 tests
+ #as: -mv850e
+ #...
+ 00000000 <.*>:
+ 0: 40 0e 00 00 movhi 0, r0, r1
+ 2: R_V850_HI16_S foo
+ 4: 01 16 00 00 addi 0, r1, r2
+ 6: R_V850_LO16 foo
+ 8: 01 17 00 00 ld\.b 0\[r1\],r2
+ a: R_V850_LO16 foo
+ c: 81 17 01 00 ld\.bu 0\[r1\],r2
+ 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
+ #pass
diff -c /dev/null gas/testsuite/gas/v850/split-lo16.s
*** /dev/null Fri Apr 23 00:21:55 2004
--- gas/testsuite/gas/v850/split-lo16.s Thu Dec 16 16:25:08 2004
***************
*** 0 ****
--- 1,7 ----
+ movhi hi(foo),r0,r1
+ addi lo(foo),r1,r2
+ ld.b lo(foo),r1,r2
+ ld.bu lo(foo),r1,r2
+
+ ld.bu lo(0x12345),r1,r2
+ ld.bu lo(0x123456),r1,r2
diff -c /dev/null ld/testsuite/ld-v850/split-lo16.d
*** /dev/null Fri Apr 23 00:21:55 2004
--- ld/testsuite/ld-v850/split-lo16.d Thu Dec 16 16:25:08 2004
***************
*** 0 ****
--- 1,26 ----
+ #source: split-lo16.s -mv850e
+ #ld: -Tsplit-lo16.ld
+ #objdump: -d
+ #...
+ 00010000 <.*>:
+ 10000: 40 0e 34 12 movhi 4660, r0, r1
+ 10004: 01 16 78 56 addi 22136, r1, r2
+ 10008: 81 17 79 56 ld\.bu 22136\[r1\],r2
+ 1000c: 40 0e 36 12 movhi 4662, r0, r1
+ 10010: 01 16 78 d8 addi -10120, r1, r2
+ 10014: 81 17 79 d8 ld\.bu -10120\[r1\],r2
+ 10018: 40 0e 12 00 movhi 18, r0, r1
+ 1001c: 81 17 57 34 ld\.bu 13398\[r1\],r2
+ 10020: 01 16 56 34 addi 13398, r1, r2
+ 10024: 40 0e 14 00 movhi 20, r0, r1
+ 10028: 81 17 57 b6 ld\.bu -18858\[r1\],r2
+ 1002c: 01 16 56 b6 addi -18858, r1, r2
+ 10030: 40 0e 79 56 movhi 22137, r0, r1
+ 10034: 01 16 bc 9a addi -25924, r1, r2
+ 10038: 81 17 bd 9a ld\.bu -25924\[r1\],r2
+ 1003c: 40 0e 9b 78 movhi 30875, r0, r1
+ 10040: 81 17 df bc ld\.bu -17186\[r1\],r2
+ 10044: 01 16 de bc addi -17186, r1, r2
+ 10048: 40 0e 45 23 movhi 9029, r0, r1
+ 1004c: a1 17 89 67 ld\.bu 26505\[r1\],r2
+ #pass
diff -c /dev/null ld/testsuite/ld-v850/v850.exp
*** /dev/null Fri Apr 23 00:21:55 2004
--- ld/testsuite/ld-v850/v850.exp Thu Dec 16 16:25:08 2004
***************
*** 0 ****
--- 1,3 ----
+ if [istarget v850*-*-*] {
+ run_dump_test "split-lo16"
+ }
diff -c /dev/null ld/testsuite/ld-v850/split-lo16.s
*** /dev/null Fri Apr 23 00:21:55 2004
--- ld/testsuite/ld-v850/split-lo16.s Thu Dec 16 16:25:08 2004
***************
*** 0 ****
--- 1,20 ----
+ movhi hi(lo16_nocarry),r0,r1
+ addi lo(lo16_nocarry),r1,r2
+ ld.bu lo(lo16_nocarry)[r1],r2
+ movhi hi(lo16_nocarry + 0x18200),r0,r1
+ addi lo(lo16_nocarry + 0x18200),r1,r2
+ ld.bu lo(lo16_nocarry + 0x18200)[r1],r2
+ movhi hi(split_lo16_nocarry),r0,r1
+ ld.bu lo(split_lo16_nocarry)[r1],r2
+ addi lo(split_lo16_nocarry),r1,r2
+ movhi hi(split_lo16_nocarry + 0x18200),r0,r1
+ ld.bu lo(split_lo16_nocarry + 0x18200)[r1],r2
+ addi lo(split_lo16_nocarry + 0x18200),r1,r2
+ movhi hi(lo16_carry),r0,r1
+ addi lo(lo16_carry),r1,r2
+ ld.bu lo(lo16_carry)[r1],r2
+ movhi hi(split_lo16_carry),r0,r1
+ ld.bu lo(split_lo16_carry)[r1],r2
+ addi lo(split_lo16_carry),r1,r2
+ movhi hi(odd),r0,r1
+ ld.bu lo(odd)[r1],r2
diff -c /dev/null ld/testsuite/ld-v850/split-lo16.ld
*** /dev/null Fri Apr 23 00:21:55 2004
--- ld/testsuite/ld-v850/split-lo16.ld Thu Dec 16 16:25:08 2004
***************
*** 0 ****
--- 1,11 ----
+ SECTIONS
+ {
+ lo16_carry = 0x56789abc;
+ lo16_nocarry = 0x12345678;
+ split_lo16_carry = 0x789abcde;
+ split_lo16_nocarry = 0x00123456;
+ odd = 0x23456789;
+ . = 0x10000;
+ .text : { *(.text); }
+ /DISCARD/ : { *(*); }
+ }
More information about the Binutils
mailing list