From 493ffac5aad8c39215702435c2506fd4d3077191 Mon Sep 17 00:00:00 2001 From: Dimitar Dimitrov Date: Wed, 9 May 2018 11:39:32 +0100 Subject: Fix binary compatibility between GCC and the TI compiler for the PRU target. My original implementation for LDI32 pseudo does not conform to the TI ABI. I wrongly documented my TI PRU ELF object files inspection, which got propagated into my binutils implementation. Issue was exposed when running the GCC ABI testsuite against TI toolchain. According to TI ABI, LDI32 must use first LDI instruction to load the MSB 16bits, and second LDI instruction for the LSB 16bits. This patch will break binary compatibility with previously released binutils versions for PRU. Still, I think it is better to fix binutils to conform to the chip vendor ABI. bfd * elf32-pru.c (pru_elf32_do_ldi32_relocate): Make LDI32 relocation conformant to TI ABI. (pru_elf32_relax_section): Likewise. (pru_elf_relax_delete_bytes): Fix offsets for new LDI32 code. * elf32-pru.c (pru_elf32_do_ldi32_relocate): Ignore addend. (pru_elf32_pmem_relocate): Trap - should not get here. (pru_elf32_relocate_section): Add support for REL relocations. (elf_info_to_howto_rel): Enable REL. (elf_backend_may_use_rel_p): Likewise. (elf_backend_may_use_rela_p): Likewise. (elf_backend_default_use_rela_p): Likewise. gas * config/tc-pru.c (md_apply_fix): Make LDI32 relocation conformant to TI ABI. (pru_assemble_arg_i): Likewise. (output_insn_ldi32): Likewise. * testsuite/gas/pru/ldi.d: Update test for the now fixed LDI32. * gas/config/tc-pru.c (pru_assemble_arg_b): Check imm8 operand range. * gas/testsuite/gas/pru/illegal2.l: New test. * gas/testsuite/gas/pru/illegal2.s: New test. * gas/testsuite/gas/pru/pru.exp: Register new illegal2 test. ld * scripttempl/pru.sc: Add LD sections to allow linking TI toolchain object files. * scripttempl/pru.sc: Switch to init_array. * testsuite/ld-pru/ldi32.d: Update LDI32 test to conform to TI ABI. * testsuite/ld-pru/norelax_ldi32-data.d: Likewise. * testsuite/ld-pru/norelax_ldi32-dis.d: Likewise. * testsuite/ld-pru/relax_ldi32-data.d: Likewise. * testsuite/ld-pru/relax_ldi32-dis.d: Likewise. --- gas/ChangeLog | 12 ++++++++++++ gas/config/tc-pru.c | 18 +++++++++++++----- gas/testsuite/gas/pru/illegal2.l | 2 ++ gas/testsuite/gas/pru/illegal2.s | 5 +++++ gas/testsuite/gas/pru/ldi.d | 8 ++++---- gas/testsuite/gas/pru/pru.exp | 1 + 6 files changed, 37 insertions(+), 9 deletions(-) create mode 100644 gas/testsuite/gas/pru/illegal2.l create mode 100644 gas/testsuite/gas/pru/illegal2.s (limited to 'gas') diff --git a/gas/ChangeLog b/gas/ChangeLog index 88ab077..b44c9e3 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,15 @@ +2018-05-09 Dimitar Dimitrov + + * config/tc-pru.c (md_apply_fix): Make LDI32 relocation conformant + to TI ABI. + (pru_assemble_arg_i): Likewise. + (output_insn_ldi32): Likewise. + * testsuite/gas/pru/ldi.d: Update test for the now fixed LDI32. + * gas/config/tc-pru.c (pru_assemble_arg_b): Check imm8 operand range. + * gas/testsuite/gas/pru/illegal2.l: New test. + * gas/testsuite/gas/pru/illegal2.s: New test. + * gas/testsuite/gas/pru/pru.exp: Register new illegal2 test. + 2018-05-08 Jim Wilson * testsuite/gas/riscv/c-zero-imm.d: Add more tests. diff --git a/gas/config/tc-pru.c b/gas/config/tc-pru.c index d0f630e..5121b1f 100644 --- a/gas/config/tc-pru.c +++ b/gas/config/tc-pru.c @@ -814,8 +814,11 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) /* As the only 64-bit "insn", LDI32 needs special handling. */ uint32_t insn1 = insn & 0xffffffff; uint32_t insn2 = insn >> 32; - SET_INSN_FIELD (IMM16, insn1, fixup & 0xffff); - SET_INSN_FIELD (IMM16, insn2, fixup >> 16); + SET_INSN_FIELD (IMM16, insn1, fixup >> 16); + SET_INSN_FIELD (IMM16, insn2, fixup & 0xffff); + + SET_INSN_FIELD (RDSEL, insn1, RSEL_31_16); + SET_INSN_FIELD (RDSEL, insn2, RSEL_15_0); md_number_to_chars (buf, insn1, 4); md_number_to_chars (buf + 4, insn2, 4); @@ -1086,6 +1089,8 @@ pru_assemble_arg_b (pru_insn_infoS *insn_info, const char *argstr) if (src2 == NULL) { unsigned long imm8 = pru_assemble_noreloc_expression (argstr); + if (imm8 >= 0x100) + as_bad (_("value %lu is too large for a byte operand"), imm8); SET_INSN_FIELD (IMM8, insn_info->insn_code, imm8); SET_INSN_FIELD (IO, insn_info->insn_code, 1); } @@ -1141,7 +1146,8 @@ pru_assemble_arg_i (pru_insn_infoS *insn_info, const char *argstr) /* QUIRK: LDI must clear IO bit high, even though it has immediate arg. */ SET_INSN_FIELD (IO, insn_info->insn_code, 0); - SET_INSN_FIELD (IMM16, insn_info->insn_code, imm32 & 0xffff); + SET_INSN_FIELD (RDSEL, insn_info->insn_code, RSEL_31_16); + SET_INSN_FIELD (IMM16, insn_info->insn_code, imm32 >> 16); insn_info->ldi32_imm32 = imm32; } @@ -1475,11 +1481,13 @@ output_insn_ldi32 (pru_insn_infoS *insn) unsigned long insn2; f = frag_more (8); + SET_INSN_FIELD (IMM16, insn->insn_code, insn->ldi32_imm32 >> 16); + SET_INSN_FIELD (RDSEL, insn->insn_code, RSEL_31_16); md_number_to_chars (f, insn->insn_code, 4); insn2 = insn->insn_code; - SET_INSN_FIELD (IMM16, insn2, insn->ldi32_imm32 >> 16); - SET_INSN_FIELD (RDSEL, insn2, RSEL_31_16); + SET_INSN_FIELD (IMM16, insn2, insn->ldi32_imm32 & 0xffff); + SET_INSN_FIELD (RDSEL, insn2, RSEL_15_0); md_number_to_chars (f + 4, insn2, 4); /* Emit debug info. */ diff --git a/gas/testsuite/gas/pru/illegal2.l b/gas/testsuite/gas/pru/illegal2.l new file mode 100644 index 0000000..793eca7 --- /dev/null +++ b/gas/testsuite/gas/pru/illegal2.l @@ -0,0 +1,2 @@ +.*illegal2.s: Assembler messages: +.*illegal2.s:5: Error: value 256 is too large for a byte operand diff --git a/gas/testsuite/gas/pru/illegal2.s b/gas/testsuite/gas/pru/illegal2.s new file mode 100644 index 0000000..c37f1b2 --- /dev/null +++ b/gas/testsuite/gas/pru/illegal2.s @@ -0,0 +1,5 @@ +# Source file used to test illegal operands. + +foo: +# Out-of-bounds immediate value + add r2, r2, 256 diff --git a/gas/testsuite/gas/pru/ldi.d b/gas/testsuite/gas/pru/ldi.d index 8851504..4c2cf7a 100644 --- a/gas/testsuite/gas/pru/ldi.d +++ b/gas/testsuite/gas/pru/ldi.d @@ -6,12 +6,12 @@ .*: +file format elf32-pru Disassembly of section .text: -0+0000 <[^>]*> 240000f0 ldi r16, 0 +0+0000 <[^>]*> 240000d0 ldi r16.w2, 0 [\t ]*0: R_PRU_LDI32 \*ABS\*\+0x12345678 -0+0004 <[^>]*> 240000d0 ldi r16.w2, 0 +0+0004 <[^>]*> 24000090 ldi r16.w0, 0 0+0008 <[^>]*> 241234f0 ldi r16, 4660 0+000c <[^>]*> 240000f0 ldi r16, 0 [\t ]*c: R_PRU_U16_PMEMIMM .text -0+0010 <[^>]*> 240000f0 ldi r16, 0 +0+0010 <[^>]*> 240000d0 ldi r16.w2, 0 [\t ]*10: R_PRU_LDI32 var1 -0+0014 <[^>]*> 240000d0 ldi r16.w2, 0 +0+0014 <[^>]*> 24000090 ldi r16.w0, 0 diff --git a/gas/testsuite/gas/pru/pru.exp b/gas/testsuite/gas/pru/pru.exp index 49bdf03..cacaa2b 100644 --- a/gas/testsuite/gas/pru/pru.exp +++ b/gas/testsuite/gas/pru/pru.exp @@ -22,5 +22,6 @@ if { [istarget pru-*-*] } { run_dump_tests [lsort [glob -nocomplain $srcdir/$subdir/*.d]] run_list_test "illegal" "" + run_list_test "illegal2" "" run_list_test "warn_reglabel" "" } -- cgit v1.1