From 1e50d24d553250622687bbc21027e8bfdb31870f Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Thu, 16 Dec 2004 16:56:04 +0000 Subject: [PATCH] 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. --- bfd/ChangeLog | 13 + bfd/bfd-in2.h | 4 + bfd/elf32-v850.c | 392 +++++++++++++++------------- bfd/libbfd.h | 1 + bfd/reloc.c | 5 + gas/ChangeLog | 6 + gas/config/tc-v850.c | 29 +- gas/testsuite/ChangeLog | 5 + gas/testsuite/gas/v850/basic.exp | 1 + gas/testsuite/gas/v850/split-lo16.d | 16 ++ gas/testsuite/gas/v850/split-lo16.s | 7 + include/elf/ChangeLog | 4 + include/elf/v850.h | 1 + ld/testsuite/ChangeLog | 4 + ld/testsuite/ld-v850/split-lo16.d | 26 ++ ld/testsuite/ld-v850/split-lo16.ld | 11 + ld/testsuite/ld-v850/split-lo16.s | 20 ++ ld/testsuite/ld-v850/v850.exp | 3 + 18 files changed, 369 insertions(+), 179 deletions(-) create mode 100644 gas/testsuite/gas/v850/split-lo16.d create mode 100644 gas/testsuite/gas/v850/split-lo16.s create mode 100644 ld/testsuite/ld-v850/split-lo16.d create mode 100644 ld/testsuite/ld-v850/split-lo16.ld create mode 100644 ld/testsuite/ld-v850/split-lo16.s create mode 100644 ld/testsuite/ld-v850/v850.exp diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 9f1c90f29a..70af75209a 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,16 @@ +2004-12-16 Richard Sandiford + + * 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. + 2004-12-14 P.J. Darcy * config.bfd: Add s390x-ibm-tpf support. diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index f60382323b..8f7a3d4251 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -2967,6 +2967,10 @@ bits placed non-contiguously in the instruction. */ /* 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, diff --git a/bfd/elf32-v850.c b/bfd/elf32-v850.c index 09eb1ab65a..d960235298 100644 --- a/bfd/elf32-v850.c +++ b/bfd/elf32-v850.c @@ -533,6 +533,21 @@ static reloc_howto_type v850_elf_howto_table[] = 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. */ @@ -567,6 +582,7 @@ static const struct v850_elf_reloc_map v850_elf_reloc_map[] = { 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 }, @@ -687,6 +703,7 @@ v850_elf_check_relocs (abfd, info, sec, relocs) 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: @@ -902,6 +919,187 @@ find_remembered_hi16s_reloc (addend, already_found) return addr; } +/* Calculate the final operand value for a R_V850_LO16 or + R_V850_LO16_SPLIT_OFFSET. *INSN is the current operand value and + ADDEND is the sum of the relocation symbol and offset. Store the + operand value in *INSN and return true on success. + + 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. */ @@ -913,6 +1111,7 @@ v850_elf_perform_relocation (abfd, r_type, addend, address) bfd_byte *address; { unsigned long insn; + unsigned long result; bfd_signed_vma saddend = (bfd_signed_vma) addend; switch (r_type) @@ -972,183 +1171,10 @@ v850_elf_perform_relocation (abfd, r_type, addend, address) 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; - } + 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); @@ -1278,6 +1304,17 @@ v850_elf_perform_relocation (abfd, r_type, addend, address) 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); @@ -1492,6 +1529,7 @@ v850_elf_final_link_relocate (howto, input_bfd, output_bfd, 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: diff --git a/bfd/libbfd.h b/bfd/libbfd.h index 20372ddd12..8dbbd84d25 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -1299,6 +1299,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "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", diff --git a/bfd/reloc.c b/bfd/reloc.c index e4fdbe316a..96ba9c5fb7 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -3098,6 +3098,11 @@ ENUM BFD_RELOC_V850_ALIGN 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 diff --git a/gas/ChangeLog b/gas/ChangeLog index e7f185928a..392a8ec9be 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,9 @@ +2004-12-16 Richard Sandiford + + * 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. + 2004-12-14 P.J. Darcy * configure.in: Add s390x-ibm-tpf support. diff --git a/gas/config/tc-v850.c b/gas/config/tc-v850.c index ed208ee2d2..dfa1c7f3cf 100644 --- a/gas/config/tc-v850.c +++ b/gas/config/tc-v850.c @@ -1375,6 +1375,25 @@ md_begin () 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 *)); @@ -1516,7 +1535,7 @@ v850_reloc_prefix (operand) CHECK_ ("hi0", BFD_RELOC_HI16 ); CHECK_ ("hi", BFD_RELOC_HI16_S ); - CHECK_ ("lo", BFD_RELOC_LO16 ); + CHECK_ ("lo", handle_lo16 (operand) ); CHECK_ ("sdaoff", handle_sdaoff (operand)); CHECK_ ("zdaoff", handle_zdaoff (operand)); CHECK_ ("tdaoff", handle_tdaoff (operand)); @@ -1755,6 +1774,7 @@ md_assemble (str) /* 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); @@ -2199,6 +2219,7 @@ md_assemble (str) 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; @@ -2405,7 +2426,11 @@ md_apply_fix3 (fixP, valueP, seg) /* We still have to insert the value into memory! */ where = fixP->fx_frag->fr_literal + fixP->fx_where; - if (fixP->fx_size == 1) + 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); diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog index 56c056ec82..3b19181a7a 100644 --- a/gas/testsuite/ChangeLog +++ b/gas/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2004-12-16 Richard Sandiford + + * gas/v850/split-lo16.{s,d}: New test. + * gas/v850/v850.exp: Run it. + 2004-12-15 Jan Beulich * gas/elf/section5.[els]: New. diff --git a/gas/testsuite/gas/v850/basic.exp b/gas/testsuite/gas/v850/basic.exp index e3b0713bae..1cf251ee81 100644 --- a/gas/testsuite/gas/v850/basic.exp +++ b/gas/testsuite/gas/v850/basic.exp @@ -436,4 +436,5 @@ if [istarget v850*-*-*] then { 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 --git a/gas/testsuite/gas/v850/split-lo16.d b/gas/testsuite/gas/v850/split-lo16.d new file mode 100644 index 0000000000..9503ac9d8d --- /dev/null +++ b/gas/testsuite/gas/v850/split-lo16.d @@ -0,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 --git a/gas/testsuite/gas/v850/split-lo16.s b/gas/testsuite/gas/v850/split-lo16.s new file mode 100644 index 0000000000..fc3afd14e6 --- /dev/null +++ b/gas/testsuite/gas/v850/split-lo16.s @@ -0,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 --git a/include/elf/ChangeLog b/include/elf/ChangeLog index f4f961d9b2..ea49947f59 100644 --- a/include/elf/ChangeLog +++ b/include/elf/ChangeLog @@ -1,3 +1,7 @@ +2004-12-16 Richard Sandiford + + * v850.h (R_V850_LO16_SPLIT_OFFSET): New reloc. + 2004-12-09 Ian Lance Taylor * mips.h (E_MIPS_MACH_9000): Define. diff --git a/include/elf/v850.h b/include/elf/v850.h index 7d5110b334..f42900532c 100644 --- a/include/elf/v850.h +++ b/include/elf/v850.h @@ -79,6 +79,7 @@ START_RELOC_NUMBERS (v850_reloc_type) 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) diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog index cbf50fcdc7..d817a227bd 100644 --- a/ld/testsuite/ChangeLog +++ b/ld/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2004-12-16 Richard Sandiford + + * ld-v850: New directory. + 2004-12-14 Richard Sandiford * ld-mips-elf/jal-overflow-2.[sd]: New test. diff --git a/ld/testsuite/ld-v850/split-lo16.d b/ld/testsuite/ld-v850/split-lo16.d new file mode 100644 index 0000000000..c5668ffaf7 --- /dev/null +++ b/ld/testsuite/ld-v850/split-lo16.d @@ -0,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 --git a/ld/testsuite/ld-v850/split-lo16.ld b/ld/testsuite/ld-v850/split-lo16.ld new file mode 100644 index 0000000000..bde906303b --- /dev/null +++ b/ld/testsuite/ld-v850/split-lo16.ld @@ -0,0 +1,11 @@ +SECTIONS +{ + lo16_carry = 0x56789abc; + lo16_nocarry = 0x12345678; + split_lo16_carry = 0x789abcde; + split_lo16_nocarry = 0x00123456; + odd = 0x23456789; + . = 0x10000; + .text : { *(.text); } + /DISCARD/ : { *(*); } +} diff --git a/ld/testsuite/ld-v850/split-lo16.s b/ld/testsuite/ld-v850/split-lo16.s new file mode 100644 index 0000000000..7eaae41244 --- /dev/null +++ b/ld/testsuite/ld-v850/split-lo16.s @@ -0,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 --git a/ld/testsuite/ld-v850/v850.exp b/ld/testsuite/ld-v850/v850.exp new file mode 100644 index 0000000000..59f184ac87 --- /dev/null +++ b/ld/testsuite/ld-v850/v850.exp @@ -0,0 +1,3 @@ +if [istarget v850*-*-*] { + run_dump_test "split-lo16" +} -- 2.34.1