* [PATCH v2 01/15] PRU BFD support
2016-12-27 20:44 [PATCH v2 00/15] Binutils/gas/ld port for PRU Dimitar Dimitrov
` (2 preceding siblings ...)
2016-12-27 20:44 ` [PATCH v2 02/15] PRU Binutils port Dimitar Dimitrov
@ 2016-12-27 20:44 ` Dimitar Dimitrov
2016-12-27 20:44 ` [PATCH v2 09/15] ld: testsuite: Fix srec test setup for PRU Dimitar Dimitrov
` (11 subsequent siblings)
15 siblings, 0 replies; 19+ messages in thread
From: Dimitar Dimitrov @ 2016-12-27 20:44 UTC (permalink / raw)
To: binutils; +Cc: Dimitar Dimitrov
2016-12-26 Dimitar Dimitrov <dimitar@dinux.eu>
bfd/
* Makefile.in: Regenerate.
* configure: Regenerate.
* po/SRC-POTFILES.in: Regenerate.
* bfd-in2.h: Regenerate
* libbfd.h: Regenerate.
* archures.c: Add bfd_arch_pru.
* Makefile.am: Add PRU target.
* config.bfd: Ditto.
* configure.ac: Ditto.
* elf-bfd.h (enum elf_target_id): Add PRU_ELF_DATA.
* targets.c: Add pru_elf32_vec.
* reloc.c: Add PRU relocations.
* cpu-pru.c: New file.
* elf32-pru.c: New file.
Signed-off-by: Dimitar Dimitrov <dimitar@dinux.eu>
---
bfd/Makefile.am | 4 +
bfd/archures.c | 4 +
bfd/config.bfd | 6 +
bfd/configure.ac | 1 +
bfd/cpu-pru.c | 43 ++
bfd/elf-bfd.h | 1 +
bfd/elf32-pru.c | 1469 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
bfd/reloc.c | 48 ++
bfd/targets.c | 3 +
9 files changed, 1579 insertions(+)
create mode 100644 bfd/cpu-pru.c
create mode 100644 bfd/elf32-pru.c
diff --git a/bfd/Makefile.am b/bfd/Makefile.am
index 0d5dd4a423..ff02ebb110 100644
--- a/bfd/Makefile.am
+++ b/bfd/Makefile.am
@@ -147,6 +147,7 @@ ALL_MACHINES = \
cpu-pj.lo \
cpu-plugin.lo \
cpu-powerpc.lo \
+ cpu-pru.lo \
cpu-rs6000.lo \
cpu-riscv.lo \
cpu-rl78.lo \
@@ -235,6 +236,7 @@ ALL_MACHINES_CFILES = \
cpu-pj.c \
cpu-plugin.c \
cpu-powerpc.c \
+ cpu-pru.c \
cpu-rs6000.c \
cpu-riscv.c \
cpu-rl78.c \
@@ -365,6 +367,7 @@ BFD32_BACKENDS = \
elf32-or1k.lo \
elf32-pj.lo \
elf32-ppc.lo \
+ elf32-pru.lo \
elf32-rl78.lo \
elf32-rx.lo \
elf32-s390.lo \
@@ -557,6 +560,7 @@ BFD32_BACKENDS_CFILES = \
elf32-or1k.c \
elf32-pj.c \
elf32-ppc.c \
+ elf32-pru.c \
elf32-rl78.c \
elf32-rx.c \
elf32-s390.c \
diff --git a/bfd/archures.c b/bfd/archures.c
index e503492310..1b1e9ce889 100644
--- a/bfd/archures.c
+++ b/bfd/archures.c
@@ -528,6 +528,8 @@ DESCRIPTION
.#define bfd_mach_nios2r2 2
. bfd_arch_visium, {* Visium *}
.#define bfd_mach_visium 1
+. bfd_arch_pru, {* PRU *}
+.#define bfd_mach_pru 0
. bfd_arch_last
. };
*/
@@ -631,6 +633,7 @@ extern const bfd_arch_info_type bfd_pj_arch;
extern const bfd_arch_info_type bfd_plugin_arch;
extern const bfd_arch_info_type bfd_powerpc_archs[];
#define bfd_powerpc_arch bfd_powerpc_archs[0]
+extern const bfd_arch_info_type bfd_pru_arch;
extern const bfd_arch_info_type bfd_riscv_arch;
extern const bfd_arch_info_type bfd_rs6000_arch;
extern const bfd_arch_info_type bfd_rl78_arch;
@@ -721,6 +724,7 @@ static const bfd_arch_info_type * const bfd_archures_list[] =
&bfd_or1k_arch,
&bfd_pdp11_arch,
&bfd_powerpc_arch,
+ &bfd_pru_arch,
&bfd_riscv_arch,
&bfd_rl78_arch,
&bfd_rs6000_arch,
diff --git a/bfd/config.bfd b/bfd/config.bfd
index 5bca5d9161..97f4f91729 100644
--- a/bfd/config.bfd
+++ b/bfd/config.bfd
@@ -189,6 +189,7 @@ or1k*|or1knd*) targ_archs=bfd_or1k_arch ;;
pdp11*) targ_archs=bfd_pdp11_arch ;;
pj*) targ_archs="bfd_pj_arch bfd_i386_arch";;
powerpc*) targ_archs="bfd_rs6000_arch bfd_powerpc_arch" ;;
+pru*) targ_archs=bfd_pru_arch ;;
riscv*) targ_archs=bfd_riscv_arch ;;
rs6000) targ_archs="bfd_rs6000_arch bfd_powerpc_arch" ;;
s390*) targ_archs=bfd_s390_arch ;;
@@ -1436,6 +1437,11 @@ case "${targ}" in
targ_selvecs="powerpc_pei_le_vec powerpc_pei_vec powerpc_pe_le_vec powerpc_pe_vec"
;;
+ pru-*-*)
+ targ_defvec=pru_elf32_vec
+ targ_underscore=yes
+ ;;
+
#ifdef BFD64
riscv32-*-*)
targ_defvec=riscv_elf32_vec
diff --git a/bfd/configure.ac b/bfd/configure.ac
index 944fc567dc..cda6c85a82 100644
--- a/bfd/configure.ac
+++ b/bfd/configure.ac
@@ -606,6 +606,7 @@ do
powerpc_pei_vec) tb="$tb pei-ppc.lo peigen.lo $coff" ;;
powerpc_pei_le_vec) tb="$tb pei-ppc.lo peigen.lo $coff" ;;
powerpc_xcoff_vec) tb="$tb coff-rs6000.lo $xcoff" ;;
+ pru_elf32_vec) tb="$tb elf32-pru.lo elf32.lo $elf" ;;
riscv_elf32_vec) tb="$tb elf32-riscv.lo elfxx-riscv.lo elf32.lo $elf" ;;
riscv_elf64_vec) tb="$tb elf64-riscv.lo elf64.lo elfxx-riscv.lo elf32.lo $elf"; target_size=64 ;;
rl78_elf32_vec) tb="$tb elf32-rl78.lo elf32.lo $elf" ;;
diff --git a/bfd/cpu-pru.c b/bfd/cpu-pru.c
new file mode 100644
index 0000000000..75d5d5aec7
--- /dev/null
+++ b/bfd/cpu-pru.c
@@ -0,0 +1,43 @@
+/* BFD support for the TI PRU microprocessor.
+ Copyright (C) 2014 Free Software Foundation, Inc.
+ Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
+
+ This file is part of BFD, the Binary File Descriptor library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+#include "sysdep.h"
+#include "bfd.h"
+#include "libbfd.h"
+
+#define N(BITS_WORD, BITS_ADDR, NUMBER, PRINT, DEFAULT, NEXT) \
+ { \
+ BITS_WORD, /* bits in a word */ \
+ BITS_ADDR, /* bits in an address */ \
+ 8, /* 8 bits in a byte */ \
+ bfd_arch_pru, \
+ NUMBER, \
+ "pru", \
+ PRINT, \
+ 3, \
+ DEFAULT, \
+ bfd_default_compatible, \
+ bfd_default_scan, \
+ bfd_arch_default_fill, \
+ NEXT \
+ }
+
+const bfd_arch_info_type bfd_pru_arch = N (32, 32, 0, "pru", TRUE, NULL);
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 1c634d8dd1..3dcc245e85 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -467,6 +467,7 @@ enum elf_target_id
OR1K_ELF_DATA,
PPC32_ELF_DATA,
PPC64_ELF_DATA,
+ PRU_ELF_DATA,
S390_ELF_DATA,
SH_ELF_DATA,
SPARC_ELF_DATA,
diff --git a/bfd/elf32-pru.c b/bfd/elf32-pru.c
new file mode 100644
index 0000000000..244b01d046
--- /dev/null
+++ b/bfd/elf32-pru.c
@@ -0,0 +1,1469 @@
+/* 32-bit ELF support for TI PRU.
+ Copyright (C) 2014-2016 Free Software Foundation, Inc.
+ Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
+ Based on elf32-nios2.c
+
+ This file is part of BFD, the Binary File Descriptor library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+/* This file handles TI PRU ELF targets. */
+
+#include "sysdep.h"
+#include "bfd.h"
+#include "libbfd.h"
+#include "bfdlink.h"
+#include "genlink.h"
+#include "elf-bfd.h"
+#include "elf/pru.h"
+#include "opcode/pru.h"
+
+#define SWAP_VALS(A,B) \
+ do { \
+ (A) ^= (B); \
+ (B) ^= (A); \
+ (A) ^= (B); \
+ } while (0)
+
+/* Enable debugging printout at stdout with this variable. */
+static bfd_boolean debug_relax = FALSE;
+
+/* Forward declarations. */
+static bfd_reloc_status_type pru_elf32_pmem_relocate
+ (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
+static bfd_reloc_status_type pru_elf32_s10_pcrel_relocate
+ (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
+static bfd_reloc_status_type pru_elf32_u8_pcrel_relocate
+ (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
+static bfd_reloc_status_type pru_elf32_ldi32_relocate
+ (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
+static bfd_reloc_status_type bfd_elf_pru_diff_relocate
+ (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
+
+/* Target vector. */
+extern const bfd_target pru_elf32_vec;
+
+/* The relocation table used for SHT_REL sections. */
+static reloc_howto_type elf_pru_howto_table_rel[] = {
+ /* No relocation. */
+ HOWTO (R_PRU_NONE, /* type */
+ 0, /* rightshift */
+ 0, /* size (0 = byte, 1 = short, 2 = long) */
+ 3, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont,/* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_PRU_NONE", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ HOWTO (R_PRU_16_PMEM,
+ 2,
+ 1, /* short */
+ 32,
+ FALSE,
+ 0,
+ complain_overflow_dont,
+ bfd_elf_generic_reloc,
+ "R_PRU_16_PMEM",
+ FALSE,
+ 0, /* src_mask */
+ 0xffff,
+ FALSE),
+
+ HOWTO (R_PRU_U16_PMEMIMM,
+ 2,
+ 2,
+ 32,
+ FALSE,
+ 8,
+ complain_overflow_unsigned,
+ pru_elf32_pmem_relocate,
+ "R_PRU_U16_PMEMIMM",
+ FALSE,
+ 0, /* src_mask */
+ 0x00ffff00,
+ FALSE),
+
+ HOWTO (R_PRU_BFD_RELOC_16,
+ 0,
+ 1, /* short */
+ 16,
+ FALSE,
+ 0,
+ complain_overflow_bitfield,
+ bfd_elf_generic_reloc,
+ "R_PRU_BFD_RELOC16",
+ FALSE,
+ 0, /* src_mask */
+ 0x0000ffff,
+ FALSE),
+
+ /* 16-bit unsigned immediate relocation. */
+ HOWTO (R_PRU_U16, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 8, /* bitpos */
+ complain_overflow_unsigned, /* complain on overflow */
+ bfd_elf_generic_reloc, /* special function */
+ "R_PRU_U16", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0x00ffff00, /* dest_mask */
+ FALSE), /* pcrel_offset */
+
+ HOWTO (R_PRU_32_PMEM,
+ 2,
+ 2, /* long */
+ 32,
+ FALSE,
+ 0,
+ complain_overflow_dont,
+ pru_elf32_pmem_relocate,
+ "R_PRU_32_PMEM",
+ FALSE,
+ 0, /* src_mask */
+ 0xffffffff,
+ FALSE),
+
+ HOWTO (R_PRU_BFD_RELOC_32,
+ 0,
+ 2, /* long */
+ 32,
+ FALSE,
+ 0,
+ complain_overflow_dont,
+ bfd_elf_generic_reloc,
+ "R_PRU_BFD_RELOC32",
+ FALSE,
+ 0, /* src_mask */
+ 0xffffffff,
+ FALSE),
+
+ HOWTO (R_PRU_S10_PCREL,
+ 2,
+ 2,
+ 10,
+ TRUE,
+ 0,
+ complain_overflow_bitfield,
+ pru_elf32_s10_pcrel_relocate,
+ "R_PRU_S10_PCREL",
+ FALSE,
+ 0, /* src_mask */
+ 0x060000ff,
+ TRUE),
+
+ HOWTO (R_PRU_U8_PCREL,
+ 2,
+ 2,
+ 8,
+ TRUE,
+ 0,
+ complain_overflow_unsigned,
+ pru_elf32_u8_pcrel_relocate,
+ "R_PRU_U8_PCREL",
+ FALSE,
+ 0, /* src_mask */
+ 0x000000ff,
+ TRUE),
+
+ HOWTO (R_PRU_LDI32,
+ 0, /* rightshift */
+ 4, /* size (4 = 8bytes) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_unsigned, /* complain on overflow */
+ pru_elf32_ldi32_relocate, /* special function */
+ "R_PRU_LDI32", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0xffffffff, /* dest_mask */
+ FALSE), /* pcrel_offset */
+
+ /* GNU-specific relocations. */
+ HOWTO (R_PRU_GNU_BFD_RELOC_8,
+ 0,
+ 0, /* byte */
+ 8,
+ FALSE,
+ 0,
+ complain_overflow_bitfield,
+ bfd_elf_generic_reloc,
+ "R_PRU_BFD_RELOC8",
+ FALSE,
+ 0, /* src_mask */
+ 0x000000ff,
+ FALSE),
+
+ HOWTO (R_PRU_GNU_DIFF8, /* type */
+ 0, /* rightshift */
+ 0, /* size (0 = byte, 1 = short, 2 = long) */
+ 8, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ bfd_elf_pru_diff_relocate, /* special_function */
+ "R_PRU_DIFF8", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0xff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ HOWTO (R_PRU_GNU_DIFF16, /* type */
+ 0, /* rightshift */
+ 1, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ bfd_elf_pru_diff_relocate,/* special_function */
+ "R_PRU_DIFF16", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0xffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ HOWTO (R_PRU_GNU_DIFF32, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ bfd_elf_pru_diff_relocate,/* special_function */
+ "R_PRU_DIFF32", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ HOWTO (R_PRU_GNU_DIFF16_PMEM, /* type */
+ 0, /* rightshift */
+ 1, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ bfd_elf_pru_diff_relocate,/* special_function */
+ "R_PRU_DIFF16_PMEM", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0xffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ HOWTO (R_PRU_GNU_DIFF32_PMEM, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ bfd_elf_pru_diff_relocate,/* special_function */
+ "R_PRU_DIFF32_PMEM", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+/* Add other relocations here. */
+};
+
+static unsigned char elf_code_to_howto_index[R_PRU_ILLEGAL + 1];
+
+/* Return the howto for relocation RTYPE. */
+static reloc_howto_type *
+lookup_howto (unsigned int rtype)
+{
+ static int initialized = 0;
+ int i;
+ int howto_tbl_size = (int) (sizeof (elf_pru_howto_table_rel)
+ / sizeof (elf_pru_howto_table_rel[0]));
+
+ if (!initialized)
+ {
+ initialized = 1;
+ memset (elf_code_to_howto_index, 0xff,
+ sizeof (elf_code_to_howto_index));
+ for (i = 0; i < howto_tbl_size; i++)
+ elf_code_to_howto_index[elf_pru_howto_table_rel[i].type] = i;
+ }
+
+ BFD_ASSERT (rtype <= R_PRU_ILLEGAL);
+ i = elf_code_to_howto_index[rtype];
+ if (i >= howto_tbl_size)
+ return 0;
+ return elf_pru_howto_table_rel + i;
+}
+
+/* Map for converting BFD reloc types to PRU reloc types. */
+struct elf_reloc_map
+{
+ bfd_reloc_code_real_type bfd_val;
+ enum elf_pru_reloc_type elf_val;
+};
+
+static const struct elf_reloc_map pru_reloc_map[] = {
+ {BFD_RELOC_NONE, R_PRU_NONE},
+ {BFD_RELOC_PRU_16_PMEM, R_PRU_16_PMEM},
+ {BFD_RELOC_PRU_U16_PMEMIMM, R_PRU_U16_PMEMIMM},
+ {BFD_RELOC_16, R_PRU_BFD_RELOC_16},
+ {BFD_RELOC_PRU_U16, R_PRU_U16},
+ {BFD_RELOC_PRU_32_PMEM, R_PRU_32_PMEM},
+ {BFD_RELOC_32, R_PRU_BFD_RELOC_32},
+ {BFD_RELOC_PRU_S10_PCREL, R_PRU_S10_PCREL},
+ {BFD_RELOC_PRU_U8_PCREL, R_PRU_U8_PCREL},
+ {BFD_RELOC_PRU_LDI32, R_PRU_LDI32},
+
+ {BFD_RELOC_8, R_PRU_GNU_BFD_RELOC_8},
+ {BFD_RELOC_PRU_GNU_DIFF8, R_PRU_GNU_DIFF8},
+ {BFD_RELOC_PRU_GNU_DIFF16, R_PRU_GNU_DIFF16},
+ {BFD_RELOC_PRU_GNU_DIFF32, R_PRU_GNU_DIFF32},
+ {BFD_RELOC_PRU_GNU_DIFF16_PMEM, R_PRU_GNU_DIFF16_PMEM},
+ {BFD_RELOC_PRU_GNU_DIFF32_PMEM, R_PRU_GNU_DIFF32_PMEM},
+};
+
+
+/* Assorted hash table functions. */
+
+/* Create an entry in a PRU ELF linker hash table. */
+static struct bfd_hash_entry *
+link_hash_newfunc (struct bfd_hash_entry *entry,
+ struct bfd_hash_table *table, const char *string)
+{
+ /* Allocate the structure if it has not already been allocated by a
+ subclass. */
+ if (entry == NULL)
+ {
+ entry = bfd_hash_allocate (table,
+ sizeof (struct elf_link_hash_entry));
+ if (entry == NULL)
+ return entry;
+ }
+
+ /* Call the allocation method of the superclass. */
+ entry = _bfd_elf_link_hash_newfunc (entry, table, string);
+
+ return entry;
+}
+
+/* Implement bfd_elf32_bfd_reloc_type_lookup:
+ Given a BFD reloc type, return a howto structure. */
+static reloc_howto_type *
+pru_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+ bfd_reloc_code_real_type code)
+{
+ int i;
+ for (i = 0;
+ i < (int) (sizeof (pru_reloc_map) / sizeof (struct elf_reloc_map));
+ ++i)
+ if (pru_reloc_map[i].bfd_val == code)
+ return lookup_howto ((unsigned int) pru_reloc_map[i].elf_val);
+ return NULL;
+}
+
+/* Implement bfd_elf32_bfd_reloc_name_lookup:
+ Given a reloc name, return a howto structure. */
+static reloc_howto_type *
+pru_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+ const char *r_name)
+{
+ unsigned int i;
+ for (i = 0;
+ i < (sizeof (elf_pru_howto_table_rel)
+ / sizeof (elf_pru_howto_table_rel[0]));
+ i++)
+ if (elf_pru_howto_table_rel[i].name
+ && strcasecmp (elf_pru_howto_table_rel[i].name, r_name) == 0)
+ return &elf_pru_howto_table_rel[i];
+
+ return NULL;
+}
+
+/* Implement elf_info_to_howto:
+ Given a ELF32 relocation, fill in a arelent structure. */
+static void
+pru_elf32_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr,
+ Elf_Internal_Rela *dst)
+{
+ unsigned int r_type;
+
+ r_type = ELF32_R_TYPE (dst->r_info);
+ BFD_ASSERT (r_type < R_PRU_ILLEGAL);
+ cache_ptr->howto = lookup_howto (r_type);
+}
+
+/* Do the relocations that require special handling. */
+/* Produce a word address for program memory. Linker scripts will put .text
+ at a high offset in order to differentiate it from .data. So here we also
+ mask the high bits of PMEM address.
+
+ But why 1MB when internal Program Memory much smaller? We want to catch
+ unintended overflows.
+
+ Why not use (1<<31) as an offset and a mask? Sitara DDRAM usually resides
+ there, and users might want to put some shared carveout memory region in
+ their linker scripts. So 0x80000000 might be a valid .data address.
+
+ Note that we still keep and pass down the original howto. This way we
+ can reuse this function for several different relocations. */
+static bfd_reloc_status_type
+pru_elf32_do_pmem_relocate (bfd *abfd, reloc_howto_type *howto,
+ asection *input_section,
+ bfd_byte *data, bfd_vma offset,
+ bfd_vma symbol_value, bfd_vma addend)
+{
+ symbol_value = symbol_value + addend;
+ addend = 0;
+ symbol_value &= 0x3fffff;
+ return _bfd_final_link_relocate (howto, abfd, input_section,
+ data, offset, symbol_value, addend);
+}
+
+/* Direct copy of _bfd_final_link_relocate, but with special
+ "fill-in". This copy-paste mumbo jumbo is only needed because BFD
+ cannot deal correctly with non-contiguous bit fields. */
+static bfd_reloc_status_type
+pru_elf32_do_s10_pcrel_relocate (bfd *input_bfd, reloc_howto_type *howto,
+ asection *input_section,
+ bfd_byte *contents, bfd_vma address,
+ bfd_vma relocation, bfd_vma addend)
+{
+ bfd_byte *location;
+ bfd_vma x = 0;
+ bfd_vma qboff;
+ bfd_reloc_status_type flag = bfd_reloc_ok;
+
+ /* Sanity check the address. */
+ if (address > bfd_get_section_limit (input_bfd, input_section))
+ return bfd_reloc_outofrange;
+
+ BFD_ASSERT (howto->pc_relative);
+ BFD_ASSERT (howto->pcrel_offset);
+
+ relocation = relocation + addend - (input_section->output_section->vma
+ + input_section->output_offset) - address;
+
+ location = contents + address;
+
+ /* Get the value we are going to relocate. */
+ BFD_ASSERT (bfd_get_reloc_size (howto) == 4);
+ x = bfd_get_32 (input_bfd, location);
+
+ qboff = GET_BROFF_SIGNED (x) << howto->rightshift;
+ relocation += qboff;
+
+ BFD_ASSERT (howto->complain_on_overflow == complain_overflow_bitfield);
+
+ if (relocation > 2047 && relocation < (bfd_vma)-2048l)
+ flag = bfd_reloc_overflow;
+
+ /* Check that target address is word-aligned. */
+ if (relocation & ((1 << howto->rightshift) - 1))
+ flag = bfd_reloc_outofrange;
+
+ relocation >>= (bfd_vma) howto->rightshift;
+
+ /* Fill-in the RELOCATION to the right bits of X. */
+ SET_BROFF_URAW (x, relocation);
+
+ bfd_put_32 (input_bfd, x, location);
+
+ return flag;
+}
+
+static bfd_reloc_status_type
+pru_elf32_do_u8_pcrel_relocate (bfd *abfd, reloc_howto_type *howto,
+ asection *input_section,
+ bfd_byte *data, bfd_vma offset,
+ bfd_vma symbol_value, bfd_vma addend)
+{
+ bfd_vma relocation;
+
+ BFD_ASSERT (howto->pc_relative);
+ BFD_ASSERT (howto->pcrel_offset);
+
+ relocation = symbol_value + addend - (input_section->output_section->vma
+ + input_section->output_offset) - offset;
+ relocation >>= howto->rightshift;
+
+ /* 0 and 1 are invalid target labels for LOOP. We cannot
+ encode this info in HOWTO, so catch such cases here. */
+ if (relocation < 2)
+ return bfd_reloc_outofrange;
+
+ return _bfd_final_link_relocate (howto, abfd, input_section,
+ data, offset, symbol_value, addend);
+}
+
+/* Idea and code taken from elf32-d30v. */
+static bfd_reloc_status_type
+pru_elf32_do_ldi32_relocate (bfd *abfd, reloc_howto_type *howto,
+ asection *input_section,
+ bfd_byte *data, bfd_vma offset,
+ bfd_vma symbol_value, bfd_vma addend)
+{
+ bfd_signed_vma relocation;
+ bfd_size_type octets = offset * bfd_octets_per_byte (abfd);
+ bfd_byte *location;
+ unsigned long in1, in2, num;
+
+ /* A hacked-up version of _bfd_final_link_relocate() follows. */
+
+ /* Sanity check the address. */
+ if (octets + bfd_get_reloc_size (howto)
+ > bfd_get_section_limit_octets (abfd, input_section))
+ return bfd_reloc_outofrange;
+
+ /* This function assumes that we are dealing with a basic relocation
+ against a symbol. We want to compute the value of the symbol to
+ relocate to. This is just VALUE, the value of the symbol, plus
+ ADDEND, any addend associated with the reloc. */
+ relocation = symbol_value + addend;
+
+ BFD_ASSERT (!howto->pc_relative);
+
+ /* A hacked-up version of _bfd_relocate_contents() follows. */
+ location = data + offset * bfd_octets_per_byte (abfd);
+
+ BFD_ASSERT (!howto->pc_relative);
+
+ in1 = bfd_get_32 (abfd, location);
+ in2 = bfd_get_32 (abfd, location + 4);
+
+ /* Extract the addend - should be zero per my understanding. */
+ num = GET_INSN_FIELD (IMM16, in1) | (GET_INSN_FIELD (IMM16, in2) << 16);
+ BFD_ASSERT (!num);
+
+ relocation += num;
+
+ SET_INSN_FIELD (IMM16, in1, relocation & 0xffff);
+ SET_INSN_FIELD (IMM16, in2, relocation >> 16);
+
+ bfd_put_32 (abfd, in1, location);
+ bfd_put_32 (abfd, in2, location + 4);
+
+ return bfd_reloc_ok;
+}
+
+/* HOWTO handlers for relocations that require special handling. */
+
+static bfd_reloc_status_type
+pru_elf32_pmem_relocate (bfd *abfd, arelent *reloc_entry,
+ asymbol *symbol, void *data,
+ asection *input_section, bfd *output_bfd,
+ char **error_message)
+{
+ /* If this is a relocatable link (output_bfd test tells us), just
+ call the generic function. Any adjustment will be done at final
+ link time. */
+ if (output_bfd != NULL)
+ return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
+ input_section, output_bfd, error_message);
+
+ return pru_elf32_do_pmem_relocate (abfd, reloc_entry->howto,
+ input_section,
+ data, reloc_entry->address,
+ (symbol->value
+ + symbol->section->output_section->vma
+ + symbol->section->output_offset),
+ reloc_entry->addend);
+}
+
+static bfd_reloc_status_type
+pru_elf32_s10_pcrel_relocate (bfd *abfd, arelent *reloc_entry,
+ asymbol *symbol, void *data,
+ asection *input_section, bfd *output_bfd,
+ char **error_message)
+{
+ /* If this is a relocatable link (output_bfd test tells us), just
+ call the generic function. Any adjustment will be done at final
+ link time. */
+ if (output_bfd != NULL)
+ return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
+ input_section, output_bfd, error_message);
+
+ return pru_elf32_do_s10_pcrel_relocate (abfd, reloc_entry->howto,
+ input_section, data,
+ reloc_entry->address,
+ (symbol->value
+ + symbol->section->output_section->vma
+ + symbol->section->output_offset),
+ reloc_entry->addend);
+}
+
+static bfd_reloc_status_type
+pru_elf32_u8_pcrel_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
+ void *data, asection *input_section,
+ bfd *output_bfd,
+ char **error_message)
+{
+ /* If this is a relocatable link (output_bfd test tells us), just
+ call the generic function. Any adjustment will be done at final
+ link time. */
+ if (output_bfd != NULL)
+ return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
+ input_section, output_bfd, error_message);
+
+ return pru_elf32_do_u8_pcrel_relocate (abfd, reloc_entry->howto,
+ input_section,
+ data, reloc_entry->address,
+ (symbol->value
+ + symbol->section->output_section->vma
+ + symbol->section->output_offset),
+ reloc_entry->addend);
+}
+
+static bfd_reloc_status_type
+pru_elf32_ldi32_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
+ void *data, asection *input_section,
+ bfd *output_bfd,
+ char **error_message)
+{
+ /* If this is a relocatable link (output_bfd test tells us), just
+ call the generic function. Any adjustment will be done at final
+ link time. */
+ if (output_bfd != NULL)
+ return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
+ input_section, output_bfd, error_message);
+
+ return pru_elf32_do_ldi32_relocate (abfd, reloc_entry->howto,
+ input_section,
+ data, reloc_entry->address,
+ (symbol->value
+ + symbol->section->output_section->vma
+ + symbol->section->output_offset),
+ reloc_entry->addend);
+}
+
+
+/* Implement elf_backend_relocate_section. */
+static bfd_boolean
+pru_elf32_relocate_section (bfd *output_bfd,
+ struct bfd_link_info *info,
+ bfd *input_bfd,
+ asection *input_section,
+ bfd_byte *contents,
+ Elf_Internal_Rela *relocs,
+ Elf_Internal_Sym *local_syms,
+ asection **local_sections)
+{
+ Elf_Internal_Shdr *symtab_hdr;
+ struct elf_link_hash_entry **sym_hashes;
+ Elf_Internal_Rela *rel;
+ Elf_Internal_Rela *relend;
+
+ symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+ sym_hashes = elf_sym_hashes (input_bfd);
+ relend = relocs + input_section->reloc_count;
+
+ for (rel = relocs; rel < relend; rel++)
+ {
+ reloc_howto_type *howto;
+ unsigned long r_symndx;
+ Elf_Internal_Sym *sym;
+ asection *sec;
+ struct elf_link_hash_entry *h;
+ bfd_vma relocation;
+ bfd_reloc_status_type r = bfd_reloc_ok;
+ const char *name = NULL;
+ const char* msg = (const char*) NULL;
+ bfd_boolean unresolved_reloc;
+
+ r_symndx = ELF32_R_SYM (rel->r_info);
+
+ howto = lookup_howto ((unsigned) ELF32_R_TYPE (rel->r_info));
+ h = NULL;
+ sym = NULL;
+ sec = NULL;
+
+ if (r_symndx < symtab_hdr->sh_info)
+ {
+ sym = local_syms + r_symndx;
+ sec = local_sections[r_symndx];
+ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
+ }
+ else
+ {
+ bfd_boolean warned, ignored;
+
+ RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
+ r_symndx, symtab_hdr, sym_hashes,
+ h, sec, relocation,
+ unresolved_reloc, warned, ignored);
+ }
+
+ if (sec && discarded_section (sec))
+ RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
+ rel, 1, relend, howto, 0, contents);
+
+ /* Nothing more to do unless this is a final link. */
+ if (bfd_link_relocatable (info))
+ continue;
+
+ if (howto)
+ {
+ switch (howto->type)
+ {
+ case R_PRU_NONE:
+ /* We don't need to find a value for this symbol. It's just a
+ marker. */
+ r = bfd_reloc_ok;
+ break;
+
+ case R_PRU_U16_PMEMIMM:
+ case R_PRU_32_PMEM:
+ case R_PRU_16_PMEM:
+ r = pru_elf32_do_pmem_relocate (input_bfd, howto,
+ input_section,
+ contents, rel->r_offset,
+ relocation, rel->r_addend);
+ break;
+ case R_PRU_S10_PCREL:
+ r = pru_elf32_do_s10_pcrel_relocate (input_bfd, howto,
+ input_section,
+ contents,
+ rel->r_offset,
+ relocation,
+ rel->r_addend);
+ break;
+ case R_PRU_U8_PCREL:
+ r = pru_elf32_do_u8_pcrel_relocate (input_bfd, howto,
+ input_section,
+ contents,
+ rel->r_offset,
+ relocation,
+ rel->r_addend);
+ break;
+ case R_PRU_LDI32:
+ r = pru_elf32_do_ldi32_relocate (input_bfd, howto,
+ input_section,
+ contents,
+ rel->r_offset,
+ relocation,
+ rel->r_addend);
+ break;
+ case R_PRU_GNU_DIFF8:
+ case R_PRU_GNU_DIFF16:
+ case R_PRU_GNU_DIFF32:
+ case R_PRU_GNU_DIFF16_PMEM:
+ case R_PRU_GNU_DIFF32_PMEM:
+ /* Nothing to do here, as contents already contain the
+ diff value. */
+ r = bfd_reloc_ok;
+ break;
+
+ default:
+ r = _bfd_final_link_relocate (howto, input_bfd,
+ input_section, contents,
+ rel->r_offset, relocation,
+ rel->r_addend);
+ break;
+ }
+ }
+ else
+ r = bfd_reloc_notsupported;
+
+ if (r != bfd_reloc_ok)
+ {
+ if (h != NULL)
+ name = h->root.root.string;
+ else
+ {
+ name = bfd_elf_string_from_elf_section (input_bfd,
+ symtab_hdr->sh_link,
+ sym->st_name);
+ if (name == NULL || *name == '\0')
+ name = bfd_section_name (input_bfd, sec);
+ }
+
+ switch (r)
+ {
+ case bfd_reloc_overflow:
+ (*info->callbacks->reloc_overflow) (info, NULL, name,
+ howto->name, (bfd_vma) 0,
+ input_bfd, input_section,
+ rel->r_offset);
+ break;
+
+ case bfd_reloc_undefined:
+ (*info->callbacks->undefined_symbol) (info, name, input_bfd,
+ input_section,
+ rel->r_offset, TRUE);
+ break;
+
+ case bfd_reloc_outofrange:
+ if (msg == NULL)
+ msg = _("relocation out of range");
+ break;
+
+ case bfd_reloc_notsupported:
+ if (msg == NULL)
+ msg = _("unsupported relocation");
+ break;
+
+ case bfd_reloc_dangerous:
+ if (msg == NULL)
+ msg = _("dangerous relocation");
+ break;
+
+ default:
+ if (msg == NULL)
+ msg = _("unknown error");
+ break;
+ }
+
+ if (msg)
+ {
+ (*info->callbacks->warning) (info, msg, name, input_bfd,
+ input_section, rel->r_offset);
+ return FALSE;
+ }
+ }
+ }
+ return TRUE;
+}
+
+\f
+/* Perform a diff relocation. Nothing to do, as the difference value is
+ already written into the section's contents. */
+
+static bfd_reloc_status_type
+bfd_elf_pru_diff_relocate (bfd *abfd ATTRIBUTE_UNUSED,
+ arelent *reloc_entry ATTRIBUTE_UNUSED,
+ asymbol *symbol ATTRIBUTE_UNUSED,
+ void *data ATTRIBUTE_UNUSED,
+ asection *input_section ATTRIBUTE_UNUSED,
+ bfd *output_bfd ATTRIBUTE_UNUSED,
+ char **error_message ATTRIBUTE_UNUSED)
+{
+ return bfd_reloc_ok;
+}
+
+
+/* Returns whether the relocation type passed is a diff reloc. */
+
+static bfd_boolean
+elf32_pru_is_diff_reloc (Elf_Internal_Rela *irel)
+{
+ return (ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF8
+ || ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF16
+ || ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF32
+ || ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF16_PMEM
+ || ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF32_PMEM);
+}
+
+/* Reduce the diff value written in the section by count if the shrinked
+ insn address happens to fall between the two symbols for which this
+ diff reloc was emitted. */
+
+static void
+elf32_pru_adjust_diff_reloc_value (bfd *abfd,
+ struct bfd_section *isec,
+ Elf_Internal_Rela *irel,
+ bfd_vma symval,
+ bfd_vma shrinked_insn_address,
+ int count)
+{
+ unsigned char *reloc_contents = NULL;
+ unsigned char *isec_contents = elf_section_data (isec)->this_hdr.contents;
+ if (isec_contents == NULL)
+ {
+ if (! bfd_malloc_and_get_section (abfd, isec, &isec_contents))
+ return;
+
+ elf_section_data (isec)->this_hdr.contents = isec_contents;
+ }
+
+ reloc_contents = isec_contents + irel->r_offset;
+
+ /* Read value written in object file. */
+ bfd_signed_vma x = 0;
+ switch (ELF32_R_TYPE (irel->r_info))
+ {
+ case R_PRU_GNU_DIFF8:
+ {
+ x = bfd_get_signed_8 (abfd, reloc_contents);
+ break;
+ }
+ case R_PRU_GNU_DIFF16:
+ {
+ x = bfd_get_signed_16 (abfd, reloc_contents);
+ break;
+ }
+ case R_PRU_GNU_DIFF32:
+ {
+ x = bfd_get_signed_32 (abfd, reloc_contents);
+ break;
+ }
+ case R_PRU_GNU_DIFF16_PMEM:
+ {
+ x = bfd_get_signed_16 (abfd, reloc_contents) * 4;
+ break;
+ }
+ case R_PRU_GNU_DIFF32_PMEM:
+ {
+ x = bfd_get_signed_32 (abfd, reloc_contents) * 4;
+ break;
+ }
+ default:
+ {
+ BFD_FAIL ();
+ }
+ }
+
+ /* For a diff reloc sym1 - sym2 the diff at assembly time (x) is written
+ into the object file at the reloc offset. sym2's logical value is
+ symval (<start_of_section>) + reloc addend. Compute the start and end
+ addresses and check if the shrinked insn falls between sym1 and sym2. */
+
+ bfd_vma end_address = symval + irel->r_addend;
+ bfd_vma start_address = end_address - x;
+
+ /* Shrink the absolute DIFF value (get the to labels "closer"
+ together), because we have removed data between labels. */
+ if (x < 0)
+ {
+ x += count;
+ /* In case the signed x is negative, restore order. */
+ SWAP_VALS (end_address, start_address);
+ }
+ else
+ {
+ x -= count;
+ }
+
+ /* Reduce the diff value by count bytes and write it back into section
+ contents. */
+
+ if (shrinked_insn_address >= start_address
+ && shrinked_insn_address <= end_address)
+ {
+ switch (ELF32_R_TYPE (irel->r_info))
+ {
+ case R_PRU_GNU_DIFF8:
+ {
+ bfd_put_signed_8 (abfd, x & 0xFF, reloc_contents);
+ break;
+ }
+ case R_PRU_GNU_DIFF16:
+ {
+ bfd_put_signed_16 (abfd, x & 0xFFFF, reloc_contents);
+ break;
+ }
+ case R_PRU_GNU_DIFF32:
+ {
+ bfd_put_signed_32 (abfd, x & 0xFFFFFFFF, reloc_contents);
+ break;
+ }
+ case R_PRU_GNU_DIFF16_PMEM:
+ {
+ bfd_put_signed_16 (abfd, (x / 4) & 0xFFFF, reloc_contents);
+ break;
+ }
+ case R_PRU_GNU_DIFF32_PMEM:
+ {
+ bfd_put_signed_32 (abfd, (x / 4) & 0xFFFFFFFF, reloc_contents);
+ break;
+ }
+ default:
+ {
+ BFD_FAIL ();
+ }
+ }
+
+ }
+}
+
+/* Delete some bytes from a section while changing the size of an instruction.
+ The parameter "addr" denotes the section-relative offset pointing just
+ behind the shrinked instruction. "addr+count" point at the first
+ byte just behind the original unshrinked instruction.
+
+ Idea copied from the AVR port. */
+
+static bfd_boolean
+pru_elf_relax_delete_bytes (bfd *abfd,
+ asection *sec,
+ bfd_vma addr,
+ int count)
+{
+ Elf_Internal_Shdr *symtab_hdr;
+ unsigned int sec_shndx;
+ bfd_byte *contents;
+ Elf_Internal_Rela *irel, *irelend;
+ Elf_Internal_Sym *isym;
+ Elf_Internal_Sym *isymbuf = NULL;
+ bfd_vma toaddr;
+ struct elf_link_hash_entry **sym_hashes;
+ struct elf_link_hash_entry **end_hashes;
+ unsigned int symcount;
+
+ symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
+ contents = elf_section_data (sec)->this_hdr.contents;
+
+ toaddr = sec->size;
+
+ irel = elf_section_data (sec)->relocs;
+ irelend = irel + sec->reloc_count;
+
+ /* Actually delete the bytes. */
+ if (toaddr - addr - count > 0)
+ memmove (contents + addr, contents + addr + count,
+ (size_t) (toaddr - addr - count));
+ sec->size -= count;
+
+ /* Adjust all the reloc addresses. */
+ for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++)
+ {
+ bfd_vma old_reloc_address;
+
+ old_reloc_address = (sec->output_section->vma
+ + sec->output_offset + irel->r_offset);
+
+ /* Get the new reloc address. */
+ if ((irel->r_offset > addr
+ && irel->r_offset < toaddr))
+ {
+ if (debug_relax)
+ printf ("Relocation at address 0x%x needs to be moved.\n"
+ "Old section offset: 0x%x, New section offset: 0x%x \n",
+ (unsigned int) old_reloc_address,
+ (unsigned int) irel->r_offset,
+ (unsigned int) ((irel->r_offset) - count));
+
+ irel->r_offset -= count;
+ }
+
+ }
+
+ /* The reloc's own addresses are now ok. However, we need to readjust
+ the reloc's addend, i.e. the reloc's value if two conditions are met:
+ 1.) the reloc is relative to a symbol in this section that
+ is located in front of the shrinked instruction
+ 2.) symbol plus addend end up behind the shrinked instruction.
+
+ The most common case where this happens are relocs relative to
+ the section-start symbol.
+
+ This step needs to be done for all of the sections of the bfd. */
+
+ {
+ struct bfd_section *isec;
+
+ for (isec = abfd->sections; isec; isec = isec->next)
+ {
+ bfd_vma symval;
+ bfd_vma shrinked_insn_address;
+
+ if (isec->reloc_count == 0)
+ continue;
+
+ shrinked_insn_address = (sec->output_section->vma
+ + sec->output_offset + addr - count);
+
+ irel = elf_section_data (isec)->relocs;
+ /* PR 12161: Read in the relocs for this section if necessary. */
+ if (irel == NULL)
+ irel = _bfd_elf_link_read_relocs (abfd, isec, NULL, NULL, TRUE);
+
+ for (irelend = irel + isec->reloc_count;
+ irel < irelend;
+ irel++)
+ {
+ /* Read this BFD's local symbols if we haven't done
+ so already. */
+ if (isymbuf == NULL && symtab_hdr->sh_info != 0)
+ {
+ isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
+ if (isymbuf == NULL)
+ isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
+ symtab_hdr->sh_info, 0,
+ NULL, NULL, NULL);
+ if (isymbuf == NULL)
+ return FALSE;
+ }
+
+ /* Get the value of the symbol referred to by the reloc. */
+ if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
+ {
+ /* A local symbol. */
+ asection *sym_sec;
+
+ isym = isymbuf + ELF32_R_SYM (irel->r_info);
+ sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
+ symval = isym->st_value;
+ /* If the reloc is absolute, it will not have
+ a symbol or section associated with it. */
+ if (sym_sec == sec)
+ {
+ symval += sym_sec->output_section->vma
+ + sym_sec->output_offset;
+
+ if (debug_relax)
+ printf ("Checking if the relocation's "
+ "addend needs corrections.\n"
+ "Address of anchor symbol: 0x%x \n"
+ "Address of relocation target: 0x%x \n"
+ "Address of relaxed insn: 0x%x \n",
+ (unsigned int) symval,
+ (unsigned int) (symval + irel->r_addend),
+ (unsigned int) shrinked_insn_address);
+
+ /* Shrink the special DIFF relocations. */
+ if (elf32_pru_is_diff_reloc (irel))
+ {
+ elf32_pru_adjust_diff_reloc_value (abfd, isec, irel,
+ symval,
+ shrinked_insn_address,
+ count);
+ }
+
+ /* Fix the addend, if it is affected. */
+ if (symval <= shrinked_insn_address
+ && (symval + irel->r_addend) > shrinked_insn_address)
+ {
+
+ irel->r_addend -= count;
+
+ if (debug_relax)
+ printf ("Relocation's addend needed to be fixed \n");
+ }
+ }
+ /* else...Reference symbol is absolute.
+ No adjustment needed. */
+ }
+ /* else...Reference symbol is extern. No need for adjusting
+ the addend. */
+ }
+ }
+ }
+
+ /* Adjust the local symbols defined in this section. */
+ isym = (Elf_Internal_Sym *) symtab_hdr->contents;
+ /* Fix PR 9841, there may be no local symbols. */
+ if (isym != NULL)
+ {
+ Elf_Internal_Sym *isymend;
+
+ isymend = isym + symtab_hdr->sh_info;
+ for (; isym < isymend; isym++)
+ {
+ if (isym->st_shndx == sec_shndx)
+ {
+ if (isym->st_value > addr
+ && isym->st_value <= toaddr)
+ isym->st_value -= count;
+
+ if (isym->st_value <= addr
+ && isym->st_value + isym->st_size > addr)
+ {
+ /* If this assert fires then we have a symbol that ends
+ part way through an instruction. Does that make
+ sense? */
+ BFD_ASSERT (isym->st_value + isym->st_size >= addr + count);
+ isym->st_size -= count;
+ }
+ }
+ }
+ }
+
+ /* Now adjust the global symbols defined in this section. */
+ symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
+ - symtab_hdr->sh_info);
+ sym_hashes = elf_sym_hashes (abfd);
+ end_hashes = sym_hashes + symcount;
+ for (; sym_hashes < end_hashes; sym_hashes++)
+ {
+ struct elf_link_hash_entry *sym_hash = *sym_hashes;
+ if ((sym_hash->root.type == bfd_link_hash_defined
+ || sym_hash->root.type == bfd_link_hash_defweak)
+ && sym_hash->root.u.def.section == sec)
+ {
+ if (sym_hash->root.u.def.value > addr
+ && sym_hash->root.u.def.value <= toaddr)
+ sym_hash->root.u.def.value -= count;
+
+ if (sym_hash->root.u.def.value <= addr
+ && (sym_hash->root.u.def.value + sym_hash->size > addr))
+ {
+ /* If this assert fires then we have a symbol that ends
+ part way through an instruction. Does that make
+ sense? */
+ BFD_ASSERT (sym_hash->root.u.def.value + sym_hash->size
+ >= addr + count);
+ sym_hash->size -= count;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+static bfd_boolean
+pru_elf32_relax_section (bfd * abfd, asection * sec,
+ struct bfd_link_info * link_info,
+ bfd_boolean * again)
+{
+ Elf_Internal_Shdr * symtab_hdr;
+ Elf_Internal_Rela * internal_relocs;
+ Elf_Internal_Rela * irel;
+ Elf_Internal_Rela * irelend;
+ bfd_byte * contents = NULL;
+ Elf_Internal_Sym * isymbuf = NULL;
+
+ /* Assume nothing changes. */
+ *again = FALSE;
+
+ /* We don't have to do anything for a relocatable link, if
+ this section does not have relocs, or if this is not a
+ code section. */
+ if (bfd_link_relocatable (link_info)
+ || (sec->flags & SEC_RELOC) == 0
+ || sec->reloc_count == 0 || (sec->flags & SEC_CODE) == 0)
+ return TRUE;
+
+ symtab_hdr = & elf_tdata (abfd)->symtab_hdr;
+
+ /* Get a copy of the native relocations. */
+ internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL,
+ link_info->keep_memory);
+ if (internal_relocs == NULL)
+ goto error_return;
+
+ /* Walk through them looking for relaxing opportunities. */
+ irelend = internal_relocs + sec->reloc_count;
+
+ for (irel = internal_relocs; irel < irelend; irel++)
+ {
+ bfd_vma symval;
+
+ /* Get the section contents if we haven't done so already. */
+ if (contents == NULL)
+ {
+ /* Get cached copy if it exists. */
+ if (elf_section_data (sec)->this_hdr.contents != NULL)
+ contents = elf_section_data (sec)->this_hdr.contents;
+ else if (! bfd_malloc_and_get_section (abfd, sec, &contents))
+ goto error_return;
+ }
+
+ /* Read this BFD's local symbols if we haven't done so already. */
+ if (isymbuf == NULL && symtab_hdr->sh_info != 0)
+ {
+ isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
+ if (isymbuf == NULL)
+ isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
+ symtab_hdr->sh_info, 0,
+ NULL, NULL, NULL);
+ if (isymbuf == NULL)
+ goto error_return;
+ }
+
+ /* Get the value of the symbol referred to by the reloc. */
+ if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
+ {
+ /* A local symbol. */
+ Elf_Internal_Sym *isym;
+ asection *sym_sec;
+
+ isym = isymbuf + ELF32_R_SYM (irel->r_info);
+ if (isym->st_shndx == SHN_UNDEF)
+ sym_sec = bfd_und_section_ptr;
+ else if (isym->st_shndx == SHN_ABS)
+ sym_sec = bfd_abs_section_ptr;
+ else if (isym->st_shndx == SHN_COMMON)
+ sym_sec = bfd_com_section_ptr;
+ else
+ sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
+ symval = (isym->st_value
+ + sym_sec->output_section->vma + sym_sec->output_offset);
+ }
+ else
+ {
+ unsigned long indx;
+ struct elf_link_hash_entry *h;
+
+ /* An external symbol. */
+ indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
+ h = elf_sym_hashes (abfd)[indx];
+ BFD_ASSERT (h != NULL);
+
+ if (h->root.type != bfd_link_hash_defined
+ && h->root.type != bfd_link_hash_defweak)
+ /* This appears to be a reference to an undefined
+ symbol. Just ignore it--it will be caught by the
+ regular reloc processing. */
+ continue;
+
+ symval = (h->root.u.def.value
+ + h->root.u.def.section->output_section->vma
+ + h->root.u.def.section->output_offset);
+ }
+
+ /* For simplicity of coding, we are going to modify the section
+ contents, the section relocs, and the BFD symbol table. We
+ must tell the rest of the code not to free up this
+ information. It would be possible to instead create a table
+ of changes which have to be made, as is done in coff-mips.c;
+ that would be more work, but would require less memory when
+ the linker is run. */
+
+ /* Check if we can remove an LDI instruction from the LDI32
+ pseudo instruction if the upper 16 operand bits are zero. */
+ if (ELF32_R_TYPE (irel->r_info) == (int) R_PRU_LDI32)
+ {
+ bfd_vma value = symval + irel->r_addend;
+
+ if (debug_relax)
+ printf ("R_PRU_LDI32 with value=0x%lx\n", (long) value);
+
+ if ((long) value >> 16 == 0)
+ {
+ /* Note that we've changed the relocs, section contents. */
+ elf_section_data (sec)->relocs = internal_relocs;
+ elf_section_data (sec)->this_hdr.contents = contents;
+ symtab_hdr->contents = (unsigned char *) isymbuf;
+
+ /* Delete bytes. */
+ if (!pru_elf_relax_delete_bytes (abfd, sec, irel->r_offset + 4, 4))
+ goto error_return;
+
+ /* We're done with deletion of the second instruction.
+ Set a regular LDI relocation for the first instruction
+ we left to load the 16-bit value into the 32-bit
+ register. */
+ irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
+ R_PRU_U16);
+
+ /* That will change things, so, we should relax again.
+ Note that this is not required, and it may be slow. */
+ *again = TRUE;
+ }
+ }
+ }
+
+ if (isymbuf != NULL && symtab_hdr->contents != (unsigned char *) isymbuf)
+ {
+ if (!link_info->keep_memory)
+ free (isymbuf);
+ else
+ {
+ /* Cache the symbols for elf_link_input_bfd. */
+ symtab_hdr->contents = (unsigned char *) isymbuf;
+ }
+ }
+
+ if (contents != NULL
+ && elf_section_data (sec)->this_hdr.contents != contents)
+ {
+ if (!link_info->keep_memory)
+ free (contents);
+ else
+ {
+ /* Cache the section contents for elf_link_input_bfd. */
+ elf_section_data (sec)->this_hdr.contents = contents;
+ }
+ }
+
+ if (internal_relocs != NULL
+ && elf_section_data (sec)->relocs != internal_relocs)
+ free (internal_relocs);
+
+ return TRUE;
+
+error_return:
+ if (isymbuf != NULL && symtab_hdr->contents != (unsigned char *) isymbuf)
+ free (isymbuf);
+ if (contents != NULL
+ && elf_section_data (sec)->this_hdr.contents != contents)
+ free (contents);
+ if (internal_relocs != NULL
+ && elf_section_data (sec)->relocs != internal_relocs)
+ free (internal_relocs);
+
+ return FALSE;
+}
+
+/* Free the derived linker hash table. */
+static void
+pru_elf32_link_hash_table_free (bfd *obfd)
+{
+ _bfd_elf_link_hash_table_free (obfd);
+}
+
+/* Implement bfd_elf32_bfd_link_hash_table_create. */
+static struct bfd_link_hash_table *
+pru_elf32_link_hash_table_create (bfd *abfd)
+{
+ struct elf_link_hash_table *ret;
+ bfd_size_type amt = sizeof (struct elf_link_hash_table);
+
+ ret = bfd_zmalloc (amt);
+ if (ret == NULL)
+ return NULL;
+
+ if (!_bfd_elf_link_hash_table_init (ret, abfd,
+ link_hash_newfunc,
+ sizeof (struct
+ elf_link_hash_entry),
+ PRU_ELF_DATA))
+ {
+ free (ret);
+ return NULL;
+ }
+
+ ret->root.hash_table_free = pru_elf32_link_hash_table_free;
+
+ return &ret->root;
+}
+
+#define ELF_ARCH bfd_arch_pru
+#define ELF_TARGET_ID PRU_ELF_DATA
+#define ELF_MACHINE_CODE EM_TI_PRU
+
+#define ELF_MAXPAGESIZE 1
+
+#define bfd_elf32_bfd_link_hash_table_create \
+ pru_elf32_link_hash_table_create
+
+/* Relocation table lookup macros. */
+
+#define bfd_elf32_bfd_reloc_type_lookup pru_elf32_bfd_reloc_type_lookup
+#define bfd_elf32_bfd_reloc_name_lookup pru_elf32_bfd_reloc_name_lookup
+
+/* elf_info_to_howto (using RELA relocations). */
+
+#define elf_info_to_howto pru_elf32_info_to_howto
+
+/* elf backend functions. */
+
+#define elf_backend_rela_normal 1
+
+#define elf_backend_relocate_section pru_elf32_relocate_section
+#define bfd_elf32_bfd_relax_section pru_elf32_relax_section
+
+#define TARGET_LITTLE_SYM pru_elf32_vec
+#define TARGET_LITTLE_NAME "elf32-pru"
+
+#include "elf32-target.h"
diff --git a/bfd/reloc.c b/bfd/reloc.c
index 3c7b6060b0..4a79a230fd 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -6517,6 +6517,54 @@ ENUMDOC
Relocations used by the Altera Nios II core.
ENUM
+ BFD_RELOC_PRU_U16
+ENUMDOC
+ PRU LDI 16-bit unsigned data-memory relocation.
+ENUM
+ BFD_RELOC_PRU_U16_PMEMIMM
+ENUMDOC
+ PRU LDI 16-bit unsigned instruction-memory relocation.
+ENUM
+ BFD_RELOC_PRU_LDI32
+ENUMDOC
+ PRU relocation for two consecutive LDI load instructions that load a
+ 32 bit value into a register. If the higher bits are all zero, then
+ the second instruction may be relaxed.
+ENUM
+ BFD_RELOC_PRU_S10_PCREL
+ENUMDOC
+ PRU QBBx 10-bit signed PC-relative relocation.
+ENUM
+ BFD_RELOC_PRU_U8_PCREL
+ENUMDOC
+ PRU 8-bit unsigned relocation used for the LOOP instruction.
+ENUM
+ BFD_RELOC_PRU_32_PMEM
+ENUMX
+ BFD_RELOC_PRU_16_PMEM
+ENUMDOC
+ PRU Program Memory relocations. Used to convert from byte addressing to
+ 32-bit word addressing.
+ENUM
+ BFD_RELOC_PRU_GNU_DIFF8
+ENUMX
+ BFD_RELOC_PRU_GNU_DIFF16
+ENUMX
+ BFD_RELOC_PRU_GNU_DIFF32
+ENUMX
+ BFD_RELOC_PRU_GNU_DIFF16_PMEM
+ENUMX
+ BFD_RELOC_PRU_GNU_DIFF32_PMEM
+ENUMDOC
+ PRU relocations to mark the difference of two local symbols.
+ These are only needed to support linker relaxation and can be ignored
+ when not relaxing. The field is set to the value of the difference
+ assuming no relaxation. The relocation encodes the position of the
+ second symbol so the linker can determine whether to adjust the field
+ value. The PMEM variants encode the word difference, instead of byte
+ difference between symbols.
+
+ENUM
BFD_RELOC_IQ2000_OFFSET_16
ENUMX
BFD_RELOC_IQ2000_OFFSET_21
diff --git a/bfd/targets.c b/bfd/targets.c
index 8e6158e667..7ae8eb4225 100644
--- a/bfd/targets.c
+++ b/bfd/targets.c
@@ -799,6 +799,7 @@ extern const bfd_target powerpc_pe_le_vec;
extern const bfd_target powerpc_pei_vec;
extern const bfd_target powerpc_pei_le_vec;
extern const bfd_target powerpc_xcoff_vec;
+extern const bfd_target pru_elf32_vec;
extern const bfd_target riscv_elf32_vec;
extern const bfd_target riscv_elf64_vec;
extern const bfd_target rl78_elf32_vec;
@@ -1305,6 +1306,8 @@ static const bfd_target * const _bfd_target_vector[] =
&powerpc_xcoff_vec,
#endif
+ &pru_elf32_vec,
+
#ifdef BFD64
&riscv_elf32_vec,
&riscv_elf64_vec,
--
2.11.0
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v2 02/15] PRU Binutils port
2016-12-27 20:44 [PATCH v2 00/15] Binutils/gas/ld port for PRU Dimitar Dimitrov
2016-12-27 20:44 ` [PATCH v2 03/15] PRU GAS Port Dimitar Dimitrov
2016-12-27 20:44 ` [PATCH v2 13/15] ld: testsuite: Disable endsym test case Dimitar Dimitrov
@ 2016-12-27 20:44 ` Dimitar Dimitrov
2016-12-27 20:44 ` [PATCH v2 01/15] PRU BFD support Dimitar Dimitrov
` (12 subsequent siblings)
15 siblings, 0 replies; 19+ messages in thread
From: Dimitar Dimitrov @ 2016-12-27 20:44 UTC (permalink / raw)
To: binutils; +Cc: Dimitar Dimitrov
2016-12-26 Dimitar Dimitrov <dimitar@dinux.eu>
binutils/
* readelf.c (guess_is_rela): Add EM_TI_PRU.
(dump_relocations): Invoke elf_pru_reloc_type.
(get_machine_name): Handle EM_TI_PRU.
(is_32bit_abs_reloc): Handle R_PRU_BFD_RELOC_32.
(is_16bit_abs_reloc): Handle R_PRU_BFD_RELOC_16.
(is_none_reloc): Handle PRU_NONE and PRU_DIFF variants.
include/
* elf/common.h: Add PRU ELF.
* elf/pru.h: New file.
Signed-off-by: Dimitar Dimitrov <dimitar@dinux.eu>
---
binutils/readelf.c | 16 +++++++++++++++
include/elf/common.h | 2 +-
include/elf/pru.h | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 72 insertions(+), 1 deletion(-)
create mode 100644 include/elf/pru.h
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 873a471029..0a49e8a0d5 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -137,6 +137,7 @@
#include "elf/pj.h"
#include "elf/ppc.h"
#include "elf/ppc64.h"
+#include "elf/pru.h"
#include "elf/rl78.h"
#include "elf/rx.h"
#include "elf/s390.h"
@@ -776,6 +777,7 @@ guess_is_rela (unsigned int e_machine)
case EM_OR1K:
case EM_PPC64:
case EM_PPC:
+ case EM_TI_PRU:
case EM_RISCV:
case EM_RL78:
case EM_RX:
@@ -1483,6 +1485,10 @@ dump_relocations (FILE * file,
case EM_ALTERA_NIOS2:
rtype = elf_nios2_reloc_type (type);
break;
+
+ case EM_TI_PRU:
+ rtype = elf_pru_reloc_type (type);
+ break;
}
if (rtype == NULL)
@@ -2370,6 +2376,7 @@ get_machine_name (unsigned e_machine)
case EM_CSR_KALIMBA: return "CSR Kalimba architecture family";
case EM_Z80: return "Zilog Z80";
case EM_AMDGPU: return "AMD GPU architecture";
+ case EM_TI_PRU: return "TI PRU I/O processor";
default:
snprintf (buff, sizeof (buff), _("<unknown>: 0x%x"), e_machine);
return buff;
@@ -11852,6 +11859,8 @@ is_32bit_abs_reloc (unsigned int reloc_type)
return reloc_type == 1; /* R_PPC64_ADDR32. */
case EM_PPC:
return reloc_type == 1; /* R_PPC_ADDR32. */
+ case EM_TI_PRU:
+ return reloc_type == 11; /* R_PRU_BFD_RELOC_32. */
case EM_RISCV:
return reloc_type == 1; /* R_RISCV_32. */
case EM_RL78:
@@ -12134,6 +12143,8 @@ is_16bit_abs_reloc (unsigned int reloc_type)
return reloc_type == 9; /* R_NIOS_16. */
case EM_OR1K:
return reloc_type == 2; /* R_OR1K_16. */
+ case EM_TI_PRU:
+ return reloc_type == 8; /* R_PRU_BFD_RELOC_16. */
case EM_TI_C6000:
return reloc_type == 2; /* R_C6000_ABS16. */
case EM_VISIUM:
@@ -12210,6 +12221,11 @@ is_none_reloc (unsigned int reloc_type)
|| reloc_type == 205 /* R_NDS32_DIFF16. */
|| reloc_type == 206 /* R_NDS32_DIFF32. */
|| reloc_type == 207 /* R_NDS32_ULEB128. */);
+ case EM_TI_PRU:
+ return (reloc_type == 0 /* R_PRU_NONE. */
+ || reloc_type == 65 /* R_PRU_DIFF8. */
+ || reloc_type == 66 /* R_PRU_DIFF16. */
+ || reloc_type == 67 /* R_PRU_DIFF32. */);
case EM_XTENSA_OLD:
case EM_XTENSA:
return (reloc_type == 0 /* R_XTENSA_NONE. */
diff --git a/include/elf/common.h b/include/elf/common.h
index da79613e6d..192c585a72 100644
--- a/include/elf/common.h
+++ b/include/elf/common.h
@@ -248,7 +248,7 @@
#define EM_TI_C2000 141 /* Texas Instruments TMS320C2000 DSP family */
#define EM_TI_C5500 142 /* Texas Instruments TMS320C55x DSP family */
#define EM_res143 143 /* Reserved */
-#define EM_res144 144 /* Reserved */
+#define EM_TI_PRU 144 /* Texas Instruments Programmable Realtime Unit */
#define EM_res145 145 /* Reserved */
#define EM_res146 146 /* Reserved */
#define EM_res147 147 /* Reserved */
diff --git a/include/elf/pru.h b/include/elf/pru.h
new file mode 100644
index 0000000000..84501562ac
--- /dev/null
+++ b/include/elf/pru.h
@@ -0,0 +1,55 @@
+/* TI PRU ELF support for BFD.
+ Copyright (C) 2014-2016 Free Software Foundation, Inc.
+ Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
+
+ This file is part of BFD, the Binary File Descriptor library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+
+/* This file holds definitions specific to the TI PRU ELF ABI. Note
+ that most of this is not actually implemented by BFD. */
+
+#ifndef _ELF_PRU_H
+#define _ELF_PRU_H
+
+#include "elf/reloc-macros.h"
+
+START_RELOC_NUMBERS (elf_pru_reloc_type)
+ RELOC_NUMBER (R_PRU_NONE, 0)
+ RELOC_NUMBER (R_PRU_16_PMEM, 5)
+ RELOC_NUMBER (R_PRU_U16_PMEMIMM, 6)
+ RELOC_NUMBER (R_PRU_BFD_RELOC_16, 8)
+ RELOC_NUMBER (R_PRU_U16, 9)
+ RELOC_NUMBER (R_PRU_32_PMEM, 10)
+ RELOC_NUMBER (R_PRU_BFD_RELOC_32, 11)
+ RELOC_NUMBER (R_PRU_S10_PCREL, 14)
+ RELOC_NUMBER (R_PRU_U8_PCREL, 15)
+ RELOC_NUMBER (R_PRU_LDI32, 18)
+
+ /* Extensions required by GCC, or simply nice to have. */
+ RELOC_NUMBER (R_PRU_GNU_BFD_RELOC_8, 64)
+ RELOC_NUMBER (R_PRU_GNU_DIFF8, 65)
+ RELOC_NUMBER (R_PRU_GNU_DIFF16, 66)
+ RELOC_NUMBER (R_PRU_GNU_DIFF32, 67)
+ RELOC_NUMBER (R_PRU_GNU_DIFF16_PMEM, 68)
+ RELOC_NUMBER (R_PRU_GNU_DIFF32_PMEM, 69)
+ RELOC_NUMBER (R_PRU_ILLEGAL, 70)
+END_RELOC_NUMBERS (R_PRU_maxext)
+
+/* Processor-specific section flags. */
+
+#endif /* _ELF_PRU_H */
--
2.11.0
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v2 00/15] Binutils/gas/ld port for PRU
@ 2016-12-27 20:44 Dimitar Dimitrov
2016-12-27 20:44 ` [PATCH v2 03/15] PRU GAS Port Dimitar Dimitrov
` (15 more replies)
0 siblings, 16 replies; 19+ messages in thread
From: Dimitar Dimitrov @ 2016-12-27 20:44 UTC (permalink / raw)
To: binutils; +Cc: Dimitar Dimitrov
I hope I have addressed all comments from the initial submission. Biggest change
in v2 is the major rework of relocations to make the GNU PRU port compatible with TI's proprietary toolchain ELF format. I still have not implemented TI's debug info relocations, but they may come as another patch in the future.
My TI PRU ELF reverse-engineering notes are here: https://github.com/dinuxbg/gnupru/wiki .
I have also used a simple sanity check test to ensure that GNU LD can link TI CLPRU object files: https://github.com/dinuxbg/gnupru/tree/for-next/testing/interop
v2
- BFD: Removed HI16/LO16 relocations as they were non-standard and not
supported by the TI proprietary toolchain.
- BFD: Added LDI32 relocation as supported by the TI proprietary toolchain.
- AS,BFD: Removed leading symbol underscore in order to be compatible with
TI's ABI.
- BFD: Assigned relocation numbers in order to be compatible with
TI's toolchain.
- Fixed changelog snippets.
- Removed auto-generated files from patches.
- LD: Fix default linker script for 'ld -r'
- Switch to r3.w2 as return address for the call and ret pseudos. This will
help keeping the same ABI with TI's C compiler.
- BFD: Use EM_TI_PRU for ELF machine ID.
- GAS: Make use of bfd_check_overflow.
- BFD: Set src_mask=0 because PRU has USE_RELA.
- BFD: Get rid of unneeded PRU hash.
- LD: Remove gc-sections flag as we do not support it. Update the testsuite
accordingly.
v1
Initial submission: https://sourceware.org/ml/binutils/2016-12/msg00066.html
Dimitar Dimitrov (15):
PRU BFD support
PRU Binutils port
PRU GAS Port
PRU LD Port
PRU Opcode Port
Add PRU ELF ID to elfcpp
ld: testsuite: Mark PRU as elf target that does not support shared
libraries
ld: testsuite: Mark sec64k case as too big for PRU
ld: testsuite: Fix srec test setup for PRU
gas: testsuite: Mark lns-common-1-alt variant for PRU
ld: testsuite: PRU assembler does not support diff expressions mixing
data and text labels.
ld: testsuite: PRU LD does not support arbitrary .text base addresses.
ld: testsuite: Disable endsym test case
ld: testsuite: Sanitize output from ld
ld: testsuite: Mark --gc-sections as unsupported for PRU
bfd/Makefile.am | 4 +
bfd/archures.c | 4 +
bfd/config.bfd | 6 +
bfd/configure.ac | 1 +
bfd/cpu-pru.c | 43 +
bfd/elf-bfd.h | 1 +
bfd/elf32-pru.c | 1469 ++++++++++++++++++++++
bfd/reloc.c | 48 +
bfd/targets.c | 3 +
binutils/readelf.c | 16 +
elfcpp/elfcpp.h | 1 +
gas/Makefile.am | 2 +
gas/NEWS | 2 +
gas/config/obj-elf.c | 4 +
gas/config/tc-pru.c | 1946 ++++++++++++++++++++++++++++++
gas/config/tc-pru.h | 154 +++
gas/configure.tgt | 2 +
gas/doc/Makefile.am | 1 +
gas/doc/all.texi | 1 +
gas/doc/as.texinfo | 32 +
gas/doc/c-pru.texi | 150 +++
gas/testsuite/gas/lns/lns.exp | 1 +
gas/testsuite/gas/pru/alu.d | 32 +
gas/testsuite/gas/pru/alu.s | 30 +
gas/testsuite/gas/pru/branch.d | 63 +
gas/testsuite/gas/pru/branch.s | 42 +
gas/testsuite/gas/pru/illegal.l | 5 +
gas/testsuite/gas/pru/illegal.s | 11 +
gas/testsuite/gas/pru/ldi.d | 17 +
gas/testsuite/gas/pru/ldi.s | 9 +
gas/testsuite/gas/pru/ldst.d | 33 +
gas/testsuite/gas/pru/ldst.s | 37 +
gas/testsuite/gas/pru/loop.d | 15 +
gas/testsuite/gas/pru/loop.s | 10 +
gas/testsuite/gas/pru/misc.d | 12 +
gas/testsuite/gas/pru/misc.s | 6 +
gas/testsuite/gas/pru/pru.exp | 26 +
gas/testsuite/gas/pru/pseudo.d | 15 +
gas/testsuite/gas/pru/pseudo.s | 10 +
gas/testsuite/gas/pru/warn_reglabel.l | 3 +
gas/testsuite/gas/pru/warn_reglabel.s | 6 +
gas/testsuite/gas/pru/xfr.d | 44 +
gas/testsuite/gas/pru/xfr.s | 52 +
include/dis-asm.h | 1 +
include/elf/common.h | 2 +-
include/elf/pru.h | 55 +
include/opcode/pru.h | 411 +++++++
ld/Makefile.am | 6 +
ld/NEWS | 2 +
ld/configure.tgt | 1 +
ld/emulparams/pruelf.sh | 19 +
ld/emultempl/pruelf.em | 50 +
ld/scripttempl/pru.sc | 179 +++
ld/testsuite/ld-elf/eh-frame-hdr.d | 2 +-
ld/testsuite/ld-elf/endsym.d | 1 +
ld/testsuite/ld-elf/group8a.d | 2 +-
ld/testsuite/ld-elf/group8b.d | 2 +-
ld/testsuite/ld-elf/group9a.d | 2 +-
ld/testsuite/ld-elf/group9b.d | 2 +-
ld/testsuite/ld-elf/merge.d | 2 +-
ld/testsuite/ld-elf/pr12851.d | 2 +-
ld/testsuite/ld-elf/pr14926.d | 2 +-
ld/testsuite/ld-elf/sec-to-seg.exp | 1 +
ld/testsuite/ld-elf/sec64k.exp | 3 +-
ld/testsuite/ld-pru/emit-relocs-1.d | 37 +
ld/testsuite/ld-pru/emit-relocs-1.ld | 20 +
ld/testsuite/ld-pru/emit-relocs-1a.s | 24 +
ld/testsuite/ld-pru/emit-relocs-1b.s | 18 +
ld/testsuite/ld-pru/ldi32.d | 12 +
ld/testsuite/ld-pru/ldi32.s | 6 +
ld/testsuite/ld-pru/ldi32_symbol.s | 3 +
ld/testsuite/ld-pru/norelax_ldi32-data.d | 20 +
ld/testsuite/ld-pru/norelax_ldi32-dis.d | 29 +
ld/testsuite/ld-pru/pcrel_s10.d | 18 +
ld/testsuite/ld-pru/pcrel_s10.s | 8 +
ld/testsuite/ld-pru/pcrel_s10_label.s | 9 +
ld/testsuite/ld-pru/pcrel_u8-illegal.d | 7 +
ld/testsuite/ld-pru/pcrel_u8-illegal.s | 10 +
ld/testsuite/ld-pru/pcrel_u8-illegal2.d | 7 +
ld/testsuite/ld-pru/pcrel_u8-illegal2.s | 7 +
ld/testsuite/ld-pru/pcrel_u8-illegal3.d | 7 +
ld/testsuite/ld-pru/pcrel_u8-illegal3.s | 7 +
ld/testsuite/ld-pru/pcrel_u8.d | 15 +
ld/testsuite/ld-pru/pcrel_u8.s | 10 +
ld/testsuite/ld-pru/pcrel_u8_label.s | 4 +
ld/testsuite/ld-pru/pmem.d | 15 +
ld/testsuite/ld-pru/pmem.s | 15 +
ld/testsuite/ld-pru/pmem_symbol.s | 15 +
ld/testsuite/ld-pru/pru.exp | 9 +
ld/testsuite/ld-pru/relax_ldi32-data.d | 19 +
ld/testsuite/ld-pru/relax_ldi32-dis.d | 27 +
ld/testsuite/ld-pru/relax_ldi32.s | 30 +
ld/testsuite/ld-pru/relax_ldi32_symbol.s | 6 +
ld/testsuite/ld-pru/reloc.d | 14 +
ld/testsuite/ld-pru/reloc.s | 9 +
ld/testsuite/ld-pru/reloc_symbol.s | 25 +
ld/testsuite/ld-pru/u16.d | 11 +
ld/testsuite/ld-pru/u16.s | 4 +
ld/testsuite/ld-pru/u16_symbol.s | 3 +
ld/testsuite/ld-srec/srec.exp | 5 +
ld/testsuite/lib/ld-lib.exp | 8 +-
opcodes/Makefile.am | 2 +
opcodes/configure.ac | 1 +
opcodes/disassemble.c | 7 +-
opcodes/pru-dis.c | 286 +++++
opcodes/pru-opc.c | 236 ++++
106 files changed, 6127 insertions(+), 14 deletions(-)
create mode 100644 bfd/cpu-pru.c
create mode 100644 bfd/elf32-pru.c
create mode 100644 gas/config/tc-pru.c
create mode 100644 gas/config/tc-pru.h
create mode 100644 gas/doc/c-pru.texi
create mode 100644 gas/testsuite/gas/pru/alu.d
create mode 100644 gas/testsuite/gas/pru/alu.s
create mode 100644 gas/testsuite/gas/pru/branch.d
create mode 100644 gas/testsuite/gas/pru/branch.s
create mode 100644 gas/testsuite/gas/pru/illegal.l
create mode 100644 gas/testsuite/gas/pru/illegal.s
create mode 100644 gas/testsuite/gas/pru/ldi.d
create mode 100644 gas/testsuite/gas/pru/ldi.s
create mode 100644 gas/testsuite/gas/pru/ldst.d
create mode 100644 gas/testsuite/gas/pru/ldst.s
create mode 100644 gas/testsuite/gas/pru/loop.d
create mode 100644 gas/testsuite/gas/pru/loop.s
create mode 100644 gas/testsuite/gas/pru/misc.d
create mode 100644 gas/testsuite/gas/pru/misc.s
create mode 100644 gas/testsuite/gas/pru/pru.exp
create mode 100644 gas/testsuite/gas/pru/pseudo.d
create mode 100644 gas/testsuite/gas/pru/pseudo.s
create mode 100644 gas/testsuite/gas/pru/warn_reglabel.l
create mode 100644 gas/testsuite/gas/pru/warn_reglabel.s
create mode 100644 gas/testsuite/gas/pru/xfr.d
create mode 100644 gas/testsuite/gas/pru/xfr.s
create mode 100644 include/elf/pru.h
create mode 100644 include/opcode/pru.h
create mode 100644 ld/emulparams/pruelf.sh
create mode 100644 ld/emultempl/pruelf.em
create mode 100644 ld/scripttempl/pru.sc
create mode 100644 ld/testsuite/ld-pru/emit-relocs-1.d
create mode 100644 ld/testsuite/ld-pru/emit-relocs-1.ld
create mode 100644 ld/testsuite/ld-pru/emit-relocs-1a.s
create mode 100644 ld/testsuite/ld-pru/emit-relocs-1b.s
create mode 100644 ld/testsuite/ld-pru/ldi32.d
create mode 100644 ld/testsuite/ld-pru/ldi32.s
create mode 100644 ld/testsuite/ld-pru/ldi32_symbol.s
create mode 100644 ld/testsuite/ld-pru/norelax_ldi32-data.d
create mode 100644 ld/testsuite/ld-pru/norelax_ldi32-dis.d
create mode 100644 ld/testsuite/ld-pru/pcrel_s10.d
create mode 100644 ld/testsuite/ld-pru/pcrel_s10.s
create mode 100644 ld/testsuite/ld-pru/pcrel_s10_label.s
create mode 100644 ld/testsuite/ld-pru/pcrel_u8-illegal.d
create mode 100644 ld/testsuite/ld-pru/pcrel_u8-illegal.s
create mode 100644 ld/testsuite/ld-pru/pcrel_u8-illegal2.d
create mode 100644 ld/testsuite/ld-pru/pcrel_u8-illegal2.s
create mode 100644 ld/testsuite/ld-pru/pcrel_u8-illegal3.d
create mode 100644 ld/testsuite/ld-pru/pcrel_u8-illegal3.s
create mode 100644 ld/testsuite/ld-pru/pcrel_u8.d
create mode 100644 ld/testsuite/ld-pru/pcrel_u8.s
create mode 100644 ld/testsuite/ld-pru/pcrel_u8_label.s
create mode 100644 ld/testsuite/ld-pru/pmem.d
create mode 100644 ld/testsuite/ld-pru/pmem.s
create mode 100644 ld/testsuite/ld-pru/pmem_symbol.s
create mode 100644 ld/testsuite/ld-pru/pru.exp
create mode 100644 ld/testsuite/ld-pru/relax_ldi32-data.d
create mode 100644 ld/testsuite/ld-pru/relax_ldi32-dis.d
create mode 100644 ld/testsuite/ld-pru/relax_ldi32.s
create mode 100644 ld/testsuite/ld-pru/relax_ldi32_symbol.s
create mode 100644 ld/testsuite/ld-pru/reloc.d
create mode 100644 ld/testsuite/ld-pru/reloc.s
create mode 100644 ld/testsuite/ld-pru/reloc_symbol.s
create mode 100644 ld/testsuite/ld-pru/u16.d
create mode 100644 ld/testsuite/ld-pru/u16.s
create mode 100644 ld/testsuite/ld-pru/u16_symbol.s
create mode 100644 opcodes/pru-dis.c
create mode 100644 opcodes/pru-opc.c
--
2.11.0
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v2 09/15] ld: testsuite: Fix srec test setup for PRU
2016-12-27 20:44 [PATCH v2 00/15] Binutils/gas/ld port for PRU Dimitar Dimitrov
` (3 preceding siblings ...)
2016-12-27 20:44 ` [PATCH v2 01/15] PRU BFD support Dimitar Dimitrov
@ 2016-12-27 20:44 ` Dimitar Dimitrov
2016-12-27 20:45 ` [PATCH v2 12/15] ld: testsuite: PRU LD does not support arbitrary .text base addresses Dimitar Dimitrov
` (10 subsequent siblings)
15 siblings, 0 replies; 19+ messages in thread
From: Dimitar Dimitrov @ 2016-12-27 20:44 UTC (permalink / raw)
To: binutils; +Cc: Dimitar Dimitrov
2016-12-26 Dimitar Dimitrov <dimitar@dinux.eu>
ld/
* testsuite/ld-srec/srec.exp (run_srec_test): Fix srec test setup
for PRU.
Signed-off-by: Dimitar Dimitrov <dimitar@dinux.eu>
---
ld/testsuite/ld-srec/srec.exp | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/ld/testsuite/ld-srec/srec.exp b/ld/testsuite/ld-srec/srec.exp
index 9fcf07ac58..10b0a51347 100644
--- a/ld/testsuite/ld-srec/srec.exp
+++ b/ld/testsuite/ld-srec/srec.exp
@@ -300,6 +300,11 @@ proc run_srec_test { test objs } {
set flags "$flags -no-relax"
}
+ # PRU ELF target relaxes by default; S-Record linker does not
+ if [istarget pru*-*-*] {
+ set flags "$flags -no-relax"
+ }
+
if { ![ld_simple_link $ld tmpdir/sr1 "$flags $objs"] \
|| ![ld_simple_link $ld tmpdir/sr2.sr "$flags --oformat srec $objs"] } {
fail $test
--
2.11.0
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v2 13/15] ld: testsuite: Disable endsym test case
2016-12-27 20:44 [PATCH v2 00/15] Binutils/gas/ld port for PRU Dimitar Dimitrov
2016-12-27 20:44 ` [PATCH v2 03/15] PRU GAS Port Dimitar Dimitrov
@ 2016-12-27 20:44 ` Dimitar Dimitrov
2016-12-27 20:44 ` [PATCH v2 02/15] PRU Binutils port Dimitar Dimitrov
` (13 subsequent siblings)
15 siblings, 0 replies; 19+ messages in thread
From: Dimitar Dimitrov @ 2016-12-27 20:44 UTC (permalink / raw)
To: binutils; +Cc: Dimitar Dimitrov
PRU does not export __end symbol because it is ambiguous for it.
Users are expected to use instead the section markers __text_end,
__data_end, __bss_end or __noinit_end.
2016-12-26 Dimitar Dimitrov <dimitar@dinux.eu>
ld/
* testsuite/ld-elf/endsym.d: Disable for PRU.
Signed-off-by: Dimitar Dimitrov <dimitar@dinux.eu>
---
ld/testsuite/ld-elf/endsym.d | 1 +
1 file changed, 1 insertion(+)
diff --git a/ld/testsuite/ld-elf/endsym.d b/ld/testsuite/ld-elf/endsym.d
index eefdd43912..3472154e18 100644
--- a/ld/testsuite/ld-elf/endsym.d
+++ b/ld/testsuite/ld-elf/endsym.d
@@ -4,6 +4,7 @@
#nm: -n
#notarget: hppa*-*-hpux*
#xfail: m68hc1*-* xgate-* cr16-*-* crx-*-* dlx-*-* nds32*-*-* visium-*-*
+#xfail: pru-*-*
#...
.* end
--
2.11.0
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v2 03/15] PRU GAS Port
2016-12-27 20:44 [PATCH v2 00/15] Binutils/gas/ld port for PRU Dimitar Dimitrov
@ 2016-12-27 20:44 ` Dimitar Dimitrov
2016-12-27 20:44 ` [PATCH v2 13/15] ld: testsuite: Disable endsym test case Dimitar Dimitrov
` (14 subsequent siblings)
15 siblings, 0 replies; 19+ messages in thread
From: Dimitar Dimitrov @ 2016-12-27 20:44 UTC (permalink / raw)
To: binutils; +Cc: Dimitar Dimitrov
2016-12-26 Dimitar Dimitrov <dimitar@dinux.eu>
gas/
* Makefile.in: Regenerate.
* doc/Makefile.in: Regenerate.
* po/POTFILES.in: Regenerate.
* NEWS: Mention new PRU target.
* Makefile.am: Add PRU target.
* config/obj-elf.c: Ditto.
* configure.tgt: Ditto.
* config/tc-pru.c: New file.
* config/tc-pru.h: New file.
* doc/Makefile.am: Add documentation for PRU GAS port.
* doc/all.texi, Ditto.
* doc/as.texinfo: Ditto.
* doc/c-pru.texi: Document PRU GAS options.
* testsuite/gas/pru/alu.d: New file for PRU GAS testsuite.
* testsuite/gas/pru/alu.s: Ditto.
* testsuite/gas/pru/branch.d: Ditto.
* testsuite/gas/pru/branch.s: Ditto.
* testsuite/gas/pru/illegal.l: Ditto.
* testsuite/gas/pru/illegal.s: Ditto.
* testsuite/gas/pru/ldi.d: Ditto.
* testsuite/gas/pru/ldi.s: Ditto.
* testsuite/gas/pru/ldst.d: Ditto.
* testsuite/gas/pru/ldst.s: Ditto.
* testsuite/gas/pru/loop.d: Ditto.
* testsuite/gas/pru/loop.s: Ditto.
* testsuite/gas/pru/misc.d: Ditto.
* testsuite/gas/pru/misc.s: Ditto.
* testsuite/gas/pru/pru.exp: Ditto.
* testsuite/gas/pru/pseudo.d: Ditto.
* testsuite/gas/pru/pseudo.s: Ditto.
* testsuite/gas/pru/warn_reglabel.l: Ditto.
* testsuite/gas/pru/warn_reglabel.s: Ditto.
* testsuite/gas/pru/xfr.d: Ditto.
* testsuite/gas/pru/xfr.s: Ditto.
Signed-off-by: Dimitar Dimitrov <dimitar@dinux.eu>
---
gas/Makefile.am | 2 +
gas/NEWS | 2 +
gas/config/obj-elf.c | 4 +
gas/config/tc-pru.c | 1946 +++++++++++++++++++++++++++++++++
gas/config/tc-pru.h | 154 +++
gas/configure.tgt | 2 +
gas/doc/Makefile.am | 1 +
gas/doc/all.texi | 1 +
gas/doc/as.texinfo | 32 +
gas/doc/c-pru.texi | 150 +++
gas/testsuite/gas/pru/alu.d | 32 +
gas/testsuite/gas/pru/alu.s | 30 +
gas/testsuite/gas/pru/branch.d | 63 ++
gas/testsuite/gas/pru/branch.s | 42 +
gas/testsuite/gas/pru/illegal.l | 5 +
gas/testsuite/gas/pru/illegal.s | 11 +
gas/testsuite/gas/pru/ldi.d | 17 +
gas/testsuite/gas/pru/ldi.s | 9 +
gas/testsuite/gas/pru/ldst.d | 33 +
gas/testsuite/gas/pru/ldst.s | 37 +
gas/testsuite/gas/pru/loop.d | 15 +
gas/testsuite/gas/pru/loop.s | 10 +
gas/testsuite/gas/pru/misc.d | 12 +
gas/testsuite/gas/pru/misc.s | 6 +
gas/testsuite/gas/pru/pru.exp | 26 +
gas/testsuite/gas/pru/pseudo.d | 15 +
gas/testsuite/gas/pru/pseudo.s | 10 +
gas/testsuite/gas/pru/warn_reglabel.l | 3 +
gas/testsuite/gas/pru/warn_reglabel.s | 6 +
gas/testsuite/gas/pru/xfr.d | 44 +
gas/testsuite/gas/pru/xfr.s | 52 +
31 files changed, 2772 insertions(+)
create mode 100644 gas/config/tc-pru.c
create mode 100644 gas/config/tc-pru.h
create mode 100644 gas/doc/c-pru.texi
create mode 100644 gas/testsuite/gas/pru/alu.d
create mode 100644 gas/testsuite/gas/pru/alu.s
create mode 100644 gas/testsuite/gas/pru/branch.d
create mode 100644 gas/testsuite/gas/pru/branch.s
create mode 100644 gas/testsuite/gas/pru/illegal.l
create mode 100644 gas/testsuite/gas/pru/illegal.s
create mode 100644 gas/testsuite/gas/pru/ldi.d
create mode 100644 gas/testsuite/gas/pru/ldi.s
create mode 100644 gas/testsuite/gas/pru/ldst.d
create mode 100644 gas/testsuite/gas/pru/ldst.s
create mode 100644 gas/testsuite/gas/pru/loop.d
create mode 100644 gas/testsuite/gas/pru/loop.s
create mode 100644 gas/testsuite/gas/pru/misc.d
create mode 100644 gas/testsuite/gas/pru/misc.s
create mode 100644 gas/testsuite/gas/pru/pru.exp
create mode 100644 gas/testsuite/gas/pru/pseudo.d
create mode 100644 gas/testsuite/gas/pru/pseudo.s
create mode 100644 gas/testsuite/gas/pru/warn_reglabel.l
create mode 100644 gas/testsuite/gas/pru/warn_reglabel.s
create mode 100644 gas/testsuite/gas/pru/xfr.d
create mode 100644 gas/testsuite/gas/pru/xfr.s
diff --git a/gas/Makefile.am b/gas/Makefile.am
index cac7c7f8fd..3bfab34959 100644
--- a/gas/Makefile.am
+++ b/gas/Makefile.am
@@ -177,6 +177,7 @@ TARGET_CPU_CFILES = \
config/tc-pdp11.c \
config/tc-pj.c \
config/tc-ppc.c \
+ config/tc-pru.c \
config/tc-riscv.c \
config/tc-rl78.c \
config/tc-rx.c \
@@ -251,6 +252,7 @@ TARGET_CPU_HFILES = \
config/tc-pdp11.h \
config/tc-pj.h \
config/tc-ppc.h \
+ config/tc-pru.h \
config/tc-riscv.h \
config/tc-rl78.h \
config/tc-rx.h \
diff --git a/gas/NEWS b/gas/NEWS
index 8a62c2f272..0d62a6dbba 100644
--- a/gas/NEWS
+++ b/gas/NEWS
@@ -1,5 +1,7 @@
-*- text -*-
+* Add support for the Texas Instruments PRU processor.
+
Changes in 2.28:
* Add support for the RISC-V architecture.
diff --git a/gas/config/obj-elf.c b/gas/config/obj-elf.c
index 8d80c77f15..a1b882e655 100644
--- a/gas/config/obj-elf.c
+++ b/gas/config/obj-elf.c
@@ -64,6 +64,10 @@
#include "elf/nios2.h"
#endif
+#ifdef TC_PRU
+#include "elf/pru.h"
+#endif
+
static void obj_elf_line (int);
static void obj_elf_size (int);
static void obj_elf_type (int);
diff --git a/gas/config/tc-pru.c b/gas/config/tc-pru.c
new file mode 100644
index 0000000000..63aca6e442
--- /dev/null
+++ b/gas/config/tc-pru.c
@@ -0,0 +1,1946 @@
+/* TI PRU assembler.
+ Copyright (C) 2014-2016 Free Software Foundation, Inc.
+ Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
+ Based on tc-nios2.c
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to the Free
+ Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#include "as.h"
+#include "bfd_stdint.h"
+#include "opcode/pru.h"
+#include "elf/pru.h"
+#include "tc-pru.h"
+#include "bfd.h"
+#include "dwarf2dbg.h"
+#include "subsegs.h"
+#include "safe-ctype.h"
+#include "dw2gencfi.h"
+
+#ifndef OBJ_ELF
+/* We are not supporting any other target so we throw a compile time error. */
+ #error "OBJ_ELF not defined"
+#endif
+
+/* This array holds the chars that always start a comment. If the
+ pre-processor is disabled, these aren't very useful. */
+const char comment_chars[] = "#;";
+
+/* This array holds the chars that only start a comment at the beginning of
+ a line. If the line seems to have the form '# 123 filename'
+ .line and .file directives will appear in the pre-processed output. */
+/* Note that input_file.c hand checks for '#' at the beginning of the
+ first line of the input file. This is because the compiler outputs
+ #NO_APP at the beginning of its output. */
+/* Also note that C style comments are always supported. */
+const char line_comment_chars[] = "#;*";
+
+/* This array holds machine specific line separator characters. */
+const char line_separator_chars[] = "";
+
+/* Chars that can be used to separate mant from exp in floating point nums. */
+const char EXP_CHARS[] = "eE";
+
+/* Chars that mean this number is a floating point constant.
+ As in 0f12.456
+ or 0d1.2345e12 */
+const char FLT_CHARS[] = "rRsSfFdDxXpP";
+
+/* Machine-dependent command-line options. */
+
+struct pru_opt_s
+{
+ /* -mno-link-relax / -mlink-relax: generate (or not)
+ relocations for linker relaxation. */
+ bfd_boolean link_relax;
+
+ /* -mno-warn-regname-label: do not output a warning that a label name
+ matches a register name. */
+ bfd_boolean warn_regname_label;
+};
+
+static struct pru_opt_s pru_opt = { TRUE, TRUE };
+
+const char *md_shortopts = "r";
+
+enum options
+{
+ OPTION_LINK_RELAX = OPTION_MD_BASE + 1,
+ OPTION_NO_LINK_RELAX,
+ OPTION_NO_WARN_REGNAME_LABEL,
+};
+
+struct option md_longopts[] = {
+ { "mlink-relax", no_argument, NULL, OPTION_LINK_RELAX },
+ { "mno-link-relax", no_argument, NULL, OPTION_NO_LINK_RELAX },
+ { "mno-warn-regname-label", no_argument, NULL,
+ OPTION_NO_WARN_REGNAME_LABEL },
+ { NULL, no_argument, NULL, 0 }
+};
+
+size_t md_longopts_size = sizeof (md_longopts);
+
+typedef struct pru_insn_reloc
+{
+ /* Any expression in the instruction is parsed into this field,
+ which is passed to fix_new_exp () to generate a fixup. */
+ expressionS reloc_expression;
+
+ /* The type of the relocation to be applied. */
+ bfd_reloc_code_real_type reloc_type;
+
+ /* PC-relative. */
+ unsigned int reloc_pcrel;
+
+ /* The next relocation to be applied to the instruction. */
+ struct pru_insn_reloc *reloc_next;
+} pru_insn_relocS;
+
+/* This struct is used to hold state when assembling instructions. */
+typedef struct pru_insn_info
+{
+ /* Assembled instruction. */
+ unsigned long insn_code;
+ /* Used for assembling LDI32. */
+ unsigned long ldi32_imm32;
+
+ /* Pointer to the relevant bit of the opcode table. */
+ const struct pru_opcode *insn_pru_opcode;
+ /* After parsing ptrs to the tokens in the instruction fill this array
+ it is terminated with a null pointer (hence the first +1).
+ The second +1 is because in some parts of the code the opcode
+ is not counted as a token, but still placed in this array. */
+ const char *insn_tokens[PRU_MAX_INSN_TOKENS + 1 + 1];
+
+ /* This holds information used to generate fixups
+ and eventually relocations if it is not null. */
+ pru_insn_relocS *insn_reloc;
+} pru_insn_infoS;
+
+/* Opcode hash table. */
+static struct hash_control *pru_opcode_hash = NULL;
+#define pru_opcode_lookup(NAME) \
+ ((struct pru_opcode *) hash_find (pru_opcode_hash, (NAME)))
+
+/* Register hash table. */
+static struct hash_control *pru_reg_hash = NULL;
+#define pru_reg_lookup(NAME) \
+ ((struct pru_reg *) hash_find (pru_reg_hash, (NAME)))
+
+/* The known current alignment of the current section. */
+static int pru_current_align;
+static segT pru_current_align_seg;
+
+static int pru_auto_align_on = 1;
+
+/* The last seen label in the current section. This is used to auto-align
+ labels preceeding instructions. */
+static symbolS *pru_last_label;
+
+\f
+/** Utility routines. */
+/* Function md_chars_to_number takes the sequence of
+ bytes in buf and returns the corresponding value
+ in an int. n must be 1, 2, 4 or 8. */
+static uint64_t
+md_chars_to_number (char *buf, int n)
+{
+ int i;
+ uint64_t val;
+
+ gas_assert (n == 1 || n == 2 || n == 4 || n == 8);
+
+ val = 0;
+ for (i = 0; i < n; ++i)
+ val = val | ((buf[i] & 0xff) << 8 * i);
+ return val;
+}
+
+
+/* This function turns a C long int, short int or char
+ into the series of bytes that represent the number
+ on the target machine. */
+void
+md_number_to_chars (char *buf, uint64_t val, int n)
+{
+ gas_assert (n == 1 || n == 2 || n == 4 || n == 8);
+ number_to_chars_littleendian (buf, val, n);
+}
+
+/* Turn a string in input_line_pointer into a floating point constant
+ of type TYPE, and store the appropriate bytes in *LITP. The number
+ of LITTLENUMS emitted is stored in *SIZEP. An error message is
+ returned, or NULL on OK. */
+const char *
+md_atof (int type, char *litP, int *sizeP)
+{
+ return ieee_md_atof (type, litP, sizeP, FALSE);
+}
+
+/* Return true if STR starts with PREFIX, which should be a string literal. */
+#define strprefix(STR, PREFIX) \
+ (strncmp ((STR), PREFIX, strlen (PREFIX)) == 0)
+
+/* nop fill pattern for text section. */
+static char const nop[4] = { 0xe0, 0xe0, 0xe0, 0x12 };
+
+/* Handles all machine-dependent alignment needs. */
+static void
+pru_align (int log_size, const char *pfill, symbolS *label)
+{
+ int align;
+ long max_alignment = 15;
+
+ /* The front end is prone to changing segments out from under us
+ temporarily when -g is in effect. */
+ int switched_seg_p = (pru_current_align_seg != now_seg);
+
+ align = log_size;
+ if (align > max_alignment)
+ {
+ align = max_alignment;
+ as_bad (_("Alignment too large: %d assumed"), align);
+ }
+ else if (align < 0)
+ {
+ as_warn (_("Alignment negative: 0 assumed"));
+ align = 0;
+ }
+
+ if (align != 0)
+ {
+ if (subseg_text_p (now_seg) && align >= 2)
+ {
+ /* First, make sure we're on a four-byte boundary, in case
+ someone has been putting .byte values the text section. */
+ if (pru_current_align < 2 || switched_seg_p)
+ frag_align (2, 0, 0);
+
+ /* Now fill in the alignment pattern. */
+ if (pfill != NULL)
+ frag_align_pattern (align, pfill, sizeof nop, 0);
+ else
+ frag_align (align, 0, 0);
+ }
+ else
+ frag_align (align, 0, 0);
+
+ if (!switched_seg_p)
+ pru_current_align = align;
+
+ /* If the last label was in a different section we can't align it. */
+ if (label != NULL && !switched_seg_p)
+ {
+ symbolS *sym;
+ int label_seen = FALSE;
+ struct frag *old_frag;
+ valueT old_value;
+ valueT new_value;
+
+ gas_assert (S_GET_SEGMENT (label) == now_seg);
+
+ old_frag = symbol_get_frag (label);
+ old_value = S_GET_VALUE (label);
+ new_value = (valueT) frag_now_fix ();
+
+ /* It is possible to have more than one label at a particular
+ address, especially if debugging is enabled, so we must
+ take care to adjust all the labels at this address in this
+ fragment. To save time we search from the end of the symbol
+ list, backwards, since the symbols we are interested in are
+ almost certainly the ones that were most recently added.
+ Also to save time we stop searching once we have seen at least
+ one matching label, and we encounter a label that is no longer
+ in the target fragment. Note, this search is guaranteed to
+ find at least one match when sym == label, so no special case
+ code is necessary. */
+ for (sym = symbol_lastP; sym != NULL; sym = symbol_previous (sym))
+ if (symbol_get_frag (sym) == old_frag
+ && S_GET_VALUE (sym) == old_value)
+ {
+ label_seen = TRUE;
+ symbol_set_frag (sym, frag_now);
+ S_SET_VALUE (sym, new_value);
+ }
+ else if (label_seen && symbol_get_frag (sym) != old_frag)
+ break;
+ }
+ record_alignment (now_seg, align);
+ }
+}
+
+\f
+/** Support for self-check mode. */
+
+/* Mode of the assembler. */
+typedef enum
+{
+ PRU_MODE_ASSEMBLE, /* Ordinary operation. */
+ PRU_MODE_TEST /* Hidden mode used for self testing. */
+} PRU_MODE;
+
+static PRU_MODE pru_mode = PRU_MODE_ASSEMBLE;
+
+/* This function is used to in self-checking mode
+ to check the assembled instruction
+ opcode should be the assembled opcode, and exp_opcode
+ the parsed string representing the expected opcode. */
+static void
+pru_check_assembly (unsigned int opcode, const char *exp_opcode)
+{
+ if (pru_mode == PRU_MODE_TEST)
+ {
+ if (exp_opcode == NULL)
+ as_bad (_("expecting opcode string in self test mode"));
+ else if (opcode != strtoul (exp_opcode, NULL, 16))
+ as_bad (_("assembly 0x%08x, expected %s"), opcode, exp_opcode);
+ }
+}
+
+\f
+/** Support for machine-dependent assembler directives. */
+/* Handle the .align pseudo-op. This aligns to a power of two. It
+ also adjusts any current instruction label. We treat this the same
+ way the MIPS port does: .align 0 turns off auto alignment. */
+static void
+s_pru_align (int ignore ATTRIBUTE_UNUSED)
+{
+ int align;
+ char fill;
+ const char *pfill = NULL;
+ long max_alignment = 15;
+
+ align = get_absolute_expression ();
+ if (align > max_alignment)
+ {
+ align = max_alignment;
+ as_bad (_("Alignment too large: %d assumed"), align);
+ }
+ else if (align < 0)
+ {
+ as_warn (_("Alignment negative: 0 assumed"));
+ align = 0;
+ }
+
+ if (*input_line_pointer == ',')
+ {
+ input_line_pointer++;
+ fill = get_absolute_expression ();
+ pfill = (const char *) &fill;
+ }
+ else if (subseg_text_p (now_seg))
+ pfill = (const char *) &nop;
+ else
+ {
+ pfill = NULL;
+ pru_last_label = NULL;
+ }
+
+ if (align != 0)
+ {
+ pru_auto_align_on = 1;
+ pru_align (align, pfill, pru_last_label);
+ pru_last_label = NULL;
+ }
+ else
+ pru_auto_align_on = 0;
+
+ demand_empty_rest_of_line ();
+}
+
+/* Handle the .text pseudo-op. This is like the usual one, but it
+ clears the saved last label and resets known alignment. */
+static void
+s_pru_text (int i)
+{
+ s_text (i);
+ pru_last_label = NULL;
+ pru_current_align = 0;
+ pru_current_align_seg = now_seg;
+}
+
+/* Handle the .data pseudo-op. This is like the usual one, but it
+ clears the saved last label and resets known alignment. */
+static void
+s_pru_data (int i)
+{
+ s_data (i);
+ pru_last_label = NULL;
+ pru_current_align = 0;
+ pru_current_align_seg = now_seg;
+}
+
+/* Handle the .section pseudo-op. This is like the usual one, but it
+ clears the saved last label and resets known alignment. */
+static void
+s_pru_section (int ignore)
+{
+ obj_elf_section (ignore);
+ pru_last_label = NULL;
+ pru_current_align = 0;
+ pru_current_align_seg = now_seg;
+}
+
+/* Explicitly unaligned cons. */
+static void
+s_pru_ucons (int nbytes)
+{
+ int hold;
+ hold = pru_auto_align_on;
+ pru_auto_align_on = 0;
+ cons (nbytes);
+ pru_auto_align_on = hold;
+}
+
+/* .set sets assembler options. */
+static void
+s_pru_set (int equiv)
+{
+ char *save = input_line_pointer;
+ char *directive;
+ char delim = get_symbol_name (&directive);
+ char *endline = input_line_pointer;
+
+ (void) restore_line_pointer (delim);
+
+ /* We only want to handle ".set XXX" if the
+ user has tried ".set XXX, YYY" they are not
+ trying a directive. This prevents
+ us from polluting the name space. */
+ SKIP_WHITESPACE ();
+ if (is_end_of_line[(unsigned char) *input_line_pointer])
+ {
+ bfd_boolean done = TRUE;
+ *endline = 0;
+
+ if (!strcmp (directive, "no_warn_regname_label"))
+ pru_opt.warn_regname_label = FALSE;
+ else
+ done = FALSE;
+
+ if (done)
+ {
+ *endline = delim;
+ demand_empty_rest_of_line ();
+ return;
+ }
+ }
+
+ /* If we fall through to here, either we have ".set XXX, YYY"
+ or we have ".set XXX" where XXX is unknown or we have
+ a syntax error. */
+ input_line_pointer = save;
+ s_set (equiv);
+}
+
+/* Machine-dependent assembler directives.
+ Format of each entry is:
+ { "directive", handler_func, param } */
+const pseudo_typeS md_pseudo_table[] = {
+ {"align", s_pru_align, 0},
+ {"text", s_pru_text, 0},
+ {"data", s_pru_data, 0},
+ {"section", s_pru_section, 0},
+ {"section.s", s_pru_section, 0},
+ {"sect", s_pru_section, 0},
+ {"sect.s", s_pru_section, 0},
+ /* .dword and .half are included for compatibility with MIPS. */
+ {"dword", cons, 8},
+ {"half", cons, 2},
+ /* PRU native word size is 4 bytes, so we override
+ the GAS default of 2. */
+ {"word", cons, 4},
+ /* Explicitly unaligned directives. */
+ {"2byte", s_pru_ucons, 2},
+ {"4byte", s_pru_ucons, 4},
+ {"8byte", s_pru_ucons, 8},
+ {"16byte", s_pru_ucons, 16},
+ {"set", s_pru_set, 0},
+ {NULL, NULL, 0}
+};
+
+\f
+int
+md_estimate_size_before_relax (fragS *fragp ATTRIBUTE_UNUSED,
+ asection *seg ATTRIBUTE_UNUSED)
+{
+ abort ();
+ return 0;
+}
+
+void
+md_convert_frag (bfd *headers ATTRIBUTE_UNUSED, segT segment ATTRIBUTE_UNUSED,
+ fragS *fragp ATTRIBUTE_UNUSED)
+{
+ abort ();
+}
+
+\f
+static bfd_boolean
+relaxable_section (asection *sec)
+{
+ return ((sec->flags & SEC_DEBUGGING) == 0
+ && (sec->flags & SEC_CODE) != 0
+ && (sec->flags & SEC_ALLOC) != 0);
+}
+
+/* Does whatever the xtensa port does. */
+int
+pru_validate_fix_sub (fixS *fix)
+{
+ segT add_symbol_segment, sub_symbol_segment;
+
+ /* The difference of two symbols should be resolved by the assembler when
+ linkrelax is not set. If the linker may relax the section containing
+ the symbols, then an Xtensa DIFF relocation must be generated so that
+ the linker knows to adjust the difference value. */
+ if (!linkrelax || fix->fx_addsy == NULL)
+ return 0;
+
+ /* Make sure both symbols are in the same segment, and that segment is
+ "normal" and relaxable. If the segment is not "normal", then the
+ fix is not valid. If the segment is not "relaxable", then the fix
+ should have been handled earlier. */
+ add_symbol_segment = S_GET_SEGMENT (fix->fx_addsy);
+ if (! SEG_NORMAL (add_symbol_segment)
+ || ! relaxable_section (add_symbol_segment))
+ return 0;
+
+ sub_symbol_segment = S_GET_SEGMENT (fix->fx_subsy);
+ return (sub_symbol_segment == add_symbol_segment);
+}
+
+/* TC_FORCE_RELOCATION hook. */
+
+/* If linkrelax is turned on, and the symbol to relocate
+ against is in a relaxable segment, don't compute the value -
+ generate a relocation instead. */
+int
+pru_force_relocation (fixS *fix)
+{
+ if (linkrelax && fix->fx_addsy
+ && relaxable_section (S_GET_SEGMENT (fix->fx_addsy)))
+ return 1;
+
+ return generic_force_reloc (fix);
+}
+
+
+\f
+/** Fixups and overflow checking. */
+
+/* Check a fixup for overflow. */
+static bfd_reloc_status_type
+pru_check_overflow (valueT fixup, reloc_howto_type *howto)
+{
+ bfd_reloc_status_type ret;
+
+ ret = bfd_check_overflow (howto->complain_on_overflow,
+ howto->bitsize,
+ howto->rightshift,
+ bfd_get_reloc_size (howto) * 8,
+ fixup);
+
+ return ret;
+}
+
+/* Emit diagnostic for fixup overflow. */
+static void
+pru_diagnose_overflow (valueT fixup, reloc_howto_type *howto,
+ fixS *fixP, valueT value)
+{
+ if (fixP->fx_r_type == BFD_RELOC_8
+ || fixP->fx_r_type == BFD_RELOC_16
+ || fixP->fx_r_type == BFD_RELOC_32)
+ /* These relocs are against data, not instructions. */
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("immediate value 0x%x truncated to 0x%x"),
+ (unsigned int) fixup,
+ (unsigned int) (~(~(valueT) 0 << howto->bitsize) & fixup));
+ else
+ {
+ /* What opcode is the instruction? This will determine
+ whether we check for overflow in immediate values
+ and what error message we get. */
+ const struct pru_opcode *opcode;
+ enum overflow_type overflow_msg_type;
+ unsigned int range_min;
+ unsigned int range_max;
+ unsigned int address;
+ gas_assert (fixP->fx_size == 4);
+ opcode = pru_find_opcode (value);
+ gas_assert (opcode);
+ overflow_msg_type = opcode->overflow_msg;
+ switch (overflow_msg_type)
+ {
+ case call_target_overflow:
+ range_min
+ = ((fixP->fx_frag->fr_address + fixP->fx_where) & 0xf0000000);
+ range_max = range_min + 0x0fffffff;
+ address = fixup | range_min;
+
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("call target address 0x%08x out of range 0x%08x to 0x%08x"),
+ address, range_min, range_max);
+ break;
+ case qbranch_target_overflow:
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("quick branch offset %d out of range %d to %d"),
+ (int)fixup, -((1<<9) * 4), (1 << 9) * 4);
+ break;
+ case address_offset_overflow:
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("%s offset %d out of range %d to %d"),
+ opcode->name, (int)fixup, -32768, 32767);
+ break;
+ case signed_immed16_overflow:
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("immediate value %d out of range %d to %d"),
+ (int)fixup, -32768, 32767);
+ break;
+ case unsigned_immed32_overflow:
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("immediate value %llu out of range %u to %lu"),
+ (unsigned long long)fixup, 0, 0xfffffffflu);
+ break;
+ case unsigned_immed16_overflow:
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("immediate value %u out of range %u to %u"),
+ (unsigned int)fixup, 0, 65535);
+ break;
+ case unsigned_immed5_overflow:
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("immediate value %u out of range %u to %u"),
+ (unsigned int)fixup, 0, 31);
+ break;
+ default:
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("overflow in immediate argument"));
+ break;
+ }
+ }
+}
+
+/* Apply a fixup to the object file. */
+void
+md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
+{
+ unsigned char *where;
+ valueT value = *valP;
+ long n;
+
+ /* Assert that the fixup is one we can handle. */
+ gas_assert (fixP != NULL && valP != NULL
+ && (fixP->fx_r_type == BFD_RELOC_8
+ || fixP->fx_r_type == BFD_RELOC_16
+ || fixP->fx_r_type == BFD_RELOC_32
+ || fixP->fx_r_type == BFD_RELOC_64
+ || fixP->fx_r_type == BFD_RELOC_PRU_LDI32
+ || fixP->fx_r_type == BFD_RELOC_PRU_U16
+ || fixP->fx_r_type == BFD_RELOC_PRU_U16_PMEMIMM
+ || fixP->fx_r_type == BFD_RELOC_PRU_S10_PCREL
+ || fixP->fx_r_type == BFD_RELOC_PRU_U8_PCREL
+ || fixP->fx_r_type == BFD_RELOC_PRU_32_PMEM
+ || fixP->fx_r_type == BFD_RELOC_PRU_16_PMEM
+ /* Add other relocs here as we generate them. */
+ ));
+
+ if (fixP->fx_r_type == BFD_RELOC_64)
+ {
+ /* We may reach here due to .8byte directives, but we never output
+ BFD_RELOC_64; it must be resolved. */
+ if (fixP->fx_addsy != NULL)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("cannot create 64-bit relocation"));
+ else
+ {
+ md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
+ *valP, 8);
+ fixP->fx_done = 1;
+ }
+ return;
+ }
+
+ /* gas_assert (had_errors () || !fixP->fx_subsy); */
+
+ /* In general, fix instructions with immediate
+ constants. But leave LDI32 for the linker,
+ which is prepared to shorten insns. */
+ if (fixP->fx_addsy == (symbolS *) NULL
+ && fixP->fx_r_type != BFD_RELOC_PRU_LDI32)
+ fixP->fx_done = 1;
+
+ else if (fixP->fx_pcrel)
+ {
+ segT s = S_GET_SEGMENT (fixP->fx_addsy);
+
+ if (s == seg || s == absolute_section)
+ {
+ /* Blindly copied from AVR, but I don't understand why
+ this is needed in the first place. Fail hard to catch
+ when this curious code snippet is utilized. */
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("unexpected PC relative expression"));
+ value += S_GET_VALUE (fixP->fx_addsy);
+ fixP->fx_done = 1;
+ }
+ }
+ else if (linkrelax && fixP->fx_subsy)
+ {
+ /* For a subtraction relocation expression, generate one
+ of the DIFF relocs, with the value being the difference.
+ Note that a sym1 - sym2 expression is adjusted into a
+ section_start_sym + sym4_offset_from_section_start - sym1
+ expression. fixP->fx_addsy holds the section start symbol,
+ fixP->fx_offset holds sym2's offset, and fixP->fx_subsy
+ holds sym1. Calculate the current difference and write value,
+ but leave fx_offset as is - during relaxation,
+ fx_offset - value gives sym1's value. */
+
+ offsetT diffval; /* valueT is unsigned, so use offsetT. */
+
+ diffval = S_GET_VALUE (fixP->fx_addsy)
+ + fixP->fx_offset - S_GET_VALUE (fixP->fx_subsy);
+
+ switch (fixP->fx_r_type)
+ {
+ case BFD_RELOC_8:
+ fixP->fx_r_type = BFD_RELOC_PRU_GNU_DIFF8;
+ break;
+ case BFD_RELOC_16:
+ fixP->fx_r_type = BFD_RELOC_PRU_GNU_DIFF16;
+ break;
+ case BFD_RELOC_32:
+ fixP->fx_r_type = BFD_RELOC_PRU_GNU_DIFF32;
+ break;
+ case BFD_RELOC_PRU_16_PMEM:
+ fixP->fx_r_type = BFD_RELOC_PRU_GNU_DIFF16_PMEM;
+ if (diffval % 4)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("residual low bits in pmem diff relocation"));
+ diffval /= 4;
+ break;
+ case BFD_RELOC_PRU_32_PMEM:
+ fixP->fx_r_type = BFD_RELOC_PRU_GNU_DIFF32_PMEM;
+ if (diffval % 4)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("residual low bits in pmem diff relocation"));
+ diffval /= 4;
+ break;
+ default:
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("expression too complex"));
+ break;
+ }
+
+ value = *valP = diffval;
+
+ fixP->fx_subsy = NULL;
+ }
+ /* We don't actually support subtracting a symbol. */
+ if (fixP->fx_subsy != (symbolS *) NULL)
+ as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex"));
+
+ /* For the DIFF relocs, write the value into the object file while still
+ keeping fx_done FALSE, as both the difference (recorded in the object file)
+ and the sym offset (part of fixP) are needed at link relax time. */
+ where = (unsigned char *) fixP->fx_frag->fr_literal + fixP->fx_where;
+ switch (fixP->fx_r_type)
+ {
+ case BFD_RELOC_PRU_GNU_DIFF8:
+ *where = value;
+ break;
+ case BFD_RELOC_PRU_GNU_DIFF16:
+ case BFD_RELOC_PRU_GNU_DIFF16_PMEM:
+ bfd_putl16 ((bfd_vma) value, where);
+ break;
+ case BFD_RELOC_PRU_GNU_DIFF32:
+ case BFD_RELOC_PRU_GNU_DIFF32_PMEM:
+ bfd_putl32 ((bfd_vma) value, where);
+ break;
+ default:
+ break;
+ }
+
+ if (fixP->fx_done)
+ /* Fully resolved fixup. */
+ {
+ reloc_howto_type *howto
+ = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
+
+ if (howto == NULL)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("relocation is not supported"));
+ else
+ {
+ valueT fixup = value;
+ uint64_t insn;
+ char *buf;
+
+ /* Get the instruction or data to be fixed up. */
+ buf = fixP->fx_frag->fr_literal + fixP->fx_where;
+ insn = md_chars_to_number (buf, fixP->fx_size);
+
+ /* Check for overflow, emitting a diagnostic if necessary. */
+ if (pru_check_overflow (fixup, howto) != bfd_reloc_ok)
+ pru_diagnose_overflow (fixup, howto, fixP, insn);
+
+ /* Apply the right shift. */
+ fixup = ((offsetT)fixup) >> howto->rightshift;
+
+ /* Truncate the fixup to right size. */
+ n = sizeof (fixup) * 8 - howto->bitsize;
+ fixup = (fixup << n) >> n;
+
+ /* Fix up the instruction. Non-contiguous bitfields need
+ special handling. */
+ if (fixP->fx_r_type == BFD_RELOC_PRU_S10_PCREL)
+ SET_BROFF_URAW (insn, fixup);
+ else if (fixP->fx_r_type == BFD_RELOC_PRU_LDI32)
+ {
+ /* 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);
+ insn = insn1 | ((uint64_t)insn2 << 32);
+ }
+ else
+ insn = (insn & ~howto->dst_mask) | (fixup << howto->bitpos);
+ md_number_to_chars (buf, insn, fixP->fx_size);
+ }
+
+ fixP->fx_done = 1;
+ }
+
+ if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT)
+ {
+ fixP->fx_done = 0;
+ if (fixP->fx_addsy
+ && !S_IS_DEFINED (fixP->fx_addsy) && !S_IS_WEAK (fixP->fx_addsy))
+ S_SET_WEAK (fixP->fx_addsy);
+ }
+ else if (fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+ fixP->fx_done = 0;
+}
+
+
+\f
+/** Instruction parsing support. */
+
+/* Creates a new pru_insn_relocS and returns a pointer to it. */
+static pru_insn_relocS *
+pru_insn_reloc_new (bfd_reloc_code_real_type reloc_type, unsigned int pcrel)
+{
+ pru_insn_relocS *retval;
+ retval = XNEW (pru_insn_relocS);
+ if (retval == NULL)
+ {
+ as_bad (_("can't create relocation"));
+ abort ();
+ }
+
+ /* Fill out the fields with default values. */
+ retval->reloc_next = NULL;
+ retval->reloc_type = reloc_type;
+ retval->reloc_pcrel = pcrel;
+ return retval;
+}
+
+/* Frees up memory previously allocated by pru_insn_reloc_new (). */
+static void
+pru_insn_reloc_destroy (pru_insn_relocS *reloc)
+{
+ pru_insn_relocS *next;
+
+ while (reloc)
+ {
+ next = reloc->reloc_next;
+ free (reloc);
+ reloc = next;
+ }
+}
+
+/* The various pru_assemble_* functions call this
+ function to generate an expression from a string representing an expression.
+ It then tries to evaluate the expression, and if it can, returns its value.
+ If not, it creates a new pru_insn_relocS and stores the expression and
+ reloc_type for future use. */
+static unsigned long
+pru_assemble_expression (const char *exprstr,
+ pru_insn_infoS *insn,
+ pru_insn_relocS *prev_reloc,
+ bfd_reloc_code_real_type reloc_type,
+ unsigned int pcrel)
+{
+ expressionS *ep;
+ pru_insn_relocS *reloc;
+ char *saved_line_ptr;
+ unsigned short value;
+
+ gas_assert (exprstr != NULL);
+ gas_assert (insn != NULL);
+
+ /* We use this blank keyword to distinguish register from
+ label operands. */
+ if (strstr (exprstr, "%label") != NULL)
+ {
+ exprstr += strlen ("%label") + 1;
+ }
+
+ /* Check for pmem relocation operator.
+ Change the relocation type and advance the ptr to the start of
+ the expression proper. */
+ if (strstr (exprstr, "%pmem") != NULL)
+ {
+ reloc_type = BFD_RELOC_PRU_U16_PMEMIMM;
+ exprstr += strlen ("%pmem") + 1;
+ }
+
+ /* We potentially have a relocation. */
+ reloc = pru_insn_reloc_new (reloc_type, pcrel);
+ if (prev_reloc != NULL)
+ prev_reloc->reloc_next = reloc;
+ else
+ insn->insn_reloc = reloc;
+
+ /* Parse the expression string. */
+ ep = &reloc->reloc_expression;
+ saved_line_ptr = input_line_pointer;
+ input_line_pointer = (char *) exprstr;
+ SKIP_WHITESPACE ();
+ expression (ep);
+ SKIP_WHITESPACE ();
+ if (*input_line_pointer)
+ as_bad (_("trailing garbage after expression: %s"), input_line_pointer);
+ input_line_pointer = saved_line_ptr;
+
+
+ if (ep->X_op == O_illegal || ep->X_op == O_absent)
+ as_bad (_("expected expression, got %s"), exprstr);
+
+ /* This is redundant as the fixup will put this into
+ the instruction, but it is included here so that
+ self-test mode (-r) works. */
+ value = 0;
+ if (pru_mode == PRU_MODE_TEST && ep->X_op == O_constant)
+ value = ep->X_add_number;
+
+ return (unsigned long) value;
+}
+
+/* Try to parse a non-relocatable expression. */
+static unsigned long
+pru_assemble_noreloc_expression (const char *exprstr)
+{
+ expressionS exp;
+ char *saved_line_ptr;
+ unsigned long val;
+
+ gas_assert (exprstr != NULL);
+
+ saved_line_ptr = input_line_pointer;
+ input_line_pointer = (char *) exprstr;
+ SKIP_WHITESPACE ();
+ expression (&exp);
+ SKIP_WHITESPACE ();
+ if (*input_line_pointer)
+ as_bad (_("trailing garbage after expression: %s"), input_line_pointer);
+ input_line_pointer = saved_line_ptr;
+
+ val = 0;
+ if (exp.X_op != O_constant)
+ as_bad (_("expected constant expression, got %s"), exprstr);
+ else
+ val = exp.X_add_number;
+
+ return val;
+}
+
+/* Argument assemble functions.
+ All take an instruction argument string, and a pointer
+ to an instruction opcode. Upon return the insn_opcode
+ has the relevant fields filled in to represent the arg
+ string. The return value is NULL if successful, or
+ an error message if an error was detected. */
+
+static void
+pru_assemble_arg_d (pru_insn_infoS *insn_info, const char *argstr)
+{
+ struct pru_reg *dst = pru_reg_lookup (argstr);
+
+ if (dst == NULL)
+ as_bad (_("unknown register %s"), argstr);
+ else
+ {
+ SET_INSN_FIELD (RD, insn_info->insn_code, dst->index);
+ SET_INSN_FIELD (RDSEL, insn_info->insn_code, dst->regsel);
+ }
+}
+
+static void
+pru_assemble_arg_D (pru_insn_infoS *insn_info, const char *argstr)
+{
+ struct pru_reg *dst;
+
+ /* The leading & before an address register is optional. */
+ if (*argstr == '&')
+ argstr++;
+
+ dst = pru_reg_lookup (argstr);
+
+ if (dst == NULL)
+ as_bad (_("unknown register %s"), argstr);
+ else
+ {
+ unsigned long rxb = 0;
+
+ switch (dst->regsel)
+ {
+ case RSEL_31_0: rxb = 0; break; /* whole register defaults to .b0 */
+ case RSEL_7_0: rxb = 0; break;
+ case RSEL_15_8: rxb = 1; break;
+ case RSEL_23_16: rxb = 2; break;
+ case RSEL_31_24: rxb = 3; break;
+ default:
+ as_bad (_("data transfer register cannot be halfword"));
+ }
+
+ SET_INSN_FIELD (RD, insn_info->insn_code, dst->index);
+ SET_INSN_FIELD (RDB, insn_info->insn_code, rxb);
+ }
+}
+
+static void
+pru_assemble_arg_R (pru_insn_infoS *insn_info, const char *argstr)
+{
+ struct pru_reg *dst = pru_reg_lookup (argstr);
+
+ if (dst == NULL)
+ as_bad (_("unknown register %s"), argstr);
+ else
+ {
+ if (dst->regsel != RSEL_31_0)
+ {
+ as_bad (_("destination register must be full-word"));
+ }
+
+ SET_INSN_FIELD (RD, insn_info->insn_code, dst->index);
+ SET_INSN_FIELD (RDSEL, insn_info->insn_code, dst->regsel);
+ }
+}
+
+static void
+pru_assemble_arg_s (pru_insn_infoS *insn_info, const char *argstr)
+{
+ struct pru_reg *src1 = pru_reg_lookup (argstr);
+
+ if (src1 == NULL)
+ as_bad (_("unknown register %s"), argstr);
+ else
+ {
+ SET_INSN_FIELD (RS1, insn_info->insn_code, src1->index);
+ SET_INSN_FIELD (RS1SEL, insn_info->insn_code, src1->regsel);
+ }
+}
+
+static void
+pru_assemble_arg_S (pru_insn_infoS *insn_info, const char *argstr)
+{
+ struct pru_reg *src1 = pru_reg_lookup (argstr);
+
+ if (src1 == NULL)
+ as_bad (_("unknown register %s"), argstr);
+ else
+ {
+ if (src1->regsel != RSEL_31_0)
+ as_bad (_("cannot use partial register %s for addressing"), argstr);
+ SET_INSN_FIELD (RS1, insn_info->insn_code, src1->index);
+ }
+}
+
+static void
+pru_assemble_arg_b (pru_insn_infoS *insn_info, const char *argstr)
+{
+ struct pru_reg *src2 = pru_reg_lookup (argstr);
+ if (src2 == NULL)
+ {
+ unsigned long imm8 = pru_assemble_noreloc_expression (argstr);
+ SET_INSN_FIELD (IMM8, insn_info->insn_code, imm8);
+ SET_INSN_FIELD (IO, insn_info->insn_code, 1);
+ }
+ else
+ {
+ SET_INSN_FIELD (IO, insn_info->insn_code, 0);
+ SET_INSN_FIELD (RS2, insn_info->insn_code, src2->index);
+ SET_INSN_FIELD (RS2SEL, insn_info->insn_code, src2->regsel);
+ }
+
+}
+
+static void
+pru_assemble_arg_B (pru_insn_infoS *insn_info, const char *argstr)
+{
+ struct pru_reg *src2 = pru_reg_lookup (argstr);
+ if (src2 == NULL)
+ {
+ unsigned long imm8;
+ imm8 = pru_assemble_noreloc_expression (argstr);
+ if (!imm8 || imm8 > 0xff)
+ as_bad (_("loop count constant %ld is out of range [1..%d]"),
+ imm8, 0xff);
+ /* Note: HW expects the immediate loop count field
+ to be one less than the actual loop count. */
+ SET_INSN_FIELD (IMM8, insn_info->insn_code, imm8 - 1);
+ SET_INSN_FIELD (IO, insn_info->insn_code, 1);
+ }
+ else
+ {
+ SET_INSN_FIELD (IO, insn_info->insn_code, 0);
+ SET_INSN_FIELD (RS2, insn_info->insn_code, src2->index);
+ SET_INSN_FIELD (RS2SEL, insn_info->insn_code, src2->regsel);
+ }
+}
+
+static void
+pru_assemble_arg_i (pru_insn_infoS *insn_info, const char *argstr)
+{
+ unsigned long imm32;
+
+ /* We must not generate PRU_LDI32 relocation if relaxation is disabled in
+ GAS. Consider the following scenario: GAS relaxation is disabled, so
+ DIFF* expressions are fixed and not emitted as relocations. Then if LD
+ has relaxation enabled, it may shorten LDI32 but will not update
+ accordingly the DIFF expressions. */
+ if (pru_opt.link_relax)
+ imm32 = pru_assemble_expression (argstr, insn_info,
+ insn_info->insn_reloc,
+ BFD_RELOC_PRU_LDI32, 0);
+ else
+ imm32 = pru_assemble_noreloc_expression (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);
+ insn_info->ldi32_imm32 = imm32;
+}
+
+static void
+pru_assemble_arg_j (pru_insn_infoS *insn_info, const char *argstr)
+{
+ struct pru_reg *src2 = pru_reg_lookup (argstr);
+
+ if (src2 == NULL)
+ {
+ unsigned long imm16 = pru_assemble_expression (argstr, insn_info,
+ insn_info->insn_reloc,
+ BFD_RELOC_PRU_U16_PMEMIMM,
+ 0);
+ SET_INSN_FIELD (IMM16, insn_info->insn_code, imm16);
+ SET_INSN_FIELD (IO, insn_info->insn_code, 1);
+ }
+ else
+ {
+ SET_INSN_FIELD (IO, insn_info->insn_code, 0);
+ SET_INSN_FIELD (RS2, insn_info->insn_code, src2->index);
+ SET_INSN_FIELD (RS2SEL, insn_info->insn_code, src2->regsel);
+ }
+}
+
+static void
+pru_assemble_arg_W (pru_insn_infoS *insn_info, const char *argstr)
+{
+ unsigned long imm16 = pru_assemble_expression (argstr, insn_info,
+ insn_info->insn_reloc,
+ BFD_RELOC_PRU_U16, 0);
+ /* 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, imm16);
+}
+
+static void
+pru_assemble_arg_o (pru_insn_infoS *insn_info, const char *argstr)
+{
+ unsigned long imm10 = pru_assemble_expression (argstr, insn_info,
+ insn_info->insn_reloc,
+ BFD_RELOC_PRU_S10_PCREL, 1);
+ SET_BROFF_URAW (insn_info->insn_code, imm10);
+}
+
+static void
+pru_assemble_arg_O (pru_insn_infoS *insn_info, const char *argstr)
+{
+ unsigned long imm8 = pru_assemble_expression (argstr, insn_info,
+ insn_info->insn_reloc,
+ BFD_RELOC_PRU_U8_PCREL, 1);
+ SET_INSN_FIELD (LOOP_JMPOFFS, insn_info->insn_code, imm8);
+}
+
+static void
+pru_assemble_arg_l (pru_insn_infoS *insn_info, const char *argstr)
+{
+ unsigned long burstlen = 0;
+ struct pru_reg *blreg = pru_reg_lookup (argstr);
+
+ if (blreg == NULL)
+ {
+ burstlen = pru_assemble_noreloc_expression (argstr);
+ if (!burstlen || burstlen > LSSBBO_BYTECOUNT_R0_BITS7_0)
+ as_bad (_("byte count constant %ld is out of range [1..%d]"),
+ burstlen, LSSBBO_BYTECOUNT_R0_BITS7_0);
+ burstlen--;
+ }
+ else
+ {
+ if (blreg->index != 0)
+ as_bad (_("only r0 can be used as byte count register"));
+ else if (blreg->regsel > RSEL_31_24)
+ as_bad (_("only r0.bX byte fields of r0 can be used as byte count"));
+ else
+ burstlen = LSSBBO_BYTECOUNT_R0_BITS7_0 + blreg->regsel;
+ }
+ SET_BURSTLEN (insn_info->insn_code, burstlen);
+}
+
+static void
+pru_assemble_arg_n (pru_insn_infoS *insn_info, const char *argstr)
+{
+ unsigned long burstlen = 0;
+ struct pru_reg *blreg = pru_reg_lookup (argstr);
+
+ if (blreg == NULL)
+ {
+ burstlen = pru_assemble_noreloc_expression (argstr);
+ if (!burstlen || burstlen > LSSBBO_BYTECOUNT_R0_BITS7_0)
+ as_bad (_("byte count constant %ld is out of range [1..%d]"),
+ burstlen, LSSBBO_BYTECOUNT_R0_BITS7_0);
+ burstlen--;
+ }
+ else
+ {
+ if (blreg->index != 0)
+ as_bad (_("only r0 can be used as byte count register"));
+ else if (blreg->regsel > RSEL_31_24)
+ as_bad (_("only r0.bX byte fields of r0 can be used as byte count"));
+ else
+ burstlen = LSSBBO_BYTECOUNT_R0_BITS7_0 + blreg->regsel;
+ }
+ SET_INSN_FIELD (XFR_LENGTH, insn_info->insn_code, burstlen);
+}
+
+static void
+pru_assemble_arg_c (pru_insn_infoS *insn_info, const char *argstr)
+{
+ unsigned long cb = pru_assemble_noreloc_expression (argstr);
+
+ if (cb > 31)
+ as_bad (_("invalid constant table offset %ld"), cb);
+ else
+ SET_INSN_FIELD (CB, insn_info->insn_code, cb);
+}
+
+static void
+pru_assemble_arg_w (pru_insn_infoS *insn_info, const char *argstr)
+{
+ unsigned long wk = pru_assemble_noreloc_expression (argstr);
+
+ if (wk != 0 && wk != 1)
+ as_bad (_("invalid WakeOnStatus %ld"), wk);
+ else
+ SET_INSN_FIELD (WAKEONSTATUS, insn_info->insn_code, wk);
+}
+
+static void
+pru_assemble_arg_x (pru_insn_infoS *insn_info, const char *argstr)
+{
+ unsigned long wba = pru_assemble_noreloc_expression (argstr);
+
+ if (wba > 255)
+ as_bad (_("invalid XFR WideBus Address %ld"), wba);
+ else
+ SET_INSN_FIELD (XFR_WBA, insn_info->insn_code, wba);
+}
+
+/* The function consume_arg takes a pointer into a string
+ of instruction tokens (args) and a pointer into a string
+ representing the expected sequence of tokens and separators.
+ It checks whether the first argument in argstr is of the
+ expected type, throwing an error if it is not, and returns
+ the pointer argstr. */
+static char *
+pru_consume_arg (char *argstr, const char *parsestr)
+{
+ char *temp;
+
+ switch (*parsestr)
+ {
+ case 'W':
+ if (*argstr == '%')
+ {
+ if (strprefix (argstr, "%pmem") || strprefix (argstr, "%label"))
+ {
+ /* We zap the parentheses because we don't want them confused
+ with separators. */
+ temp = strchr (argstr, '(');
+ if (temp != NULL)
+ *temp = ' ';
+ temp = strchr (argstr, ')');
+ if (temp != NULL)
+ *temp = ' ';
+ }
+ else
+ as_bad (_("badly formed expression near %s"), argstr);
+ }
+ break;
+
+ case 'j':
+ case 'o':
+ case 'O':
+ if (*argstr == '%')
+ {
+ /* Only 'j' really requires %label for distinguishing registers
+ from labels, but we include 'o' and 'O' here to avoid
+ confusing assembler programmers. Thus for completeness all
+ jump operands can be prefixed with %label. */
+ if (strprefix (argstr, "%label"))
+ {
+ /* We zap the parentheses because we don't want them confused
+ with separators. */
+ temp = strchr (argstr, '(');
+ if (temp != NULL)
+ *temp = ' ';
+ temp = strchr (argstr, ')');
+ if (temp != NULL)
+ *temp = ' ';
+ }
+ else
+ as_bad (_("badly formed expression near %s"), argstr);
+ }
+ break;
+
+ case 'b':
+ case 'B':
+ case 'c':
+ case 'd':
+ case 'D':
+ case 'E':
+ case 'i':
+ case 's':
+ case 'S':
+ case 'l':
+ case 'n':
+ case 'R':
+ case 'w':
+ case 'x':
+ /* We can't have %pmem here. */
+ if (*argstr == '%')
+ as_bad (_("badly formed expression near %s"), argstr);
+ break;
+ default:
+ BAD_CASE (*parsestr);
+ break;
+ }
+
+ return argstr;
+}
+
+/* The function consume_separator takes a pointer into a string
+ of instruction tokens (args) and a pointer into a string representing
+ the expected sequence of tokens and separators. It finds the first
+ instance of the character pointed to by separator in argstr, and
+ returns a pointer to the next element of argstr, which is the
+ following token in the sequence. */
+static char *
+pru_consume_separator (char *argstr, const char *separator)
+{
+ char *p;
+
+ p = strchr (argstr, *separator);
+
+ if (p != NULL)
+ *p++ = 0;
+ else
+ as_bad (_("expecting %c near %s"), *separator, argstr);
+ return p;
+}
+
+
+/* The principal argument parsing function which takes a string argstr
+ representing the instruction arguments for insn, and extracts the argument
+ tokens matching parsestr into parsed_args. */
+static void
+pru_parse_args (pru_insn_infoS *insn ATTRIBUTE_UNUSED, char *argstr,
+ const char *parsestr, char **parsed_args)
+{
+ char *p;
+ char *end = NULL;
+ int i;
+ p = argstr;
+ i = 0;
+ bfd_boolean terminate = FALSE;
+
+ /* This rest of this function is it too fragile and it mostly works,
+ therefore special case this one. */
+ if (*parsestr == 0 && argstr != 0)
+ {
+ as_bad (_("too many arguments"));
+ parsed_args[0] = NULL;
+ return;
+ }
+
+ while (p != NULL && !terminate && i < PRU_MAX_INSN_TOKENS)
+ {
+ parsed_args[i] = pru_consume_arg (p, parsestr);
+ ++parsestr;
+ if (*parsestr != '\0')
+ {
+ p = pru_consume_separator (p, parsestr);
+ ++parsestr;
+ }
+ else
+ {
+ /* Check that the argument string has no trailing arguments. */
+ /* If we've got a %pmem relocation, we've zapped the parens with
+ spaces. */
+ if (strprefix (p, "%pmem") || strprefix (p, "%label"))
+ end = strpbrk (p, ",");
+ else
+ end = strpbrk (p, " ,");
+
+ if (end != NULL)
+ as_bad (_("too many arguments"));
+ }
+
+ if (*parsestr == '\0' || (p != NULL && *p == '\0'))
+ terminate = TRUE;
+ ++i;
+ }
+
+ parsed_args[i] = NULL;
+
+ /* There are no instructions with optional arguments; complain. */
+ if (*parsestr != '\0')
+ as_bad (_("missing argument"));
+}
+
+\f
+/** Assembler output support. */
+
+/* Output a normal instruction. */
+static void
+output_insn (pru_insn_infoS *insn)
+{
+ char *f;
+ pru_insn_relocS *reloc;
+
+ f = frag_more (4);
+ /* This allocates enough space for the instruction
+ and puts it in the current frag. */
+ md_number_to_chars (f, insn->insn_code, 4);
+ /* Emit debug info. */
+ dwarf2_emit_insn (4);
+ /* Create any fixups to be acted on later. */
+ for (reloc = insn->insn_reloc; reloc != NULL; reloc = reloc->reloc_next)
+ fix_new_exp (frag_now, f - frag_now->fr_literal, 4,
+ &reloc->reloc_expression, reloc->reloc_pcrel,
+ reloc->reloc_type);
+}
+
+/* Output two LDI instructions from LDI32 macro */
+static void
+output_insn_ldi32 (pru_insn_infoS *insn)
+{
+ char *f;
+ pru_insn_relocS *reloc;
+ unsigned long insn2;
+
+ f = frag_more (8);
+ 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);
+ md_number_to_chars (f + 4, insn2, 4);
+
+ /* Emit debug info. */
+ dwarf2_emit_insn (8);
+
+ /* Create any fixups to be acted on later. */
+ for (reloc = insn->insn_reloc; reloc != NULL; reloc = reloc->reloc_next)
+ fix_new_exp (frag_now, f - frag_now->fr_literal, 4,
+ &reloc->reloc_expression, reloc->reloc_pcrel,
+ reloc->reloc_type);
+}
+
+\f
+/** External interfaces. */
+
+/* The following functions are called by machine-independent parts of
+ the assembler. */
+int
+md_parse_option (int c, const char *arg ATTRIBUTE_UNUSED)
+{
+ switch (c)
+ {
+ case 'r':
+ /* Hidden option for self-test mode. */
+ pru_mode = PRU_MODE_TEST;
+ break;
+ case OPTION_LINK_RELAX:
+ pru_opt.link_relax = TRUE;
+ break;
+ case OPTION_NO_LINK_RELAX:
+ pru_opt.link_relax = FALSE;
+ break;
+ case OPTION_NO_WARN_REGNAME_LABEL:
+ pru_opt.warn_regname_label = FALSE;
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ return 1;
+}
+
+const char *
+pru_target_format (void)
+{
+ return "elf32-pru";
+}
+
+/* Machine-dependent usage message. */
+void
+md_show_usage (FILE *stream)
+{
+ fprintf (stream,
+ _("PRU options:\n"
+ " -mlink-relax generate relocations for linker relaxation (default).\n"
+ " -mno-link-relax don't generate relocations for linker relaxation.\n"
+ ));
+
+}
+
+/* This function is called once, at assembler startup time.
+ It should set up all the tables, etc. that the MD part of the
+ assembler will need. */
+void
+md_begin (void)
+{
+ int i;
+ const char *inserted;
+
+ /* Create and fill a hashtable for the PRU opcodes, registers and
+ arguments. */
+ pru_opcode_hash = hash_new ();
+ pru_reg_hash = hash_new ();
+
+ for (i = 0; i < NUMOPCODES; ++i)
+ {
+ inserted
+ = hash_insert (pru_opcode_hash, pru_opcodes[i].name,
+ (PTR) & pru_opcodes[i]);
+ if (inserted != NULL)
+ {
+ fprintf (stderr, _("internal error: can't hash `%s': %s\n"),
+ pru_opcodes[i].name, inserted);
+ /* Probably a memory allocation problem? Give up now. */
+ as_fatal (_("Broken assembler. No assembly attempted."));
+ }
+ }
+
+ for (i = 0; i < pru_num_regs; ++i)
+ {
+ inserted
+ = hash_insert (pru_reg_hash, pru_regs[i].name,
+ (PTR) & pru_regs[i]);
+ if (inserted != NULL)
+ {
+ fprintf (stderr, _("internal error: can't hash `%s': %s\n"),
+ pru_regs[i].name, inserted);
+ /* Probably a memory allocation problem? Give up now. */
+ as_fatal (_("Broken assembler. No assembly attempted."));
+ }
+
+ }
+
+ linkrelax = pru_opt.link_relax;
+ /* Initialize the alignment data. */
+ pru_current_align_seg = now_seg;
+ pru_last_label = NULL;
+ pru_current_align = 0;
+}
+
+
+/* Assembles a single line of PRU assembly language. */
+void
+md_assemble (char *op_str)
+{
+ char *argstr;
+ char *op_strdup = NULL;
+ pru_insn_infoS thisinsn;
+ pru_insn_infoS *insn = &thisinsn;
+
+ /* Make sure we are aligned on a 4-byte boundary. */
+ if (pru_current_align < 2)
+ pru_align (2, NULL, pru_last_label);
+ else if (pru_current_align > 2)
+ pru_current_align = 2;
+ pru_last_label = NULL;
+
+ /* We don't want to clobber to op_str
+ because we want to be able to use it in messages. */
+ op_strdup = strdup (op_str);
+ insn->insn_tokens[0] = strtok (op_strdup, " ");
+ argstr = strtok (NULL, "");
+
+ /* Assemble the opcode. */
+ insn->insn_pru_opcode = pru_opcode_lookup (insn->insn_tokens[0]);
+ insn->insn_reloc = NULL;
+
+ if (insn->insn_pru_opcode != NULL)
+ {
+ const char *argsfmt = insn->insn_pru_opcode->args;
+ const char **argtk = &insn->insn_tokens[1];
+ const char *argp;
+
+ /* Set the opcode for the instruction. */
+ insn->insn_code = insn->insn_pru_opcode->match;
+
+ if (pru_mode == PRU_MODE_TEST)
+ {
+ /* Add the "expected" instruction parameter used for validation. */
+ argsfmt = malloc (strlen (argsfmt) + 3);
+ sprintf ((char *)argsfmt, "%s,E", insn->insn_pru_opcode->args);
+ }
+ pru_parse_args (insn, argstr, argsfmt,
+ (char **) &insn->insn_tokens[1]);
+
+ for (argp = argsfmt; !had_errors () && *argp && *argtk; ++argp)
+ {
+ gas_assert (argtk <= &insn->insn_tokens[PRU_MAX_INSN_TOKENS]);
+
+ switch (*argp)
+ {
+ case ',':
+ continue;
+
+ case 'd':
+ pru_assemble_arg_d (insn, *argtk++);
+ continue;
+ case 'D':
+ pru_assemble_arg_D (insn, *argtk++);
+ continue;
+ case 'R':
+ pru_assemble_arg_R (insn, *argtk++);
+ continue;
+ case 's':
+ pru_assemble_arg_s (insn, *argtk++);
+ continue;
+ case 'S':
+ pru_assemble_arg_S (insn, *argtk++);
+ continue;
+ case 'b':
+ pru_assemble_arg_b (insn, *argtk++);
+ continue;
+ case 'B':
+ pru_assemble_arg_B (insn, *argtk++);
+ continue;
+ case 'i':
+ pru_assemble_arg_i (insn, *argtk++);
+ continue;
+ case 'j':
+ pru_assemble_arg_j (insn, *argtk++);
+ continue;
+ case 'W':
+ pru_assemble_arg_W (insn, *argtk++);
+ continue;
+ case 'o':
+ pru_assemble_arg_o (insn, *argtk++);
+ continue;
+ case 'O':
+ pru_assemble_arg_O (insn, *argtk++);
+ continue;
+ case 'l':
+ pru_assemble_arg_l (insn, *argtk++);
+ continue;
+ case 'n':
+ pru_assemble_arg_n (insn, *argtk++);
+ continue;
+ case 'c':
+ pru_assemble_arg_c (insn, *argtk++);
+ continue;
+ case 'w':
+ pru_assemble_arg_w (insn, *argtk++);
+ continue;
+ case 'x':
+ pru_assemble_arg_x (insn, *argtk++);
+ continue;
+
+ case 'E':
+ pru_check_assembly (insn->insn_code, *argtk++);
+ default:
+ BAD_CASE (*argp);
+ }
+ }
+
+ if (*argp && !had_errors ())
+ as_bad (_("missing argument"));
+
+ if (!had_errors ())
+ {
+ if (insn->insn_pru_opcode->pinfo & PRU_INSN_LDI32)
+ {
+ output_insn_ldi32 (insn);
+ }
+ else
+ {
+ output_insn (insn);
+ }
+ }
+
+ if (pru_mode == PRU_MODE_TEST)
+ free ((char *)argsfmt);
+ }
+ else
+ /* Unrecognised instruction - error. */
+ as_bad (_("unrecognised instruction %s"), insn->insn_tokens[0]);
+
+ /* Don't leak memory. */
+ pru_insn_reloc_destroy (insn->insn_reloc);
+ free (op_strdup);
+}
+
+/* Round up section size. */
+valueT
+md_section_align (asection *seg, valueT addr)
+{
+ int align = bfd_get_section_alignment (stdoutput, seg);
+ return ((addr + (1 << align) - 1) & (-((valueT) 1 << align)));
+}
+
+/* Implement tc_fix_adjustable. */
+int
+pru_fix_adjustable (fixS *fixp)
+{
+ if (fixp->fx_addsy == NULL)
+ return 1;
+
+ /* Prevent all adjustments to global symbols. */
+ if (OUTPUT_FLAVOR == bfd_target_elf_flavour
+ && (S_IS_EXTERNAL (fixp->fx_addsy) || S_IS_WEAK (fixp->fx_addsy)))
+ return 0;
+
+ if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
+ || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+ return 0;
+
+ /* Preserve relocations against symbols with function type. */
+ if (symbol_get_bfdsym (fixp->fx_addsy)->flags & BSF_FUNCTION)
+ return 0;
+
+ return 1;
+}
+
+/* The function tc_gen_reloc creates a relocation structure for the
+ fixup fixp, and returns a pointer to it. This structure is passed
+ to bfd_install_relocation so that it can be written to the object
+ file for linking. */
+arelent *
+tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
+{
+ arelent *reloc = XNEW (arelent);
+ reloc->sym_ptr_ptr = XNEW (asymbol *);
+ *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
+
+ reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
+ reloc->addend = fixp->fx_offset; /* fixp->fx_addnumber; */
+
+ reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
+ if (reloc->howto == NULL)
+ {
+ as_bad_where (fixp->fx_file, fixp->fx_line,
+ _("can't represent relocation type %s"),
+ bfd_get_reloc_code_name (fixp->fx_r_type));
+
+ /* Set howto to a garbage value so that we can keep going. */
+ reloc->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32);
+ gas_assert (reloc->howto != NULL);
+ }
+ return reloc;
+}
+
+long
+md_pcrel_from (fixS *fixP ATTRIBUTE_UNUSED)
+{
+ return fixP->fx_where + fixP->fx_frag->fr_address;
+}
+
+/* Called just before the assembler exits. */
+void
+md_end (void)
+{
+ hash_die (pru_opcode_hash);
+ hash_die (pru_reg_hash);
+}
+
+symbolS *
+md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
+{
+ return NULL;
+}
+
+/* Implement tc_frob_label. */
+void
+pru_frob_label (symbolS *lab)
+{
+ /* Emit dwarf information. */
+ dwarf2_emit_label (lab);
+
+ /* Update the label's address with the current output pointer. */
+ symbol_set_frag (lab, frag_now);
+ S_SET_VALUE (lab, (valueT) frag_now_fix ());
+
+ /* Record this label for future adjustment after we find out what
+ kind of data it references, and the required alignment therewith. */
+ pru_last_label = lab;
+
+ if (pru_opt.warn_regname_label && pru_reg_lookup (S_GET_NAME (lab)))
+ as_warn (_("Label \"%s\" matches a CPU register name"), S_GET_NAME (lab));
+}
+
+static inline char *
+skip_space (char *s)
+{
+ while (*s == ' ' || *s == '\t')
+ ++s;
+ return s;
+}
+
+/* Parse special CONS expression: pmem (expression). Idea from AVR.
+
+ Used to catch and mark code (program memory) in constant expression
+ relocations. Return non-zero for program memory. */
+
+int
+pru_parse_cons_expression (expressionS *exp, int nbytes)
+{
+ int is_pmem = FALSE;
+ char *tmp;
+
+ tmp = input_line_pointer = skip_space (input_line_pointer);
+
+ if (nbytes == 4 || nbytes == 2)
+ {
+ const char *pmem_str = "%pmem";
+ int len = strlen (pmem_str);
+
+ if (strncasecmp (input_line_pointer, pmem_str, len) == 0)
+ {
+ input_line_pointer = skip_space (input_line_pointer + len);
+
+ if (*input_line_pointer == '(')
+ {
+ input_line_pointer = skip_space (input_line_pointer + 1);
+ is_pmem = TRUE;
+ expression (exp);
+
+ if (*input_line_pointer == ')')
+ ++input_line_pointer;
+ else
+ {
+ as_bad (_("`)' required"));
+ is_pmem = FALSE;
+ }
+
+ return is_pmem;
+ }
+
+ input_line_pointer = tmp;
+ }
+ }
+
+ expression (exp);
+
+ return is_pmem;
+}
+
+/* Implement TC_CONS_FIX_NEW. */
+void
+pru_cons_fix_new (fragS *frag, int where, unsigned int nbytes,
+ expressionS *exp, const int is_pmem)
+{
+ bfd_reloc_code_real_type r;
+
+ switch (nbytes | (!!is_pmem << 8))
+ {
+ case 1 | (0 << 8): r = BFD_RELOC_8; break;
+ case 2 | (0 << 8): r = BFD_RELOC_16; break;
+ case 4 | (0 << 8): r = BFD_RELOC_32; break;
+ case 8 | (0 << 8): r = BFD_RELOC_64; break;
+ case 2 | (1 << 8): r = BFD_RELOC_PRU_16_PMEM; break;
+ case 4 | (1 << 8): r = BFD_RELOC_PRU_32_PMEM; break;
+ default:
+ as_bad (_("illegal %s relocation size: %d"),
+ is_pmem ? "text" : "data", nbytes);
+ return;
+ }
+
+ fix_new_exp (frag, where, (int) nbytes, exp, 0, r);
+}
+
+/* Implement tc_regname_to_dw2regnum, to convert REGNAME to a DWARF-2
+ register number. */
+int
+pru_regname_to_dw2regnum (char *regname)
+{
+ struct pru_reg *r = pru_reg_lookup (regname);
+ if (r == NULL)
+ return -1;
+ return r->index;
+}
+
+/* Implement tc_cfi_frame_initial_instructions, to initialize the DWARF-2
+ unwind information for this procedure. */
+void
+pru_frame_initial_instructions (void)
+{
+ const unsigned fp_regno = 4;
+ cfi_add_CFA_def_cfa (fp_regno, 0);
+}
+
+bfd_boolean
+pru_allow_local_subtract (expressionS * left,
+ expressionS * right,
+ segT section)
+{
+ /* If we are not in relaxation mode, subtraction is OK. */
+ if (!linkrelax)
+ return TRUE;
+
+ /* If the symbols are not in a code section then they are OK. */
+ if ((section->flags & SEC_CODE) == 0)
+ return TRUE;
+
+ if (left->X_add_symbol == right->X_add_symbol)
+ return TRUE;
+
+ /* We have to assume that there may be instructions between the
+ two symbols and that relaxation may increase the distance between
+ them. */
+ return FALSE;
+}
diff --git a/gas/config/tc-pru.h b/gas/config/tc-pru.h
new file mode 100644
index 0000000000..d3d0d7812f
--- /dev/null
+++ b/gas/config/tc-pru.h
@@ -0,0 +1,154 @@
+/* Definitions for TI PRU assembler.
+ Copyright (C) 2014-2016 Free Software Foundation, Inc.
+ Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
+
+ This file is part of GAS, the GNU Assembler.
+
+ GAS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GAS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS; see the file COPYING. If not, write to the Free
+ Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
+#ifndef __TC_PRU__
+#define __TC_PRU__
+
+#define TARGET_BYTES_BIG_ENDIAN 0
+
+/* Words are big enough to hold addresses. */
+#define WORKING_DOT_WORD 1
+
+extern const char *pru_target_format (void);
+#define TARGET_FORMAT pru_target_format ()
+#define TARGET_ARCH bfd_arch_pru
+
+/* A PRU instruction consists of tokens and separator characters
+ the tokens are things like the instruction name (add, or jmp etc),
+ the register indices ($5, $7 etc), and constant expressions. The
+ separator characters are commas, brackets and space.
+ The instruction name is always separated from other tokens by a space
+ The maximum number of tokens in an instruction is 6 (the instruction name,
+ 4 arguments, and a 4th string representing the expected instruction opcode
+ after assembly. The latter is only used when the assemble is running in
+ self test mode, otherwise its presence will generate an error. */
+#define PRU_MAX_INSN_TOKENS 7
+
+/* There are no machine-specific operands so we #define this to nothing. */
+#define md_operand(x)
+
+/* Function prototypes exported to rest of GAS. */
+extern void md_assemble (char *op_str);
+extern void md_end (void);
+extern void md_begin (void);
+
+#define tc_fix_adjustable(fixp) pru_fix_adjustable (fixp)
+extern int pru_fix_adjustable (struct fix *);
+
+#define tc_frob_label(lab) pru_frob_label (lab)
+extern void pru_frob_label (symbolS *);
+
+extern void md_convert_frag (bfd * headers, segT sec, fragS * fragP);
+
+#define DIFF_EXPR_OK
+
+/* FIXME This seems appropriate, given that we intentionally prevent
+ PRU's .text from being used in a DIFF expression with symbols from
+ other sections. Revisit once GDB is ported. */
+#define CFI_DIFF_EXPR_OK 0
+
+#define TC_PARSE_CONS_RETURN_TYPE int
+#define TC_PARSE_CONS_RETURN_NONE 0
+
+#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) \
+ pru_parse_cons_expression (EXP, NBYTES)
+extern int pru_parse_cons_expression (expressionS *exp, int size);
+
+#define TC_CONS_FIX_NEW pru_cons_fix_new
+extern void pru_cons_fix_new (struct frag *frag, int where,
+ unsigned int nbytes, struct expressionS *exp,
+ const int is_pmem);
+
+/* If you define this macro, it means that `tc_gen_reloc' may return
+ multiple relocation entries for a single fixup. In this case, the
+ return value of `tc_gen_reloc' is a pointer to a null terminated
+ array. */
+#undef RELOC_EXPANSION_POSSIBLE
+
+/* No shared lib support, so we don't need to ensure externally
+ visible symbols can be overridden. */
+#define EXTERN_FORCE_RELOC 0
+
+/* If defined, this macro allows control over whether fixups for a
+ given section will be processed when the linkrelax variable is
+ set. Define it to zero and handle things in md_apply_fix instead. */
+#define TC_LINKRELAX_FIXUP(SEG) 0
+
+/* If this macro returns non-zero, it guarantees that a relocation will be
+ emitted even when the value can be resolved locally. Do that if
+ linkrelax is turned on. */
+#define TC_FORCE_RELOCATION(fix) pru_force_relocation (fix)
+#define TC_FORCE_RELOCATION_SUB_SAME(fix, seg) \
+ (! SEG_NORMAL (seg) || pru_force_relocation (fix))
+extern int pru_force_relocation (struct fix *);
+
+/* Do not use PC relative fixups and relocations for
+ anything but real PCREL relocations. */
+#define TC_FORCE_RELOCATION_SUB_LOCAL(FIX, SEG) \
+ (((FIX)->fx_r_type != BFD_RELOC_PRU_S10_PCREL) \
+ && ((FIX)->fx_r_type != BFD_RELOC_PRU_U8_PCREL))
+
+/* Values passed to md_apply_fix don't include the symbol value. */
+#define MD_APPLY_SYM_VALUE(FIX) 0
+
+/* We don't want gas to fixup the following memory related relocations.
+ We will need them in case that we want to do linker relaxation.
+ We could in principle keep these fixups in gas when not relaxing.
+ However, there is no serious performance penalty when making the linker
+ make the fixup work. Check also that fx_addsy is not NULL, in order to
+ make sure that the fixup refers to some sort of label. */
+#define TC_VALIDATE_FIX(FIXP,SEG,SKIP) \
+ if ((FIXP->fx_r_type == BFD_RELOC_PRU_LDI32 \
+ || FIXP->fx_r_type == BFD_RELOC_PRU_U16 \
+ || FIXP->fx_r_type == BFD_RELOC_PRU_U16_PMEMIMM \
+ || FIXP->fx_r_type == BFD_RELOC_PRU_S10_PCREL \
+ || FIXP->fx_r_type == BFD_RELOC_PRU_U8_PCREL \
+ || FIXP->fx_r_type == BFD_RELOC_PRU_32_PMEM \
+ || FIXP->fx_r_type == BFD_RELOC_PRU_16_PMEM) \
+ && FIXP->fx_addsy != NULL \
+ && FIXP->fx_subsy == NULL) \
+ { \
+ symbol_mark_used_in_reloc (FIXP->fx_addsy); \
+ goto SKIP; \
+ }
+
+/* This macro is evaluated for any fixup with a fx_subsy that
+ fixup_segment cannot reduce to a number. If the macro returns
+ false an error will be reported. */
+#define TC_VALIDATE_FIX_SUB(fix, seg) pru_validate_fix_sub (fix)
+extern int pru_validate_fix_sub (struct fix *);
+
+/* We want .cfi_* pseudo-ops for generating unwind info. */
+#define TARGET_USE_CFIPOP 1
+#define DWARF2_DEFAULT_RETURN_COLUMN 31
+#define DWARF2_CIE_DATA_ALIGNMENT (-4)
+#define tc_regname_to_dw2regnum pru_regname_to_dw2regnum
+extern int pru_regname_to_dw2regnum (char *regname);
+#define tc_cfi_frame_initial_instructions pru_frame_initial_instructions
+extern void pru_frame_initial_instructions (void);
+
+/* The difference between same-section symbols may be affected by linker
+ relaxation, so do not resolve such expressions in the assembler. */
+#define md_allow_local_subtract(l,r,s) pru_allow_local_subtract (l, r, s)
+extern bfd_boolean pru_allow_local_subtract (expressionS *, expressionS *,
+ segT);
+
+#endif /* __TC_PRU__ */
diff --git a/gas/configure.tgt b/gas/configure.tgt
index 495155539b..4abf83fb5e 100644
--- a/gas/configure.tgt
+++ b/gas/configure.tgt
@@ -396,6 +396,8 @@ case ${generic_target} in
ppc-*-kaos*) fmt=elf ;;
ppc-*-lynxos*) fmt=elf em=lynx ;;
+ pru-*-*) fmt=elf ;;
+
riscv*-*-*) fmt=elf endian=little em=linux ;;
s390-*-linux-*) fmt=elf em=linux ;;
diff --git a/gas/doc/Makefile.am b/gas/doc/Makefile.am
index 54d7ef1b5c..c604a29071 100644
--- a/gas/doc/Makefile.am
+++ b/gas/doc/Makefile.am
@@ -80,6 +80,7 @@ CPU_DOCS = \
c-pdp11.texi \
c-pj.texi \
c-ppc.texi \
+ c-pru.texi \
c-rl78.texi \
c-riscv.texi \
c-rx.texi \
diff --git a/gas/doc/all.texi b/gas/doc/all.texi
index 3c25d39796..79fcaba0d9 100644
--- a/gas/doc/all.texi
+++ b/gas/doc/all.texi
@@ -62,6 +62,7 @@
@set PDP11
@set PJ
@set PPC
+@set PRU
@set RL78
@set RISCV
@set RX
diff --git a/gas/doc/as.texinfo b/gas/doc/as.texinfo
index d83d2b305e..f03c2ef3c9 100644
--- a/gas/doc/as.texinfo
+++ b/gas/doc/as.texinfo
@@ -493,6 +493,13 @@ gcc(1), ld(1), and the Info entries for @file{binutils} and @file{ld}.
[@b{-msolaris}|@b{-mno-solaris}]
[@b{-nops=@var{count}}]
@end ifset
+@ifset PRU
+
+@emph{Target PRU options:}
+ [@b{-link-relax}]
+ [@b{-mnolink-relax}]
+ [@b{-mno-warn-regname-label}]
+@end ifset
@ifset RL78
@emph{Target RL78 options:}
@@ -1232,6 +1239,24 @@ Generate ``little endian'' format output.
@end table
@end ifset
+@ifset PRU
+
+@ifclear man
+@xref{PRU Options}, for the options available when @value{AS} is configured
+for a PRU processor.
+@end ifclear
+
+@ifset man
+@c man begin OPTIONS
+The following options are available when @value{AS} is configured for a
+PRU processor.
+@c man end
+@c man begin INCLUDE
+@include c-pru.texi
+@c ended inside the included file
+@end ifset
+@end ifset
+
@ifset M68HC11
The following options are available when @value{AS} is configured for the
Motorola 68HC11 or 68HC12 series.
@@ -7596,6 +7621,9 @@ subject, see the hardware manufacturer's manual.
@ifset PPC
* PPC-Dependent:: PowerPC Dependent Features
@end ifset
+@ifset PRU
+* PRU-Dependent:: PRU Dependent Features
+@end ifset
@ifset RL78
* RL78-Dependent:: RL78 Dependent Features
@end ifset
@@ -7825,6 +7853,10 @@ family.
@include c-ppc.texi
@end ifset
+@ifset PRU
+@include c-pru.texi
+@end ifset
+
@ifset RL78
@include c-rl78.texi
@end ifset
diff --git a/gas/doc/c-pru.texi b/gas/doc/c-pru.texi
new file mode 100644
index 0000000000..f7d756e6f7
--- /dev/null
+++ b/gas/doc/c-pru.texi
@@ -0,0 +1,150 @@
+@c Copyright (C) 2015 Free Software Foundation, Inc.
+@c This is part of the GAS manual.
+@c For copying conditions, see the file as.texinfo.
+@c man end
+@ifset GENERIC
+@page
+@node PRU-Dependent
+@chapter PRU Dependent Features
+@end ifset
+
+@cindex PRU support
+@menu
+* PRU Options:: Options
+* PRU Syntax:: Syntax
+* PRU Relocations:: Relocations
+* PRU Directives:: PRU Machine Directives
+* PRU Opcodes:: Opcodes
+@end menu
+
+@node PRU Options
+@section Options
+@cindex PRU options
+@cindex options for PRU
+
+@c man begin OPTIONS
+@table @gcctabopt
+
+@cindex @code{mlink-relax} command line option, PRU
+@item -mlink-relax
+Assume that LD would optimize LDI32 instructions by checking the upper
+16 bits of the @var{expression}. If they are all zeros, then LD would
+shorten the LDI32 instruction to a single LDI. In such case @code{@value{AS}}
+will output DIFF relocations for diff expressions.
+
+@cindex @code{mno-link-relax} command line option, PRU
+@item -mno-link-relax
+Assume that LD would not optimize LDI32 instructions. As a consequence,
+DIFF relocations will not be emitted.
+
+@cindex @code{mno-warn-regname-label} command line option, PRU
+@item -mno-warn-regname-label
+Do not warn if a label name matches a register name. Usually assembler
+programmers will want this warning to be emitted. C compilers may want
+to turn this off.
+
+@end table
+@c man end
+
+@node PRU Syntax
+@section Syntax
+@menu
+* PRU Chars:: Special Characters
+@end menu
+
+
+@node PRU Chars
+@subsection Special Characters
+
+@cindex line comment character, PRU
+@cindex PRU line comment character
+@samp{#} and @samp{;} are the line comment characters.
+
+
+@node PRU Relocations
+@section PRU Machine Relocations
+
+@cindex machine relocations, PRU
+@cindex PRU machine relocations
+
+@table @code
+
+@cindex @code{pmem} directive, PRU
+@item %pmem(@var{expression})
+Convert @var{expression} from byte-address to a
+word-address. In other words, shift right by two.
+
+@item %label(@var{expression})
+Mark the given operand as a label. This is useful if you need to jump to
+a label that matches a register name.
+
+@smallexample
+@group
+r1:
+ jmp r1 ; Will jump to register R1
+ jmp %label(r1) ; Will jump to label r1
+@end group
+@end smallexample
+
+@end table
+
+
+@node PRU Directives
+@section PRU Machine Directives
+
+@cindex machine directives, PRU
+@cindex PRU machine directives
+
+@table @code
+
+@cindex @code{align} directive, PRU
+@item .align @var{expression} [, @var{expression}]
+This is the generic @code{.align} directive, however
+this aligns to a power of two.
+
+@cindex @code{word} directive, PRU
+@item .word @var{expression}
+Create an aligned constant 4 bytes in size.
+
+@cindex @code{dword} directive, PRU
+@item .dword @var{expression}
+Create an aligned constant 8 bytes in size.
+
+@cindex @code{2byte} directive, PRU
+@item .2byte @var{expression}
+Create an unaligned constant 2 bytes in size.
+
+@cindex @code{4byte} directive, PRU
+@item .4byte @var{expression}
+Create an unaligned constant 4 bytes in size.
+
+@cindex @code{8byte} directive, PRU
+@item .8byte @var{expression}
+Create an unaligned constant 8 bytes in size.
+
+@cindex @code{16byte} directive, PRU
+@item .16byte @var{expression}
+Create an unaligned constant 16 bytes in size.
+
+@cindex @code{set no_warn_regname_label} directive, PRU
+@item .set no_warn_regname_label
+Do not output warnings when a label name matches a register name. Equivalent
+to passing the @code{-mno-warn-regname-label} command line option.
+
+@end table
+
+@node PRU Opcodes
+@section Opcodes
+
+@cindex PRU opcodes
+@cindex opcodes for PRU
+@code{@value{AS}} implements all the standard PRU core V3 opcodes in the
+original pasm assembler. Older cores are not supported by @code{@value{AS}}.
+
+GAS also implements the LDI32 pseudo instruction for loading a 32-bit
+immediate value into a register.
+
+@smallexample
+ ldi32 sp, __stack_top
+ ldi32 r14, 0x12345678
+@end smallexample
diff --git a/gas/testsuite/gas/pru/alu.d b/gas/testsuite/gas/pru/alu.d
new file mode 100644
index 0000000000..d91ad065b4
--- /dev/null
+++ b/gas/testsuite/gas/pru/alu.d
@@ -0,0 +1,32 @@
+#objdump: -dr --prefix-addresses --show-raw-insn
+#name: PRU ALU
+
+# Test the ALU instructions
+
+.*: +file format elf32-pru
+
+Disassembly of section .text:
+0+0000 <[^>]*> 00e4e4e4 add fp, fp, fp
+0+0004 <[^>]*> 01ffe4e4 add fp, fp, 255
+0+0008 <[^>]*> 0100e4e4 add fp, fp, 0
+0+000c <[^>]*> 0100e4e4 add fp, fp, 0
+0+0010 <[^>]*> 0100a424 add fp.b1, fp.w1, 0
+0+0014 <[^>]*> 00634221 add r1.b1, sp.b2, ra.b3
+0+0018 <[^>]*> 02634221 adc r1.b1, sp.b2, ra.b3
+0+001c <[^>]*> 03634221 adc r1.b1, sp.b2, 99
+0+0020 <[^>]*> 00e0e0e0 add r0, r0, r0
+0+0024 <[^>]*> 02e0e0e0 adc r0, r0, r0
+0+0028 <[^>]*> 050affe1 sub r1, r31, 10
+0+002c <[^>]*> 070affe1 suc r1, r31, 10
+0+0030 <[^>]*> 090affff lsl r31, r31, 10
+0+0034 <[^>]*> 0b0affff lsr r31, r31, 10
+0+0038 <[^>]*> 0d0a70f0 rsb r16, r16.b3, 10
+0+003c <[^>]*> 0f0a70f0 rsc r16, r16.b3, 10
+0+0040 <[^>]*> 11aa61a1 and r1.w1, r1.b3, 170
+0+0044 <[^>]*> 13aa61a1 or r1.w1, r1.b3, 170
+0+0048 <[^>]*> 15aa61a1 xor r1.w1, r1.b3, 170
+0+004c <[^>]*> 1700e1e2 not sp, r1
+0+0050 <[^>]*> 18e2e1e1 min r1, r1, sp
+0+0054 <[^>]*> 1ac3e2e1 max r1, sp, ra.w2
+0+0058 <[^>]*> 1cc3e2e1 clr r1, sp, ra.w2
+0+005c <[^>]*> 1f0ce2e1 set r1, sp, 12
diff --git a/gas/testsuite/gas/pru/alu.s b/gas/testsuite/gas/pru/alu.s
new file mode 100644
index 0000000000..e61e10191d
--- /dev/null
+++ b/gas/testsuite/gas/pru/alu.s
@@ -0,0 +1,30 @@
+# Source file used to test the ALU class of instructions.
+
+foo:
+ # Test various addressing modes
+ add fp, fp, fp
+ add fp, fp, 0xff
+ add fp, fp, 0
+ add fp, fp, 0
+ add fp.b1, fp.w1, 0
+ add r1.b1, r2.b2, r3.b3
+ adc r1.b1, r2.b2, r3.b3
+ adc r1.b1, r2.b2, 101-2
+
+ # Test ALU opcodes
+ add r0, r0, r0
+ adc r0, r0, r0
+ sub r1, r31, 10
+ suc r1, r31, 10
+ lsl r31, r31, 10
+ lsr r31, r31, 10
+ rsb r16, r16.b3, 10
+ rsc r16, r16.b3, 10
+ and r1.w1, r1.b3, 0xaa
+ or r1.w1, r1.b3, 0xaa
+ xor r1.w1, r1.b3, 0xaa
+ not r2, r1
+ min r1, r1, r2
+ max r1, r2, r3.w2
+ clr r1, r2, r3.w2
+ set r1, r2, 12
diff --git a/gas/testsuite/gas/pru/branch.d b/gas/testsuite/gas/pru/branch.d
new file mode 100644
index 0000000000..f5b50a74b5
--- /dev/null
+++ b/gas/testsuite/gas/pru/branch.d
@@ -0,0 +1,63 @@
+#objdump: -dr --prefix-addresses --show-raw-insn
+#name: PRU branch
+
+# Test the branch instructions
+
+.*: +file format elf32-pru
+
+Disassembly of section .text:
+0+0000 <[^>]*> 20ea0000 jmp r10
+0+0004 <[^>]*> 208a0000 jmp r10.w0
+0+0008 <[^>]*> 21004000 jmp 00000100 <[^>]*>
+0+000c <[^>]*> 22ca00f6 jal r22, r10.w2
+0+0010 <[^>]*> 230000f7 jal r23, 00000000 <[^>]*>
+0+0014 <[^>]*> 23ffffb7 jal r23.w1, 0003fffc <[^>]*>
+0+0018 <[^>]*> 6100f700 qbgt 00000018 <[^>]*>, r23, 0
+[\t ]*18: R_PRU_S10_PCREL[\t ]*.text\+0x60
+0+001c <[^>]*> 71ff5700 qbge 0000001c <[^>]*>, r23.b2, 255
+[\t ]*1c: R_PRU_S10_PCREL[\t ]*.text\+0x60
+0+0020 <[^>]*> 4820b600 qblt 00000020 <[^>]*>, r22.w1, r0.b1
+[\t ]*20: R_PRU_S10_PCREL[\t ]*.text\+0x60
+0+0024 <[^>]*> 58210000 qble 00000024 <[^>]*>, r0.b0, r1.b1
+[\t ]*24: R_PRU_S10_PCREL[\t ]*.text\+0x60
+0+0028 <[^>]*> 50034100 qbeq 00000028 <[^>]*>, r1.b2, ra.b0
+[\t ]*28: R_PRU_S10_PCREL[\t ]*.text\+0x60
+0+002c <[^>]*> 68f6f500 qbne 0000002c <[^>]*>, r21, r22
+[\t ]*2c: R_PRU_S10_PCREL[\t ]*.text\+0x60
+0+0030 <[^>]*> 78000000 qba 00000030 <[^>]*>
+[\t ]*30: R_PRU_S10_PCREL[\t ]*.text\+0x60
+#0+0034 <[^>]*> d0edec00 qbbs 00000034 <[^>]*>, r12, r13
+0+0034 <[^>]*> d0edec00 wbc r12, r13
+[\t ]*34: R_PRU_S10_PCREL[\t ]*.text\+0x60
+#0+0038 <[^>]*> d105ec00 qbbs 00000038 <[^>]*>, r12, 5
+0+0038 <[^>]*> d105ec00 wbc r12, 5
+[\t ]*38: R_PRU_S10_PCREL[\t ]*.text\+0x60
+#0+003c <[^>]*> c8edec00 qbbc 0000003c <[^>]*>, r12, r13
+0+003c <[^>]*> c8edec00 wbs r12, r13
+[\t ]*3c: R_PRU_S10_PCREL[\t ]*.text\+0x60
+#0+0040 <[^>]*> c905ec00 qbbc 00000040 <[^>]*>, r12, 5
+0+0040 <[^>]*> c905ec00 wbs r12, 5
+[\t ]*40: R_PRU_S10_PCREL[\t ]*.text\+0x60
+0+0044 <[^>]*> 6100f700 qbgt 00000044 <[^>]*>, r23, 0
+[\t ]*44: R_PRU_S10_PCREL[\t ]*.text\+0xc
+0+0048 <[^>]*> 71ff5700 qbge 00000048 <[^>]*>, r23.b2, 255
+[\t ]*48: R_PRU_S10_PCREL[\t ]*.text\+0xc
+0+004c <[^>]*> 4820b600 qblt 0000004c <[^>]*>, r22.w1, r0.b1
+[\t ]*4c: R_PRU_S10_PCREL[\t ]*.text\+0xc
+0+0050 <[^>]*> 58210000 qble 00000050 <[^>]*>, r0.b0, r1.b1
+[\t ]*50: R_PRU_S10_PCREL[\t ]*.text\+0xc
+0+0054 <[^>]*> 50034100 qbeq 00000054 <[^>]*>, r1.b2, ra.b0
+[\t ]*54: R_PRU_S10_PCREL[\t ]*.text\+0xc
+0+0058 <[^>]*> 68f6f500 qbne 00000058 <[^>]*>, r21, r22
+[\t ]*58: R_PRU_S10_PCREL[\t ]*.text\+0xc
+0+005c <[^>]*> 78000000 qba 0000005c <[^>]*>
+[\t ]*5c: R_PRU_S10_PCREL[\t ]*.text\+0xc
+#0+0060 <[^>]*> d0edec00 qbbs 00000060 <[^>]*>, r12, r13
+0+0060 <[^>]*> d0edec00 wbc r12, r13
+[\t ]*60: R_PRU_S10_PCREL[\t ]*.text\+0xc
+#0+0064 <[^>]*> d105ec00 qbbs 00000064 <[^>]*>, r12, 5
+0+0064 <[^>]*> d105ec00 wbc r12, 5
+[\t ]*64: R_PRU_S10_PCREL[\t ]*.text\+0xc
+#0+0068 <[^>]*> c8edec00 qbbc 00000068 <[^>]*>, r12, r13
+0+0068 <[^>]*> c8edec00 wbs r12, r13
+[\t ]*68: R_PRU_S10_PCREL[\t ]*.text\+0xc
diff --git a/gas/testsuite/gas/pru/branch.s b/gas/testsuite/gas/pru/branch.s
new file mode 100644
index 0000000000..ab43c74fd2
--- /dev/null
+++ b/gas/testsuite/gas/pru/branch.s
@@ -0,0 +1,42 @@
+# Source file used to test the miscellaneous instructions.
+
+foo:
+L1:
+ jmp r10
+ jmp r10.w0
+ jmp 0x100
+
+L2:
+ jal r22, r10.w2
+ jal r23, 0
+ jal r23.w1, 0x3fffc
+
+ # relative branches - forward jump
+L3:
+ qbgt L5, r23, 0
+ qbge L5, r23.b2, 255
+ qblt L5, r22.w1, r0.b1
+ qble L5, r0.b0, r1.b1
+ qbeq L5, r1.b2, r3.b0
+ qbne L5, r21, r22
+ qba L5
+
+ qbbs L5, r12, r13
+ qbbs L5, r12, 5
+ qbbc L5, r12, r13
+ qbbc L5, r12, 5
+
+ # relative branches - backward jump
+L4:
+ qbgt L2, r23, 0
+ qbge L2, r23.b2, 255
+ qblt L2, r22.w1, r0.b1
+ qble L2, r0.b0, r1.b1
+ qbeq L2, r1.b2, r3.b0
+ qbne L2, r21, r22
+ qba L2
+
+L5:
+ qbbs L2, r12, r13
+ qbbs L2, r12, 5
+ qbbc L2, r12, r13
diff --git a/gas/testsuite/gas/pru/illegal.l b/gas/testsuite/gas/pru/illegal.l
new file mode 100644
index 0000000000..64de14b7bd
--- /dev/null
+++ b/gas/testsuite/gas/pru/illegal.l
@@ -0,0 +1,5 @@
+.*illegal.s: Assembler messages:
+.*illegal.s:5: Error: unknown register r56
+.*illegal.s:8: Error: unrecognised instruction fop
+.*illegal.s:10: Error: too many arguments
+.*illegal.s:11: Error: too many arguments
diff --git a/gas/testsuite/gas/pru/illegal.s b/gas/testsuite/gas/pru/illegal.s
new file mode 100644
index 0000000000..1571f74033
--- /dev/null
+++ b/gas/testsuite/gas/pru/illegal.s
@@ -0,0 +1,11 @@
+# Source file used to test illegal operands.
+
+foo:
+# Illegal registers
+ add r56,r4,r5
+ add r4,r0,r2
+# Illegal opcodes
+ fop r3,r4,r5
+# Extra operands
+ nop Crapola
+ add r2, r2, r2, r4
diff --git a/gas/testsuite/gas/pru/ldi.d b/gas/testsuite/gas/pru/ldi.d
new file mode 100644
index 0000000000..885150495e
--- /dev/null
+++ b/gas/testsuite/gas/pru/ldi.d
@@ -0,0 +1,17 @@
+#objdump: -dr --prefix-addresses --show-raw-insn
+#name: PRU ldi
+
+# Test the load/store operations
+
+.*: +file format elf32-pru
+
+Disassembly of section .text:
+0+0000 <[^>]*> 240000f0 ldi r16, 0
+[\t ]*0: R_PRU_LDI32 \*ABS\*\+0x12345678
+0+0004 <[^>]*> 240000d0 ldi r16.w2, 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
+[\t ]*10: R_PRU_LDI32 var1
+0+0014 <[^>]*> 240000d0 ldi r16.w2, 0
diff --git a/gas/testsuite/gas/pru/ldi.s b/gas/testsuite/gas/pru/ldi.s
new file mode 100644
index 0000000000..201a0f2be8
--- /dev/null
+++ b/gas/testsuite/gas/pru/ldi.s
@@ -0,0 +1,9 @@
+# Source file used to test the LDI instructions.
+
+ .extern var1
+foo:
+ # immediate load
+ ldi32 r16, 0x12345678
+ ldi r16, 0x1234
+ ldi r16, %pmem(foo)
+ ldi32 r16, var1
diff --git a/gas/testsuite/gas/pru/ldst.d b/gas/testsuite/gas/pru/ldst.d
new file mode 100644
index 0000000000..7e44b6d2d0
--- /dev/null
+++ b/gas/testsuite/gas/pru/ldst.d
@@ -0,0 +1,33 @@
+#objdump: -dr --prefix-addresses --show-raw-insn
+#name: PRU load-store
+
+# Test the load/store operations
+
+.*: +file format elf32-pru
+
+Disassembly of section .text:
+0+0000 <[^>]*> 240000f0 ldi r16, 0
+0+0004 <[^>]*> 24fffff0 ldi r16, 65535
+0+0008 <[^>]*> 2401fff0 ldi r16, 511
+0+000c <[^>]*> f0611e20 lbbo r0.b1, r30, r1.b3, 1
+0+0010 <[^>]*> fe41bec0 lbbo r0.b2, r30, r1.b2, 124
+0+0014 <[^>]*> f1ff1e60 lbbo r0.b3, r30, 255, 1
+0+0018 <[^>]*> f1011e80 lbbo r0.b0, r30, 1, 2
+0+001c <[^>]*> fb005e00 lbbo r0.b0, r30, 0, 85
+0+0020 <[^>]*> fea1d912 lbbo r18.b0, r25, r1.w1, r0.b0
+0+0024 <[^>]*> ff65d992 lbbo r18.b0, r25, 101, r0.b1
+0+0028 <[^>]*> fee1f992 lbbo r18.b0, r25, r1, r0.b3
+0+002c <[^>]*> e0611e20 sbbo r0.b1, r30, r1.b3, 1
+0+0030 <[^>]*> ee41bec0 sbbo r0.b2, r30, r1.b2, 124
+0+0034 <[^>]*> e1ff1e60 sbbo r0.b3, r30, 255, 1
+0+0038 <[^>]*> e1011e80 sbbo r0.b0, r30, 1, 2
+0+003c <[^>]*> eb005e00 sbbo r0.b0, r30, 0, 85
+0+0040 <[^>]*> eee1d912 sbbo r18.b0, r25, r1, r0.b0
+0+0044 <[^>]*> ef65d992 sbbo r18.b0, r25, 101, r0.b1
+0+0048 <[^>]*> eee1f992 sbbo r18.b0, r25, r1, r0.b3
+0+004c <[^>]*> 9105608a lbco r10.b0, 0, 5, 8
+0+0050 <[^>]*> 90ab618a lbco r10.b0, 1, r11.w1, 8
+0+0054 <[^>]*> 91057f8a lbco r10.b0, 31, 5, 8
+0+0058 <[^>]*> 8105608a sbco r10.b0, 0, 5, 8
+0+005c <[^>]*> 80ab618a sbco r10.b0, 1, r11.w1, 8
+0+0060 <[^>]*> 81057f8a sbco r10.b0, 31, 5, 8
diff --git a/gas/testsuite/gas/pru/ldst.s b/gas/testsuite/gas/pru/ldst.s
new file mode 100644
index 0000000000..e8ad3a2449
--- /dev/null
+++ b/gas/testsuite/gas/pru/ldst.s
@@ -0,0 +1,37 @@
+# Source file used to test the load/store instructions.
+
+foo:
+ # immediate load
+ ldi r16, 0
+ ldi r16, 0xffff
+ ldi r16, 511
+
+ # load
+ lbbo &r0.b1, r30, r1.b3, 1
+ lbbo r0.b2, r30, r1.b2, 124
+ lbbo r0.b3, r30, 255, 1
+ lbbo &r0, r30, 1, 2
+ lbbo r0, r30, 0, 0x55
+ lbbo r18, r25, r1.w1, r0.b0
+ lbbo r18, r25, 101, r0.b1
+ lbbo r18, r25, r1, r0.b3
+
+ # store
+ sbbo &r0.b1, r30, r1.b3, 1
+ sbbo r0.b2, r30, r1.b2, 124
+ sbbo r0.b3, r30, 255, 1
+ sbbo &r0, r30, 1, 2
+ sbbo r0, r30, 0, 0x55
+ sbbo r18, r25, r1, r0.b0
+ sbbo r18, r25, 101, r0.b1
+ sbbo r18, r25, r1, r0.b3
+
+ # load with constant table address
+ lbco r10, 0, 5, 8
+ lbco r10, 1, r11.w1, 8
+ lbco r10, 31, 5, 8
+
+ # store with constant table address
+ sbco r10, 0, 5, 8
+ sbco r10, 1, r11.w1, 8
+ sbco r10, 31, 5, 8
diff --git a/gas/testsuite/gas/pru/loop.d b/gas/testsuite/gas/pru/loop.d
new file mode 100644
index 0000000000..b6d4a8a9aa
--- /dev/null
+++ b/gas/testsuite/gas/pru/loop.d
@@ -0,0 +1,15 @@
+#objdump: -dr --prefix-addresses --show-raw-insn
+#name: PRU loop
+
+# Test the loop instructions
+
+.*: +file format elf32-pru
+
+Disassembly of section .text:
+0+0000 <[^>]*> 304a0000 loop 00000000 <[^>]*>, r10.b2
+[\t ]*0: R_PRU_U8_PCREL[\t ]*.text\+0x14
+0+0004 <[^>]*> 30eb8000 iloop 00000004 <[^>]*>, r11
+[\t ]*4: R_PRU_U8_PCREL[\t ]*.text\+0x14
+0+0008 <[^>]*> 00e0e0e0 add r0, r0, r0
+0+000c <[^>]*> 00e0e0e0 add r0, r0, r0
+0+0010 <[^>]*> 00e0e0e0 add r0, r0, r0
diff --git a/gas/testsuite/gas/pru/loop.s b/gas/testsuite/gas/pru/loop.s
new file mode 100644
index 0000000000..ae057a1e96
--- /dev/null
+++ b/gas/testsuite/gas/pru/loop.s
@@ -0,0 +1,10 @@
+# Source file used to test the loop instructions.
+
+foo:
+L1:
+ loop L2, r10.b2
+ iloop L2, r11
+ add r0, r0, r0
+ add r0, r0, r0
+ add r0, r0, r0
+L2:
diff --git a/gas/testsuite/gas/pru/misc.d b/gas/testsuite/gas/pru/misc.d
new file mode 100644
index 0000000000..40a116e7fc
--- /dev/null
+++ b/gas/testsuite/gas/pru/misc.d
@@ -0,0 +1,12 @@
+#objdump: -dr --prefix-addresses --show-raw-insn
+#name: PRU misc
+
+# Test the miscellaneous instruction
+
+.*: +file format elf32-pru
+
+Disassembly of section .text:
+0+0000 <[^>]*> 2a000000 halt
+0+0004 <[^>]*> 3e800000 slp 1
+0+0008 <[^>]*> 3e000000 slp 0
+
diff --git a/gas/testsuite/gas/pru/misc.s b/gas/testsuite/gas/pru/misc.s
new file mode 100644
index 0000000000..cfe4d88fce
--- /dev/null
+++ b/gas/testsuite/gas/pru/misc.s
@@ -0,0 +1,6 @@
+# Source file used to test the miscellaneous instructions.
+
+foo:
+ halt
+ slp 1
+ slp 0
diff --git a/gas/testsuite/gas/pru/pru.exp b/gas/testsuite/gas/pru/pru.exp
new file mode 100644
index 0000000000..bf45e669b5
--- /dev/null
+++ b/gas/testsuite/gas/pru/pru.exp
@@ -0,0 +1,26 @@
+# Copyright (C) 2014-2016 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+
+#
+# Some generic PRU tests
+#
+
+if { [istarget pru-*-*] } {
+ run_dump_tests [lsort [glob -nocomplain $srcdir/$subdir/*.d]]
+
+ run_list_test "illegal" ""
+ run_list_test "warn_reglabel" ""
+}
diff --git a/gas/testsuite/gas/pru/pseudo.d b/gas/testsuite/gas/pru/pseudo.d
new file mode 100644
index 0000000000..8da6a11bd2
--- /dev/null
+++ b/gas/testsuite/gas/pru/pseudo.d
@@ -0,0 +1,15 @@
+#objdump: -dr --prefix-addresses --show-raw-insn
+#name: PRU pseudo
+
+# Test the pseudo instruction
+
+.*: +file format elf32-pru
+
+Disassembly of section .text:
+0+0000 <[^>]*> 1300e2e1 mov r1, sp
+0+0004 <[^>]*> 12e0e0e0 nop
+0+0008 <[^>]*> 230100c3 call 00000400 <[^>]*>
+0+000c <[^>]*> 22ea00c3 call r10
+0+0010 <[^>]*> 20c30000 ret
+0+0014 <[^>]*> d10cac00 wbc r12.w1, 12
+0+0018 <[^>]*> c8e1ec00 wbs r12, r1
diff --git a/gas/testsuite/gas/pru/pseudo.s b/gas/testsuite/gas/pru/pseudo.s
new file mode 100644
index 0000000000..87b7deafbd
--- /dev/null
+++ b/gas/testsuite/gas/pru/pseudo.s
@@ -0,0 +1,10 @@
+# Source file used to test the pseudo instructions.
+
+foo:
+ mov r1, r2
+ nop
+ call 0x400
+ call r10
+ ret
+ wbc r12.w1, 12
+ wbs r12, r1
diff --git a/gas/testsuite/gas/pru/warn_reglabel.l b/gas/testsuite/gas/pru/warn_reglabel.l
new file mode 100644
index 0000000000..eb077f12ec
--- /dev/null
+++ b/gas/testsuite/gas/pru/warn_reglabel.l
@@ -0,0 +1,3 @@
+.*warn_reglabel.s: Assembler messages:
+.*warn_reglabel.s:3: Warning: Label "r30" matches a CPU register name
+.*warn_reglabel.s:5: Warning: Label "r1.b2" matches a CPU register name
diff --git a/gas/testsuite/gas/pru/warn_reglabel.s b/gas/testsuite/gas/pru/warn_reglabel.s
new file mode 100644
index 0000000000..d5e46f7bb3
--- /dev/null
+++ b/gas/testsuite/gas/pru/warn_reglabel.s
@@ -0,0 +1,6 @@
+# Source file used to test warnings
+
+r30:
+ nop
+r1.b2:
+ nop
diff --git a/gas/testsuite/gas/pru/xfr.d b/gas/testsuite/gas/pru/xfr.d
new file mode 100644
index 0000000000..fd9b889264
--- /dev/null
+++ b/gas/testsuite/gas/pru/xfr.d
@@ -0,0 +1,44 @@
+#objdump: -dr --prefix-addresses --show-raw-insn
+#name: PRU xfr
+
+# Test the XFR class of instruction
+
+.*: +file format elf32-pru
+
+Disassembly of section .text:
+0+0000 <[^>]*> 2eff8002 zero sp.b0, 1
+0+0004 <[^>]*> 2eff81d7 zero r23.b2, 4
+0+0008 <[^>]*> 2effbd80 zero r0.b0, 124
+0+000c <[^>]*> 2eff0002 fill sp.b0, 1
+0+0010 <[^>]*> 2eff01b7 fill r23.b1, 4
+0+0014 <[^>]*> 2eff3d80 fill r0.b0, 124
+0+0018 <[^>]*> 2e80000a xin 0, r10.b0, 1
+0+001c <[^>]*> 2e803daa xin 0, r10.b1, 124
+0+0020 <[^>]*> 2efe806a xin 253, r10.b3, 1
+0+0024 <[^>]*> 2efebdca xin 253, r10.b2, 124
+0+0028 <[^>]*> 2eaaaa0c xin 85, r12.b0, 85
+0+002c <[^>]*> 2f00000a xout 0, r10.b0, 1
+0+0030 <[^>]*> 2f003daa xout 0, r10.b1, 124
+0+0034 <[^>]*> 2f7e806a xout 253, r10.b3, 1
+0+0038 <[^>]*> 2f7ebdca xout 253, r10.b2, 124
+0+003c <[^>]*> 2f2aaa0c xout 85, r12.b0, 85
+0+0040 <[^>]*> 2f80000a xchg 0, r10.b0, 1
+0+0044 <[^>]*> 2f803daa xchg 0, r10.b1, 124
+0+0048 <[^>]*> 2ffe806a xchg 253, r10.b3, 1
+0+004c <[^>]*> 2ffebdca xchg 253, r10.b2, 124
+0+0050 <[^>]*> 2faaaa0c xchg 85, r12.b0, 85
+0+0054 <[^>]*> 2e80400a sxin 0, r10.b0, 1
+0+0058 <[^>]*> 2e807daa sxin 0, r10.b1, 124
+0+005c <[^>]*> 2efec06a sxin 253, r10.b3, 1
+0+0060 <[^>]*> 2efefdca sxin 253, r10.b2, 124
+0+0064 <[^>]*> 2eaaea0c sxin 85, r12.b0, 85
+0+0068 <[^>]*> 2f00400a sxout 0, r10.b0, 1
+0+006c <[^>]*> 2f007daa sxout 0, r10.b1, 124
+0+0070 <[^>]*> 2f7ec06a sxout 253, r10.b3, 1
+0+0074 <[^>]*> 2f7efdca sxout 253, r10.b2, 124
+0+0078 <[^>]*> 2f2aea0c sxout 85, r12.b0, 85
+0+007c <[^>]*> 2f80400a sxchg 0, r10.b0, 1
+0+0080 <[^>]*> 2f807daa sxchg 0, r10.b1, 124
+0+0084 <[^>]*> 2ffec06a sxchg 253, r10.b3, 1
+0+0088 <[^>]*> 2ffefdca sxchg 253, r10.b2, 124
+0+008c <[^>]*> 2faaea0c sxchg 85, r12.b0, 85
diff --git a/gas/testsuite/gas/pru/xfr.s b/gas/testsuite/gas/pru/xfr.s
new file mode 100644
index 0000000000..875e1cacec
--- /dev/null
+++ b/gas/testsuite/gas/pru/xfr.s
@@ -0,0 +1,52 @@
+# Source file used to test the XFR-class of instructions.
+
+foo:
+ # register clear and fill
+ zero r2, 1
+ zero r23.b2, 4
+ zero r0, 124
+ fill r2, 1
+ fill r23.b1, 4
+ fill r0, 124
+
+ # XIN
+ xin 0, r10, 1
+ xin 0, r10.b1, 124
+ xin 253, r10.b3, 1
+ xin 253, r10.b2, 124
+ xin 85, r12.b0, 85
+
+ # XOUT
+ xout 0, r10, 1
+ xout 0, r10.b1, 124
+ xout 253, r10.b3, 1
+ xout 253, r10.b2, 124
+ xout 85, r12.b0, 85
+
+ # XCHG
+ xchg 0, r10, 1
+ xchg 0, r10.b1, 124
+ xchg 253, r10.b3, 1
+ xchg 253, r10.b2, 124
+ xchg 85, r12.b0, 85
+
+ # SXIN
+ sxin 0, r10, 1
+ sxin 0, r10.b1, 124
+ sxin 253, r10.b3, 1
+ sxin 253, r10.b2, 124
+ sxin 85, r12.b0, 85
+
+ # SXOUT
+ sxout 0, r10, 1
+ sxout 0, r10.b1, 124
+ sxout 253, r10.b3, 1
+ sxout 253, r10.b2, 124
+ sxout 85, r12.b0, 85
+
+ # XCHG
+ sxchg 0, r10, 1
+ sxchg 0, r10.b1, 124
+ sxchg 253, r10.b3, 1
+ sxchg 253, r10.b2, 124
+ sxchg 85, r12.b0, 85
--
2.11.0
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v2 11/15] ld: testsuite: PRU assembler does not support diff expressions mixing data and text labels.
2016-12-27 20:44 [PATCH v2 00/15] Binutils/gas/ld port for PRU Dimitar Dimitrov
` (13 preceding siblings ...)
2016-12-27 20:45 ` [PATCH v2 04/15] PRU LD Port Dimitar Dimitrov
@ 2016-12-27 20:45 ` Dimitar Dimitrov
2016-12-30 4:36 ` [PATCH v2 00/15] Binutils/gas/ld port for PRU Alan Modra
15 siblings, 0 replies; 19+ messages in thread
From: Dimitar Dimitrov @ 2016-12-27 20:45 UTC (permalink / raw)
To: binutils; +Cc: Dimitar Dimitrov
2016-12-26 Dimitar Dimitrov <dimitar@dinux.eu>
ld/
* testsuite/ld-elf/merge.d: Disable for PRU.
Signed-off-by: Dimitar Dimitrov <dimitar@dinux.eu>
---
ld/testsuite/ld-elf/merge.d | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ld/testsuite/ld-elf/merge.d b/ld/testsuite/ld-elf/merge.d
index 818959d1ee..d46acb6674 100644
--- a/ld/testsuite/ld-elf/merge.d
+++ b/ld/testsuite/ld-elf/merge.d
@@ -6,7 +6,7 @@
#xfail: "i370-*-*" "i860-*-*" "i960-*-*" "ip2k-*-*" "iq2000-*-*" "lm32-*-*"
#xfail: "mcore-*-*" "mn102*-*-*" "ms1-*-*" "mep-*-*" "m68hc11-*-*"
#xfail: "or32-*-*" "pj-*-*" "sparc*-*-*" "tic6x-*-*" "vax-*-*" "xstormy16-*-*"
-#xfail: "xtensa*-*-*" "metag-*-*" "ft32-*-*"
+#xfail: "xtensa*-*-*" "metag-*-*" "ft32-*-*" "pru-*-*"
.*: file format .*elf.*
--
2.11.0
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v2 08/15] ld: testsuite: Mark sec64k case as too big for PRU
2016-12-27 20:44 [PATCH v2 00/15] Binutils/gas/ld port for PRU Dimitar Dimitrov
` (5 preceding siblings ...)
2016-12-27 20:45 ` [PATCH v2 12/15] ld: testsuite: PRU LD does not support arbitrary .text base addresses Dimitar Dimitrov
@ 2016-12-27 20:45 ` Dimitar Dimitrov
2016-12-27 20:45 ` [PATCH v2 15/15] ld: testsuite: Mark --gc-sections as unsupported " Dimitar Dimitrov
` (8 subsequent siblings)
15 siblings, 0 replies; 19+ messages in thread
From: Dimitar Dimitrov @ 2016-12-27 20:45 UTC (permalink / raw)
To: binutils; +Cc: Dimitar Dimitrov
2016-12-26 Dimitar Dimitrov <dimitar@dinux.eu>
ld/
* testsuite/ld-elf/sec64k.exp: Mark sec64k case as too big for PRU.
Signed-off-by: Dimitar Dimitrov <dimitar@dinux.eu>
---
ld/testsuite/ld-elf/sec64k.exp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/ld/testsuite/ld-elf/sec64k.exp b/ld/testsuite/ld-elf/sec64k.exp
index 7f7a9f3554..283d7798af 100644
--- a/ld/testsuite/ld-elf/sec64k.exp
+++ b/ld/testsuite/ld-elf/sec64k.exp
@@ -170,7 +170,8 @@ if { ![istarget "d10v-*-*"]
&& ![istarget "avr-*-*"]
&& ![istarget "msp*-*-*"]
&& ![istarget "fr30-*-*"]
- && ![istarget "iq2000-*-*"] } {
+ && ![istarget "iq2000-*-*"]
+ && ![istarget "pru-*-*"] } {
foreach sfile $sfiles { puts $ofd "#source: $sfile" }
if { [istarget spu*-*-*] } {
puts $ofd "#ld: --local-store 0:0"
--
2.11.0
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v2 10/15] gas: testsuite: Mark lns-common-1-alt variant for PRU
2016-12-27 20:44 [PATCH v2 00/15] Binutils/gas/ld port for PRU Dimitar Dimitrov
` (11 preceding siblings ...)
2016-12-27 20:45 ` [PATCH v2 14/15] ld: testsuite: Sanitize output from ld Dimitar Dimitrov
@ 2016-12-27 20:45 ` Dimitar Dimitrov
2016-12-27 20:45 ` [PATCH v2 04/15] PRU LD Port Dimitar Dimitrov
` (2 subsequent siblings)
15 siblings, 0 replies; 19+ messages in thread
From: Dimitar Dimitrov @ 2016-12-27 20:45 UTC (permalink / raw)
To: binutils; +Cc: Dimitar Dimitrov
2016-12-26 Dimitar Dimitrov <dimitar@dinux.eu>
gas/
* testsuite/gas/lns/lns.exp: Mark lns-common-1-alt variant for PRU.
Signed-off-by: Dimitar Dimitrov <dimitar@dinux.eu>
---
gas/testsuite/gas/lns/lns.exp | 1 +
1 file changed, 1 insertion(+)
diff --git a/gas/testsuite/gas/lns/lns.exp b/gas/testsuite/gas/lns/lns.exp
index 81e0396740..acf9947d13 100644
--- a/gas/testsuite/gas/lns/lns.exp
+++ b/gas/testsuite/gas/lns/lns.exp
@@ -37,6 +37,7 @@ if {
|| [istarget mn10*-*-*]
|| [istarget msp430-*-*]
|| [istarget nds32*-*-*]
+ || [istarget pru-*-*]
|| [istarget rl78-*-*]
|| [istarget xtensa*-*-*] } {
run_dump_test "lns-common-1-alt"
--
2.11.0
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v2 05/15] PRU Opcode Port
2016-12-27 20:44 [PATCH v2 00/15] Binutils/gas/ld port for PRU Dimitar Dimitrov
` (8 preceding siblings ...)
2016-12-27 20:45 ` [PATCH v2 06/15] Add PRU ELF ID to elfcpp Dimitar Dimitrov
@ 2016-12-27 20:45 ` Dimitar Dimitrov
2016-12-27 20:45 ` [PATCH v2 07/15] ld: testsuite: Mark PRU as elf target that does not support shared libraries Dimitar Dimitrov
` (5 subsequent siblings)
15 siblings, 0 replies; 19+ messages in thread
From: Dimitar Dimitrov @ 2016-12-27 20:45 UTC (permalink / raw)
To: binutils; +Cc: Dimitar Dimitrov
2016-12-26 Dimitar Dimitrov <dimitar@dinux.eu>
include/
* dis-asm.h: Add print_insn_pru declaration.
* opcode/pru.h: New file.
opcodes/
* Makefile.in: Regenerate.
* configure: Regenerate.
* Makefile.am: Add PRU source files.
* configure.ac: Add PRU target.
* disassemble.c (disassembler): Register PRU arch.
* pru-dis.c: New file.
* pru-opc.c: New file.
Signed-off-by: Dimitar Dimitrov <dimitar@dinux.eu>
---
include/dis-asm.h | 1 +
include/opcode/pru.h | 411 ++++++++++++++++++++++++++++++++++++++++++++++++++
opcodes/Makefile.am | 2 +
opcodes/configure.ac | 1 +
opcodes/disassemble.c | 7 +-
opcodes/pru-dis.c | 286 +++++++++++++++++++++++++++++++++++
opcodes/pru-opc.c | 236 +++++++++++++++++++++++++++++
7 files changed, 943 insertions(+), 1 deletion(-)
create mode 100644 include/opcode/pru.h
create mode 100644 opcodes/pru-dis.c
create mode 100644 opcodes/pru-opc.c
diff --git a/include/dis-asm.h b/include/dis-asm.h
index 2cefff4115..91084f0c37 100644
--- a/include/dis-asm.h
+++ b/include/dis-asm.h
@@ -289,6 +289,7 @@ extern int print_insn_ns32k (bfd_vma, disassemble_info *);
extern int print_insn_or1k (bfd_vma, disassemble_info *);
extern int print_insn_pdp11 (bfd_vma, disassemble_info *);
extern int print_insn_pj (bfd_vma, disassemble_info *);
+extern int print_insn_pru (bfd_vma, disassemble_info *);
extern int print_insn_rs6000 (bfd_vma, disassemble_info *);
extern int print_insn_s390 (bfd_vma, disassemble_info *);
extern int print_insn_sh (bfd_vma, disassemble_info *);
diff --git a/include/opcode/pru.h b/include/opcode/pru.h
new file mode 100644
index 0000000000..5f2e25c900
--- /dev/null
+++ b/include/opcode/pru.h
@@ -0,0 +1,411 @@
+/* TI PRU opcode list for GAS, the GNU assembler.
+ Copyright (C) 2014-2016 Free Software Foundation, Inc.
+ Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
+
+ This file is part of GAS, the GNU Assembler, and GDB, the GNU disassembler.
+
+ GAS/GDB is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GAS/GDB is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GAS or GDB; see the file COPYING3. If not, write to
+ the Free Software Foundation, 51 Franklin Street - Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+#ifndef _PRU_H_
+#define _PRU_H_
+
+#include "bfd.h"
+
+/****************************************************************************
+ * This file contains structures, bit masks and shift counts used
+ * by the GNU toolchain to define the PRU instruction set and
+ * access various opcode fields.
+ ****************************************************************************/
+
+/* Identify different overflow situations for error messages. */
+enum overflow_type
+{
+ call_target_overflow = 0,
+ qbranch_target_overflow,
+ address_offset_overflow,
+ signed_immed16_overflow,
+ unsigned_immed32_overflow,
+ unsigned_immed16_overflow,
+ unsigned_immed8_overflow,
+ unsigned_immed5_overflow,
+ no_overflow
+};
+
+enum opcode_format_type {
+ opcode_format1,
+ opcode_format2ab,
+ opcode_format2abl,
+ opcode_format2c,
+ opcode_format2de,
+ opcode_format45,
+ opcode_format6
+};
+
+/* Opcode ID listing. Used for indexing by the simulator. */
+enum pru_instr_type {
+ prui_add, prui_adc, prui_sub, prui_suc, prui_lsl, prui_lsr, prui_rsb,
+ prui_rsc, prui_and, prui_or, prui_xor, prui_min, prui_max, prui_clr,
+ prui_set, prui_not, prui_jmp, prui_jal, prui_ldi, prui_halt, prui_slp,
+ prui_xin, prui_xout, prui_xchg, prui_sxin, prui_sxout, prui_sxchg,
+ prui_loop, prui_iloop, prui_qbgt, prui_qbge, prui_qblt, prui_qble,
+ prui_qbeq, prui_qbne, prui_qba, prui_qbbs, prui_qbbc, prui_lbbo,
+ prui_sbbo, prui_lbco, prui_sbco
+};
+
+/* This structure holds information for a particular instruction.
+
+ The args field is a string describing the operands. The following
+ letters can appear in the args:
+ b - a 5.3-bit right source register index OR 8-bit unsigned immediate
+ B - same as 'b', but for LOOP instruction where IMM is decremented
+ c - a 5 bit unsigned immediate for constant table offset
+ d - a 5.3-bit destination register index
+ D - a 5.2-bit destination register index
+ E - for internal GAS self-tests only
+ i - a 32-bit immediate or label
+ j - a 5.3-bit right source register index OR 18-bit PC address
+ l - burst length (unsigned 7-bit immediate or r0.b[0-3]) for xLBCO
+ n - burst length (unsigned 7-bit immediate or r0.b[0-3]) for XFR
+ o - a 10-bit signed PC-relative offset
+ O - an 8-bit unsigned PC-relative offset for LOOP termination point
+ R - a 5-bit destination register index
+ s - a 5.3-bit left source register index
+ S - a 5-bit left source register index
+ w - a single bit for "WakeOnStatus"
+ W - a 16-bit unsigned immediate with IO=0 field (LDI)
+ x - an 8-bit XFR wide-bus address immediate
+ Literal ',' character may also appear in the args as delimiter.
+
+ Most of the macro names are from [1].
+
+ The pinfo field is INSN_MACRO for a macro. Otherwise, it is a collection
+ of bits describing the instruction, notably any relevant hazard
+ information.
+
+ When assembling, the match field contains the opcode template, which
+ is modified by the arguments to produce the actual opcode
+ that is emitted. If pinfo is INSN_MACRO, then this is 0.
+
+ If pinfo is INSN_MACRO, the mask field stores the macro identifier.
+ Otherwise this is a bit mask for the relevant portions of the opcode
+ when disassembling. If the actual opcode anded with the match field
+ equals the opcode field, then we have found the correct instruction.
+
+ [1] http://processors.wiki.ti.com/index.php/Programmable_Realtime_Unit */
+
+struct pru_opcode
+{
+ const char *name; /* The name of the instruction. */
+ enum pru_instr_type type; /* Instruction type. Used for fast indexing
+ by the simulator. */
+ const char *args; /* A string describing the arguments for this
+ instruction. */
+ unsigned long match; /* The basic opcode for the instruction. */
+ unsigned long mask; /* Mask for the opcode field of the
+ instruction. */
+ unsigned long pinfo; /* Is this a real instruction or instruction
+ macro? */
+ enum overflow_type overflow_msg; /* Used to generate informative
+ message when fixup overflows. */
+};
+
+/* This value is used in the pru_opcode.pinfo field to indicate that the
+ instruction is a macro or pseudo-op. This requires special treatment by
+ the assembler, and is used by the disassembler to determine whether to
+ check for a nop. */
+#define PRU_INSN_MACRO 0x80000000
+
+/* This macro is specially handled throughout the code because it is
+ the only insn to output 2 words (64 bits). */
+#define PRU_INSN_LDI32 0x40000000
+
+/* Associates a register name with a 5-bit index and 3-bit regsel. */
+struct pru_reg
+{
+ const char *name; /* Name, e.g. "r10". */
+ const unsigned int index; /* Index, e.g. 10. */
+ const unsigned int regsel; /* Register field selector, .e.g RSEL_31_0. */
+};
+
+/* Macros for getting and setting an instruction field. */
+#define GET_INSN_FIELD(X, i) \
+ (((i) & OP_MASK_##X) >> OP_SH_##X)
+#define SET_INSN_FIELD(X, i, v) \
+ ((i) = (((i) & ~OP_MASK_##X) | (((v) << OP_SH_##X) & OP_MASK_##X)))
+
+#define CHECK_INSN_FIELD(X, i) \
+ (((i) & OP_MASK_##X) == OP_MATCH_##X)
+
+/* Masks, values, shifts and macros for accessing the various opcode fields. */
+
+#define OP_SH_FMT1_OP 29
+#define OP_MASK_FMT1_OP (0x7u << 29)
+#define OP_MATCH_FMT1_OP (0x0u << 29)
+
+#define OP_SH_FMT2_OP 29
+#define OP_MASK_FMT2_OP (0x7u << 29)
+#define OP_MATCH_FMT2_OP (0x1u << 29)
+
+#define OP_SH_FMT4_OP 30
+#define OP_MASK_FMT4_OP (0x3u << 30)
+#define OP_MATCH_FMT4_OP (0x1u << 30)
+
+#define OP_SH_FMT5_OP 29
+#define OP_MASK_FMT5_OP (0x7u << 29)
+#define OP_MATCH_FMT5_OP (0x6u << 29)
+
+#define OP_SH_FMT6AB_OP 29
+#define OP_MASK_FMT6AB_OP (0x7u << 29)
+#define OP_MATCH_FMT6AB_OP (0x7u << 29)
+
+#define OP_SH_FMT6CD_OP 29
+#define OP_MASK_FMT6CD_OP (0x7u << 29)
+#define OP_MATCH_FMT6CD_OP (0x4u << 29)
+
+/* Generic fields. */
+#define OP_SH_SUBOP 25
+#define OP_MASK_SUBOP (0xfu << 25)
+
+#define OP_SH_IO 24
+#define OP_MASK_IO (0x1u << 24)
+
+#define OP_SH_RS2SEL 21
+#define OP_MASK_RS2SEL (0x7u << 21)
+#define OP_SH_RS2 16
+#define OP_MASK_RS2 (0x1fu << 16)
+#define OP_SH_RS1SEL 13
+#define OP_MASK_RS1SEL (0x7u << 13)
+#define OP_SH_RS1 8
+#define OP_MASK_RS1 (0x1fu << 8)
+#define OP_SH_RDSEL 5
+#define OP_MASK_RDSEL (0x7u << 5)
+#define OP_SH_RD 0
+#define OP_MASK_RD (0x1fu << 0)
+#define OP_SH_IMM8 16
+#define OP_MASK_IMM8 (0xffu << 16)
+#define OP_SH_IMM16 8
+#define OP_MASK_IMM16 (0xffffu << 8)
+
+#define RSEL_7_0 0u
+#define RSEL_15_8 1u
+#define RSEL_23_16 2u
+#define RSEL_31_24 3u
+#define RSEL_15_0 4u
+#define RSEL_23_8 5u
+#define RSEL_31_16 6u
+#define RSEL_31_0 7u
+#define RSEL_NUM_ITEMS 8u
+
+/* Format 1 specific fields. */
+#define SUBOP_ADD 0u
+#define SUBOP_ADC 1u
+#define SUBOP_SUB 2u
+#define SUBOP_SUC 3u
+#define SUBOP_LSL 4u
+#define SUBOP_LSR 5u
+#define SUBOP_RSB 6u
+#define SUBOP_RSC 7u
+#define SUBOP_AND 8u
+#define SUBOP_OR 9u
+#define SUBOP_XOR 10u
+#define SUBOP_NOT 11u
+#define SUBOP_MIN 12u
+#define SUBOP_MAX 13u
+#define SUBOP_CLR 14u
+#define SUBOP_SET 15u
+
+/* Format 2 specific fields. */
+#define SUBOP_JMP 0u
+#define SUBOP_JAL 1u
+#define SUBOP_LDI 2u
+#define SUBOP_LMBD 3u
+#define SUBOP_SCAN 4u
+#define SUBOP_HALT 5u
+#define SUBOP_RSVD_FOR_MVIx 6u
+#define SUBOP_XFR 7u
+#define SUBOP_LOOP 8u
+#define SUBOP_RSVD_FOR_RFI 14u
+#define SUBOP_SLP 15u
+
+#define OP_SH_WAKEONSTATUS 23
+#define OP_MASK_WAKEONSTATUS (0x1u << 23)
+
+/* Format 2 XFR specific fields. */
+#define OP_SH_SUBOP_XFR 23
+#define OP_MASK_SUBOP_XFR (3u << 23)
+#define OP_SH_XFR_WBA 15
+#define OP_MASK_XFR_WBA (0xffu << 15)
+#define OP_SH_XFR_S 14
+#define OP_MASK_XFR_S (1u << 14)
+#define OP_SH_XFR_LENGTH 7
+#define OP_MASK_XFR_LENGTH (0x7fu << 7)
+
+#define SUBOP_XFR_XIN 1u
+#define SUBOP_XFR_XOUT 2u
+#define SUBOP_XFR_XCHG 3u
+
+/* Format 2 LOOP specific fields. */
+#define OP_SH_LOOP_INTERRUPTIBLE 15
+#define OP_MASK_LOOP_INTERRUPTIBLE (1u << 15)
+#define OP_SH_LOOP_JMPOFFS 0
+#define OP_MASK_LOOP_JMPOFFS (0xffu << 0)
+
+/* Format 4 specific fields. */
+#define OP_SH_BROFF98 25
+#define OP_MASK_BROFF98 (0x3u << 25)
+#define OP_SH_BROFF70 0
+#define OP_MASK_BROFF70 (0xffu << 0)
+#define OP_SH_GT 29
+#define OP_MASK_GT (0x1u << 29)
+#define OP_SH_EQ 28
+#define OP_MASK_EQ (0x1u << 28)
+#define OP_SH_LT 27
+#define OP_MASK_LT (0x1u << 27)
+#define OP_MASK_CMP (OP_MASK_GT | OP_MASK_EQ | OP_MASK_LT)
+
+
+/* Format 5 specific fields. */
+#define OP_SH_BS 28
+#define OP_MASK_BS (0x1u << 28)
+#define OP_SH_BC 27
+#define OP_MASK_BC (0x1u << 27)
+#define OP_MASK_BCMP (OP_MASK_BS | OP_MASK_BC)
+
+/* Format 6 specific fields. */
+#define OP_SH_LOADSTORE 28
+#define OP_MASK_LOADSTORE (0x1u << 28)
+#define OP_SH_BURSTLEN64 25
+#define OP_MASK_BURSTLEN64 (0x7u << 25)
+#define OP_SH_BURSTLEN31 13
+#define OP_MASK_BURSTLEN31 (0x7u << 13)
+#define OP_SH_CB 8
+#define OP_MASK_CB (0x1fu << 8)
+#define OP_SH_BURSTLEN0 7
+#define OP_MASK_BURSTLEN0 (0x1u << 7)
+#define OP_SH_RDB 5
+#define OP_MASK_RDB (0x3u << 5)
+
+#define LSSBBO_BYTECOUNT_R0_BITS7_0 124u
+#define LSBBO_BYTECOUNT_R0_BITS15_8 125u
+#define LSBBO_BYTECOUNT_R0_BITS23_16 126u
+#define LSBBO_BYTECOUNT_R0_BITS31_24 127u
+
+/* The following macros define the opcode matches for each
+ instruction code & OP_MASK_INST == OP_MATCH_INST. */
+#define OP_MATCH_ADD (OP_MATCH_FMT1_OP | (SUBOP_ADD << OP_SH_SUBOP))
+#define OP_MATCH_ADC (OP_MATCH_FMT1_OP | (SUBOP_ADC << OP_SH_SUBOP))
+#define OP_MATCH_SUB (OP_MATCH_FMT1_OP | (SUBOP_SUB << OP_SH_SUBOP))
+#define OP_MATCH_SUC (OP_MATCH_FMT1_OP | (SUBOP_SUC << OP_SH_SUBOP))
+#define OP_MATCH_LSL (OP_MATCH_FMT1_OP | (SUBOP_LSL << OP_SH_SUBOP))
+#define OP_MATCH_LSR (OP_MATCH_FMT1_OP | (SUBOP_LSR << OP_SH_SUBOP))
+#define OP_MATCH_RSB (OP_MATCH_FMT1_OP | (SUBOP_RSB << OP_SH_SUBOP))
+#define OP_MATCH_RSC (OP_MATCH_FMT1_OP | (SUBOP_RSC << OP_SH_SUBOP))
+#define OP_MATCH_AND (OP_MATCH_FMT1_OP | (SUBOP_AND << OP_SH_SUBOP))
+#define OP_MATCH_OR (OP_MATCH_FMT1_OP | (SUBOP_OR << OP_SH_SUBOP))
+#define OP_MATCH_XOR (OP_MATCH_FMT1_OP | (SUBOP_XOR << OP_SH_SUBOP))
+#define OP_MATCH_NOT (OP_MATCH_FMT1_OP | (SUBOP_NOT << OP_SH_SUBOP))
+#define OP_MATCH_MIN (OP_MATCH_FMT1_OP | (SUBOP_MIN << OP_SH_SUBOP))
+#define OP_MATCH_MAX (OP_MATCH_FMT1_OP | (SUBOP_MAX << OP_SH_SUBOP))
+#define OP_MATCH_CLR (OP_MATCH_FMT1_OP | (SUBOP_CLR << OP_SH_SUBOP))
+#define OP_MATCH_SET (OP_MATCH_FMT1_OP | (SUBOP_SET << OP_SH_SUBOP))
+
+#define OP_MATCH_JMP (OP_MATCH_FMT2_OP | (SUBOP_JMP << OP_SH_SUBOP))
+#define OP_MATCH_JAL (OP_MATCH_FMT2_OP | (SUBOP_JAL << OP_SH_SUBOP))
+#define OP_MATCH_LDI (OP_MATCH_FMT2_OP | (SUBOP_LDI << OP_SH_SUBOP))
+#define OP_MATCH_LMBD (OP_MATCH_FMT2_OP | (SUBOP_LMBD << OP_SH_SUBOP))
+#define OP_MATCH_SCAN (OP_MATCH_FMT2_OP | (SUBOP_SCAN << OP_SH_SUBOP))
+#define OP_MATCH_HALT (OP_MATCH_FMT2_OP | (SUBOP_HALT << OP_SH_SUBOP))
+#define OP_MATCH_SLP (OP_MATCH_FMT2_OP | (SUBOP_SLP << OP_SH_SUBOP))
+#define OP_MATCH_XFR (OP_MATCH_FMT2_OP | (SUBOP_XFR << OP_SH_SUBOP))
+#define OP_MATCH_SXFR (OP_MATCH_XFR | OP_MASK_XFR_S)
+#define OP_MATCH_XIN (OP_MATCH_XFR | (SUBOP_XFR_XIN << OP_SH_SUBOP_XFR))
+#define OP_MATCH_XOUT (OP_MATCH_XFR | (SUBOP_XFR_XOUT << OP_SH_SUBOP_XFR))
+#define OP_MATCH_XCHG (OP_MATCH_XFR | (SUBOP_XFR_XCHG << OP_SH_SUBOP_XFR))
+#define OP_MATCH_SXIN (OP_MATCH_SXFR | (SUBOP_XFR_XIN << OP_SH_SUBOP_XFR))
+#define OP_MATCH_SXOUT (OP_MATCH_SXFR | (SUBOP_XFR_XOUT << OP_SH_SUBOP_XFR))
+#define OP_MATCH_SXCHG (OP_MATCH_SXFR | (SUBOP_XFR_XCHG << OP_SH_SUBOP_XFR))
+#define OP_MATCH_LOOP (OP_MATCH_FMT2_OP | (SUBOP_LOOP << OP_SH_SUBOP))
+#define OP_MATCH_ILOOP (OP_MATCH_FMT2_OP | (SUBOP_LOOP << OP_SH_SUBOP) \
+ | OP_MASK_LOOP_INTERRUPTIBLE)
+
+#define OP_MATCH_QBGT (OP_MATCH_FMT4_OP | OP_MASK_GT)
+#define OP_MATCH_QBGE (OP_MATCH_FMT4_OP | OP_MASK_GT | OP_MASK_EQ)
+#define OP_MATCH_QBLT (OP_MATCH_FMT4_OP | OP_MASK_LT)
+#define OP_MATCH_QBLE (OP_MATCH_FMT4_OP | OP_MASK_LT | OP_MASK_EQ)
+#define OP_MATCH_QBEQ (OP_MATCH_FMT4_OP | OP_MASK_EQ)
+#define OP_MATCH_QBNE (OP_MATCH_FMT4_OP | OP_MASK_GT | OP_MASK_LT)
+#define OP_MATCH_QBA (OP_MATCH_FMT4_OP | OP_MASK_GT | OP_MASK_LT \
+ | OP_MASK_EQ)
+
+#define OP_MATCH_QBBS (OP_MATCH_FMT5_OP | OP_MASK_BS)
+#define OP_MATCH_QBBC (OP_MATCH_FMT5_OP | OP_MASK_BC)
+
+#define OP_MATCH_LBBO (OP_MATCH_FMT6AB_OP | OP_MASK_LOADSTORE)
+#define OP_MATCH_SBBO (OP_MATCH_FMT6AB_OP)
+#define OP_MATCH_LBCO (OP_MATCH_FMT6CD_OP | OP_MASK_LOADSTORE)
+#define OP_MATCH_SBCO (OP_MATCH_FMT6CD_OP)
+
+/* Some special extractions. */
+#define OP_MASK_BROFF (OP_MASK_BROFF98 | OP_MASK_BROFF70)
+
+#define GET_BROFF_URAW(i) \
+ ((GET_INSN_FIELD (BROFF98, i) << 8) | (GET_INSN_FIELD (BROFF70, i) << 0))
+
+#define GET_BROFF_SIGNED(i) \
+ ((long)(GET_BROFF_URAW (i) - (!!(GET_BROFF_URAW (i) & (1 << 9)) << 10)))
+
+#define SET_BROFF_URAW(i, v) \
+ do { \
+ SET_INSN_FIELD (BROFF98, (i), (v) >> 8); \
+ SET_INSN_FIELD (BROFF70, (i), (v) & 0xff); \
+ } while (0)
+
+#define GET_BURSTLEN(i) \
+ ( (GET_INSN_FIELD (BURSTLEN64, (i)) << 4) | \
+ (GET_INSN_FIELD (BURSTLEN31, (i)) << 1) | \
+ (GET_INSN_FIELD (BURSTLEN0, (i)) << 0))
+
+#define SET_BURSTLEN(i, v) \
+ do { \
+ SET_INSN_FIELD (BURSTLEN64, (i), (v) >> 4); \
+ SET_INSN_FIELD (BURSTLEN31, (i), (v) >> 1); \
+ SET_INSN_FIELD (BURSTLEN0, (i), (v) >> 0); \
+ } while (0)
+
+/* Miscellaneous helpers. */
+#define OP_MASK_XFR_OP (OP_MASK_FMT2_OP | OP_MASK_SUBOP \
+ | OP_MASK_SUBOP_XFR | OP_MASK_XFR_S)
+
+#define OP_MASK_LOOP_OP (OP_MASK_FMT2_OP | OP_MASK_SUBOP \
+ | OP_MASK_LOOP_INTERRUPTIBLE)
+
+/* These are the data structures we use to hold the instruction information. */
+extern const struct pru_opcode pru_opcodes[];
+extern const int bfd_pru_num_opcodes;
+
+/* These are the data structures used to hold the register information. */
+extern const struct pru_reg pru_regs[];
+extern const int pru_num_regs;
+
+/* Machine-independent macro for number of opcodes. */
+#define NUMOPCODES bfd_pru_num_opcodes
+#define NUMREGISTERS pru_num_regs;
+
+/* This is made extern so that the assembler can use it to find out
+ what instruction caused an error. */
+extern const struct pru_opcode *pru_find_opcode (unsigned long);
+
+#endif /* _PRU_H */
diff --git a/opcodes/Makefile.am b/opcodes/Makefile.am
index 3e9dc54a17..ff20dd0a3c 100644
--- a/opcodes/Makefile.am
+++ b/opcodes/Makefile.am
@@ -223,6 +223,8 @@ TARGET_LIBOPCODES_CFILES = \
pj-opc.c \
ppc-dis.c \
ppc-opc.c \
+ pru-dis.c \
+ pru-opc.c \
riscv-dis.c \
riscv-opc.c \
rl78-decode.c \
diff --git a/opcodes/configure.ac b/opcodes/configure.ac
index b0825beb9a..25240590fa 100644
--- a/opcodes/configure.ac
+++ b/opcodes/configure.ac
@@ -326,6 +326,7 @@ if test x${all_targets} = xfalse ; then
bfd_pj_arch) ta="$ta pj-dis.lo pj-opc.lo" ;;
bfd_powerpc_arch) ta="$ta ppc-dis.lo ppc-opc.lo" ;;
bfd_powerpc_64_arch) ta="$ta ppc-dis.lo ppc-opc.lo" ;;
+ bfd_pru_arch) ta="$ta pru-dis.lo pru-opc.lo" ;;
bfd_pyramid_arch) ;;
bfd_romp_arch) ;;
bfd_riscv_arch) ta="$ta riscv-dis.lo riscv-opc.lo" ;;
diff --git a/opcodes/disassemble.c b/opcodes/disassemble.c
index e1fb65c823..aeed703aa6 100644
--- a/opcodes/disassemble.c
+++ b/opcodes/disassemble.c
@@ -73,6 +73,7 @@
#define ARCH_pdp11
#define ARCH_pj
#define ARCH_powerpc
+#define ARCH_pru
#define ARCH_rs6000
#define ARCH_rl78
#define ARCH_rx
@@ -375,10 +376,14 @@ disassembler (bfd *abfd)
disassemble = print_insn_little_powerpc;
break;
#endif
+#ifdef ARCH_pru
+ case bfd_arch_pru:
+ disassemble = print_insn_pru;
+ break;
+#endif
#ifdef ARCH_riscv
case bfd_arch_riscv:
disassemble = print_insn_riscv;
- break;
#endif
#ifdef ARCH_rs6000
case bfd_arch_rs6000:
diff --git a/opcodes/pru-dis.c b/opcodes/pru-dis.c
new file mode 100644
index 0000000000..6de22f1f6f
--- /dev/null
+++ b/opcodes/pru-dis.c
@@ -0,0 +1,286 @@
+/* TI PRU disassemble routines
+ Copyright (C) 2014-2016 Free Software Foundation, Inc.
+ Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
+
+ This file is part of the GNU opcodes library.
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ It is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this file; see the file COPYING. If not, write to the
+ Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+#include "sysdep.h"
+#include "dis-asm.h"
+#include "opcode/pru.h"
+#include "libiberty.h"
+#include <string.h>
+#include <assert.h>
+
+/* No symbol table is available when this code runs out in an embedded
+ system as when it is used for disassembler support in a monitor. */
+#if !defined (EMBEDDED_ENV)
+#define SYMTAB_AVAILABLE 1
+#include "elf-bfd.h"
+#include "elf/pru.h"
+#endif
+
+/* Length of PRU instruction in bytes. */
+#define INSNLEN 4
+
+/* Return a pointer to an pru_opcode struct for a given instruction
+ opcode, or NULL if there is an error. */
+const struct pru_opcode *
+pru_find_opcode (unsigned long opcode)
+{
+ const struct pru_opcode *p;
+ const struct pru_opcode *op = NULL;
+ const struct pru_opcode *pseudo_op = NULL;
+
+ for (p = pru_opcodes; p < &pru_opcodes[NUMOPCODES]; p++)
+ {
+ if ((p->mask & opcode) == p->match)
+ {
+ if ((p->pinfo & PRU_INSN_MACRO) == PRU_INSN_MACRO)
+ pseudo_op = p;
+ else if ((p->pinfo & PRU_INSN_LDI32) == PRU_INSN_LDI32)
+ /* ignore - should be caught with regular patterns */;
+ else
+ op = p;
+ }
+ }
+
+ return pseudo_op ? pseudo_op : op;
+}
+
+/* There are 32 regular registers, each with 8 possible subfield selectors. */
+#define NUMREGNAMES (32 * 8)
+
+static void
+pru_print_insn_arg_reg (unsigned int r, unsigned int sel,
+ disassemble_info *info)
+{
+ unsigned int i = r * RSEL_NUM_ITEMS + sel;
+ assert (i < (unsigned int)pru_num_regs);
+ assert (i < NUMREGNAMES);
+ (*info->fprintf_func) (info->stream, "%s", pru_regs[i].name);
+}
+
+/* The function pru_print_insn_arg uses the character pointed
+ to by ARGPTR to determine how it print the next token or separator
+ character in the arguments to an instruction. */
+static int
+pru_print_insn_arg (const char *argptr,
+ unsigned long opcode, bfd_vma address,
+ disassemble_info *info)
+{
+ long offs = 0;
+ unsigned long i = 0;
+ unsigned long io = 0;
+
+ switch (*argptr)
+ {
+ case ',':
+ (*info->fprintf_func) (info->stream, "%c ", *argptr);
+ break;
+ case 'd':
+ pru_print_insn_arg_reg (GET_INSN_FIELD (RD, opcode),
+ GET_INSN_FIELD (RDSEL, opcode),
+ info);
+ break;
+ case 'D':
+ /* The first 4 values for RDB and RSEL are the same, so we
+ can reuse some code. */
+ pru_print_insn_arg_reg (GET_INSN_FIELD (RD, opcode),
+ GET_INSN_FIELD (RDB, opcode),
+ info);
+ break;
+ case 's':
+ pru_print_insn_arg_reg (GET_INSN_FIELD (RS1, opcode),
+ GET_INSN_FIELD (RS1SEL, opcode),
+ info);
+ break;
+ case 'S':
+ pru_print_insn_arg_reg (GET_INSN_FIELD (RS1, opcode),
+ RSEL_31_0,
+ info);
+ break;
+ case 'b':
+ io = GET_INSN_FIELD (IO, opcode);
+
+ if (io)
+ {
+ i = GET_INSN_FIELD (IMM8, opcode);
+ (*info->fprintf_func) (info->stream, "%ld", i);
+ }
+ else
+ {
+ pru_print_insn_arg_reg (GET_INSN_FIELD (RS2, opcode),
+ GET_INSN_FIELD (RS2SEL, opcode),
+ info);
+ }
+ break;
+ case 'B':
+ io = GET_INSN_FIELD (IO, opcode);
+
+ if (io)
+ {
+ i = GET_INSN_FIELD (IMM8, opcode) + 1;
+ (*info->fprintf_func) (info->stream, "%ld", i);
+ }
+ else
+ {
+ pru_print_insn_arg_reg (GET_INSN_FIELD (RS2, opcode),
+ GET_INSN_FIELD (RS2SEL, opcode),
+ info);
+ }
+ break;
+ case 'j':
+ io = GET_INSN_FIELD (IO, opcode);
+
+ if (io)
+ {
+ /* For the sake of pretty-printing, dump text addresses with
+ their "virtual" offset that we use for distinguishing
+ PMEM vs DMEM. This is needed for printing the correct text
+ labels. */
+ bfd_vma text_offset = address & ~0x3fffff;
+ i = GET_INSN_FIELD (IMM16, opcode) * 4;
+ (*info->print_address_func) (i + text_offset, info);
+ }
+ else
+ {
+ pru_print_insn_arg_reg (GET_INSN_FIELD (RS2, opcode),
+ GET_INSN_FIELD (RS2SEL, opcode),
+ info);
+ }
+ break;
+ case 'W':
+ i = GET_INSN_FIELD (IMM16, opcode);
+ (*info->fprintf_func) (info->stream, "%ld", i);
+ break;
+ case 'o':
+ offs = GET_BROFF_SIGNED (opcode) * 4;
+ (*info->print_address_func) (address + offs, info);
+ break;
+ case 'O':
+ offs = GET_INSN_FIELD (LOOP_JMPOFFS, opcode) * 4;
+ (*info->print_address_func) (address + offs, info);
+ break;
+ case 'l':
+ i = GET_BURSTLEN (opcode);
+ if (i < LSSBBO_BYTECOUNT_R0_BITS7_0)
+ (*info->fprintf_func) (info->stream, "%ld", i + 1);
+ else
+ {
+ i -= LSSBBO_BYTECOUNT_R0_BITS7_0;
+ (*info->fprintf_func) (info->stream, "r0.b%ld", i);
+ }
+ break;
+ case 'n':
+ i = GET_INSN_FIELD (XFR_LENGTH, opcode);
+ if (i < LSSBBO_BYTECOUNT_R0_BITS7_0)
+ (*info->fprintf_func) (info->stream, "%ld", i + 1);
+ else
+ {
+ i -= LSSBBO_BYTECOUNT_R0_BITS7_0;
+ (*info->fprintf_func) (info->stream, "r0.b%ld", i);
+ }
+ break;
+ case 'c':
+ i = GET_INSN_FIELD (CB, opcode);
+ (*info->fprintf_func) (info->stream, "%ld", i);
+ break;
+ case 'w':
+ i = GET_INSN_FIELD (WAKEONSTATUS, opcode);
+ (*info->fprintf_func) (info->stream, "%ld", i);
+ break;
+ case 'x':
+ i = GET_INSN_FIELD (XFR_WBA, opcode);
+ (*info->fprintf_func) (info->stream, "%ld", i);
+ break;
+ default:
+ (*info->fprintf_func) (info->stream, "unknown");
+ break;
+ }
+ return 0;
+}
+
+/* pru_disassemble does all the work of disassembling a PRU
+ instruction opcode. */
+static int
+pru_disassemble (bfd_vma address, unsigned long opcode,
+ disassemble_info *info)
+{
+ const struct pru_opcode *op;
+
+ info->bytes_per_line = INSNLEN;
+ info->bytes_per_chunk = INSNLEN;
+ info->display_endian = info->endian;
+ info->insn_info_valid = 1;
+ info->branch_delay_insns = 0;
+ info->data_size = 0;
+ info->insn_type = dis_nonbranch;
+ info->target = 0;
+ info->target2 = 0;
+
+ /* Find the major opcode and use this to disassemble
+ the instruction and its arguments. */
+ op = pru_find_opcode (opcode);
+
+ if (op != NULL)
+ {
+ (*info->fprintf_func) (info->stream, "%s", op->name);
+
+ const char *argstr = op->args;
+ if (argstr != NULL && *argstr != '\0')
+ {
+ (*info->fprintf_func) (info->stream, "\t");
+ while (*argstr != '\0')
+ {
+ pru_print_insn_arg (argstr, opcode, address, info);
+ ++argstr;
+ }
+ }
+ }
+ else
+ {
+ /* Handle undefined instructions. */
+ info->insn_type = dis_noninsn;
+ (*info->fprintf_func) (info->stream, "0x%lx", opcode);
+ }
+ /* Tell the caller how far to advance the program counter. */
+ return INSNLEN;
+}
+
+
+/* print_insn_pru is the main disassemble function for PRU. */
+int
+print_insn_pru (bfd_vma address, disassemble_info *info)
+{
+ bfd_byte buffer[INSNLEN];
+ int status;
+
+ status = (*info->read_memory_func) (address, buffer, INSNLEN, info);
+ if (status == 0)
+ {
+ unsigned long insn;
+ insn = (unsigned long) bfd_getl32 (buffer);
+ status = pru_disassemble (address, insn, info);
+ }
+ else
+ {
+ (*info->memory_error_func) (status, address, info);
+ status = -1;
+ }
+ return status;
+}
diff --git a/opcodes/pru-opc.c b/opcodes/pru-opc.c
new file mode 100644
index 0000000000..9b240a80de
--- /dev/null
+++ b/opcodes/pru-opc.c
@@ -0,0 +1,236 @@
+/* TI PRU opcode list.
+ Copyright (C) 2014-2016 Free Software Foundation, Inc.
+ Contributed by Dimitar Dimitrov <dimitar@dinux.eu>
+
+ This file is part of the GNU opcodes library.
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ It is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this file; see the file COPYING. If not, write to the
+ Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+/* Source:
+ http://processors.wiki.ti.com/index.php/Programmable_Realtime_Unit */
+
+#include "sysdep.h"
+#include <stdio.h>
+#include "opcode/pru.h"
+
+/* Register string table. */
+
+#define DECLARE_REG(name, index) \
+ { #name ".b0", (index), RSEL_7_0 }, \
+ { #name ".b1", (index), RSEL_15_8 }, \
+ { #name ".b2", (index), RSEL_23_16 }, \
+ { #name ".b3", (index), RSEL_31_24 }, \
+ { #name ".w0", (index), RSEL_15_0 }, \
+ { #name ".w1", (index), RSEL_23_8 }, \
+ { #name ".w2", (index), RSEL_31_16 }, \
+ { #name , (index), RSEL_31_0 }
+
+const struct pru_reg pru_regs[] = {
+ /* Standard register names. */
+ DECLARE_REG (r0, 0),
+ DECLARE_REG (r1, 1),
+ DECLARE_REG (sp, 2), /* Stack pointer. */
+ DECLARE_REG (ra, 3), /* Return address. */
+ DECLARE_REG (fp, 4), /* Frame pointer. */
+ DECLARE_REG (r5, 5),
+ DECLARE_REG (r6, 6),
+ DECLARE_REG (r7, 7),
+ DECLARE_REG (r8, 8),
+ DECLARE_REG (r9, 9),
+ DECLARE_REG (r10, 10),
+ DECLARE_REG (r11, 11),
+ DECLARE_REG (r12, 12),
+ DECLARE_REG (r13, 13),
+ DECLARE_REG (r14, 14),
+ DECLARE_REG (r15, 15),
+ DECLARE_REG (r16, 16),
+ DECLARE_REG (r17, 17),
+ DECLARE_REG (r18, 18),
+ DECLARE_REG (r19, 19),
+ DECLARE_REG (r20, 20),
+ DECLARE_REG (r21, 21),
+ DECLARE_REG (r22, 22),
+ DECLARE_REG (r23, 23),
+ DECLARE_REG (r24, 24),
+ DECLARE_REG (r25, 25),
+ DECLARE_REG (r26, 26),
+ DECLARE_REG (r27, 27),
+ DECLARE_REG (r28, 28),
+ DECLARE_REG (r29, 29),
+ DECLARE_REG (r30, 30),
+ DECLARE_REG (r31, 31),
+
+ /* Alternative names for special registers. */
+ DECLARE_REG (r2, 2),
+ DECLARE_REG (r3, 3),
+ DECLARE_REG (r4, 4)
+};
+
+#define PRU_NUM_REGS \
+ ((sizeof pru_regs) / (sizeof (pru_regs[0])))
+const int pru_num_regs = PRU_NUM_REGS;
+
+#undef PRU_NUM_REGS
+
+/* This is the opcode table used by the PRU GNU as, disassembler
+ and soon GDB. */
+const struct pru_opcode pru_opcodes[] =
+{
+ /* { name, args,
+ match, mask, pinfo, overflow_msg } */
+#define DECLARE_FORMAT1_OPCODE(str, subop) \
+ { #str, prui_ ## str, "d,s,b", \
+ OP_MATCH_ ## subop, OP_MASK_FMT1_OP | OP_MASK_SUBOP, 0, \
+ unsigned_immed8_overflow }
+
+ DECLARE_FORMAT1_OPCODE (add, ADD),
+ DECLARE_FORMAT1_OPCODE (adc, ADC),
+ DECLARE_FORMAT1_OPCODE (sub, SUB),
+ DECLARE_FORMAT1_OPCODE (suc, SUC),
+ DECLARE_FORMAT1_OPCODE (lsl, LSL),
+ DECLARE_FORMAT1_OPCODE (lsr, LSR),
+ DECLARE_FORMAT1_OPCODE (rsb, RSB),
+ DECLARE_FORMAT1_OPCODE (rsc, RSC),
+ DECLARE_FORMAT1_OPCODE (and, AND),
+ DECLARE_FORMAT1_OPCODE (or, OR),
+ DECLARE_FORMAT1_OPCODE (xor, XOR),
+ DECLARE_FORMAT1_OPCODE (min, MIN),
+ DECLARE_FORMAT1_OPCODE (max, MAX),
+ DECLARE_FORMAT1_OPCODE (clr, CLR),
+ DECLARE_FORMAT1_OPCODE (set, SET),
+
+ { "not", prui_not, "d,s",
+ OP_MATCH_NOT | OP_MASK_IO,
+ OP_MASK_FMT1_OP | OP_MASK_SUBOP | OP_MASK_IO, 0, no_overflow},
+
+ { "jmp", prui_jmp, "j",
+ OP_MATCH_JMP, OP_MASK_FMT2_OP | OP_MASK_SUBOP, 0, unsigned_immed16_overflow},
+ { "jal", prui_jal, "d,j",
+ OP_MATCH_JAL, OP_MASK_FMT2_OP | OP_MASK_SUBOP, 0, unsigned_immed16_overflow},
+ { "ldi", prui_ldi, "d,W",
+ OP_MATCH_LDI, OP_MASK_FMT2_OP | OP_MASK_SUBOP, 0, unsigned_immed16_overflow},
+ { "halt", prui_halt, "",
+ OP_MATCH_HALT, OP_MASK_FMT2_OP | OP_MASK_SUBOP, 0, no_overflow},
+ { "slp", prui_slp, "w",
+ OP_MATCH_SLP, OP_MASK_FMT2_OP | OP_MASK_SUBOP, 0, no_overflow},
+
+ { "xin", prui_xin, "x,D,n",
+ OP_MATCH_XIN, OP_MASK_XFR_OP, 0, unsigned_immed8_overflow},
+ { "xout", prui_xout, "x,D,n",
+ OP_MATCH_XOUT, OP_MASK_XFR_OP, 0, unsigned_immed8_overflow},
+ { "xchg", prui_xchg, "x,D,n",
+ OP_MATCH_XCHG, OP_MASK_XFR_OP, 0, unsigned_immed8_overflow},
+ { "sxin", prui_sxin, "x,D,n",
+ OP_MATCH_SXIN, OP_MASK_XFR_OP, 0, unsigned_immed8_overflow},
+ { "sxout", prui_sxout, "x,D,n",
+ OP_MATCH_SXOUT, OP_MASK_XFR_OP, 0, unsigned_immed8_overflow},
+ { "sxchg", prui_sxchg, "x,D,n",
+ OP_MATCH_SXCHG, OP_MASK_XFR_OP, 0, unsigned_immed8_overflow},
+
+ { "loop", prui_loop, "O,B",
+ OP_MATCH_LOOP, OP_MASK_LOOP_OP, 0, unsigned_immed8_overflow},
+ { "iloop", prui_loop, "O,B",
+ OP_MATCH_ILOOP, OP_MASK_LOOP_OP, 0, unsigned_immed8_overflow},
+
+ { "qbgt", prui_qbgt, "o,s,b",
+ OP_MATCH_QBGT, OP_MASK_FMT4_OP | OP_MASK_CMP, 0, qbranch_target_overflow},
+ { "qbge", prui_qbge, "o,s,b",
+ OP_MATCH_QBGE, OP_MASK_FMT4_OP | OP_MASK_CMP, 0, qbranch_target_overflow},
+ { "qblt", prui_qblt, "o,s,b",
+ OP_MATCH_QBLT, OP_MASK_FMT4_OP | OP_MASK_CMP, 0, qbranch_target_overflow},
+ { "qble", prui_qble, "o,s,b",
+ OP_MATCH_QBLE, OP_MASK_FMT4_OP | OP_MASK_CMP, 0, qbranch_target_overflow},
+ { "qbeq", prui_qbeq, "o,s,b",
+ OP_MATCH_QBEQ, OP_MASK_FMT4_OP | OP_MASK_CMP, 0, qbranch_target_overflow},
+ { "qbne", prui_qbne, "o,s,b",
+ OP_MATCH_QBNE, OP_MASK_FMT4_OP | OP_MASK_CMP, 0, qbranch_target_overflow},
+ { "qba", prui_qba, "o",
+ OP_MATCH_QBA, OP_MASK_FMT4_OP | OP_MASK_CMP, 0, qbranch_target_overflow},
+
+ { "qbbs", prui_qbbs, "o,s,b",
+ OP_MATCH_QBBS, OP_MASK_FMT5_OP | OP_MASK_BCMP, 0, qbranch_target_overflow},
+ { "qbbc", prui_qbbc, "o,s,b",
+ OP_MATCH_QBBC, OP_MASK_FMT5_OP | OP_MASK_BCMP, 0, qbranch_target_overflow},
+
+ { "lbbo", prui_lbbo, "D,S,b,l",
+ OP_MATCH_LBBO, OP_MASK_FMT6AB_OP | OP_MASK_LOADSTORE, 0,
+ unsigned_immed8_overflow},
+ { "sbbo", prui_sbbo, "D,S,b,l",
+ OP_MATCH_SBBO, OP_MASK_FMT6AB_OP | OP_MASK_LOADSTORE, 0,
+ unsigned_immed8_overflow},
+ { "lbco", prui_lbco, "D,c,b,l",
+ OP_MATCH_LBCO, OP_MASK_FMT6CD_OP | OP_MASK_LOADSTORE, 0,
+ unsigned_immed8_overflow},
+ { "sbco", prui_sbco, "D,c,b,l",
+ OP_MATCH_SBCO, OP_MASK_FMT6CD_OP | OP_MASK_LOADSTORE, 0,
+ unsigned_immed8_overflow},
+
+ /* Fill in the default values for the real-instruction arguments.
+ The assembler will not do it! */
+ { "nop", prui_or, "",
+ OP_MATCH_OR
+ | (RSEL_31_0 << OP_SH_RS2SEL) | (0 << OP_SH_RS2)
+ | (RSEL_31_0 << OP_SH_RS1SEL) | (0 << OP_SH_RS1)
+ | (RSEL_31_0 << OP_SH_RDSEL) | (0 << OP_SH_RD),
+ OP_MASK_FMT1_OP | OP_MASK_SUBOP
+ | OP_MASK_RS2SEL | OP_MASK_RS2 | OP_MASK_RS1SEL | OP_MASK_RS1
+ | OP_MASK_RDSEL | OP_MASK_RD | OP_MASK_IO,
+ PRU_INSN_MACRO, no_overflow},
+ { "mov", prui_or, "d,s",
+ OP_MATCH_OR | (0 << OP_SH_IMM8) | OP_MASK_IO,
+ OP_MASK_FMT1_OP | OP_MASK_SUBOP | OP_MASK_IMM8 | OP_MASK_IO,
+ PRU_INSN_MACRO, no_overflow},
+ { "ret", prui_jmp, "",
+ OP_MATCH_JMP
+ | (RSEL_31_16 << OP_SH_RS2SEL) | (3 << OP_SH_RS2),
+ OP_MASK_FMT2_OP | OP_MASK_SUBOP
+ | OP_MASK_RS2SEL | OP_MASK_RS2 | OP_MASK_IO,
+ PRU_INSN_MACRO, unsigned_immed16_overflow},
+ { "call", prui_jal, "j",
+ OP_MATCH_JAL
+ | (RSEL_31_16 << OP_SH_RDSEL) | (3 << OP_SH_RD),
+ OP_MASK_FMT2_OP | OP_MASK_SUBOP
+ | OP_MASK_RDSEL | OP_MASK_RD,
+ PRU_INSN_MACRO, unsigned_immed16_overflow},
+
+ { "wbc", prui_qbbs, "s,b",
+ OP_MATCH_QBBS | (0 << OP_SH_BROFF98) | (0 << OP_SH_BROFF70),
+ OP_MASK_FMT5_OP | OP_MASK_BCMP | OP_MASK_BROFF,
+ PRU_INSN_MACRO, qbranch_target_overflow},
+ { "wbs", prui_qbbc, "s,b",
+ OP_MATCH_QBBC | (0 << OP_SH_BROFF98) | (0 << OP_SH_BROFF70),
+ OP_MASK_FMT5_OP | OP_MASK_BCMP | OP_MASK_BROFF,
+ PRU_INSN_MACRO, qbranch_target_overflow},
+
+ { "fill", prui_xin, "D,n",
+ OP_MATCH_XIN | (254 << OP_SH_XFR_WBA),
+ OP_MASK_XFR_OP | OP_MASK_XFR_WBA,
+ PRU_INSN_MACRO, unsigned_immed8_overflow},
+ { "zero", prui_xin, "D,n",
+ OP_MATCH_XIN | (255 << OP_SH_XFR_WBA),
+ OP_MASK_XFR_OP | OP_MASK_XFR_WBA,
+ PRU_INSN_MACRO, unsigned_immed8_overflow},
+
+ { "ldi32", prui_ldi, "R,i",
+ OP_MATCH_LDI, OP_MASK_FMT2_OP | OP_MASK_SUBOP,
+ PRU_INSN_LDI32, unsigned_immed32_overflow},
+};
+
+#define PRU_NUM_OPCODES \
+ ((sizeof pru_opcodes) / (sizeof (pru_opcodes[0])))
+const int bfd_pru_num_opcodes = PRU_NUM_OPCODES;
+
+#undef PRU_NUM_OPCODES
--
2.11.0
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v2 12/15] ld: testsuite: PRU LD does not support arbitrary .text base addresses.
2016-12-27 20:44 [PATCH v2 00/15] Binutils/gas/ld port for PRU Dimitar Dimitrov
` (4 preceding siblings ...)
2016-12-27 20:44 ` [PATCH v2 09/15] ld: testsuite: Fix srec test setup for PRU Dimitar Dimitrov
@ 2016-12-27 20:45 ` Dimitar Dimitrov
2016-12-27 20:45 ` [PATCH v2 08/15] ld: testsuite: Mark sec64k case as too big for PRU Dimitar Dimitrov
` (9 subsequent siblings)
15 siblings, 0 replies; 19+ messages in thread
From: Dimitar Dimitrov @ 2016-12-27 20:45 UTC (permalink / raw)
To: binutils; +Cc: Dimitar Dimitrov
2016-12-26 Dimitar Dimitrov <dimitar@dinux.eu>
ld/
* testsuite/ld-elf/pr14926.d: Disable for PRU.
Signed-off-by: Dimitar Dimitrov <dimitar@dinux.eu>
---
ld/testsuite/ld-elf/pr14926.d | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ld/testsuite/ld-elf/pr14926.d b/ld/testsuite/ld-elf/pr14926.d
index 88c521ce87..8fc8e6416c 100644
--- a/ld/testsuite/ld-elf/pr14926.d
+++ b/ld/testsuite/ld-elf/pr14926.d
@@ -1,6 +1,6 @@
#ld: -Ttext=0x60
#readelf: -S --wide
-#notarget: d10v-* m68hc1*-* msp*-* visium-* xgate-* xstormy*-*
+#notarget: d10v-* m68hc1*-* msp*-* visium-* xgate-* xstormy*-* pru-*-*
# the above targets use memory regions that don't allow 0x60 for .text
#...
--
2.11.0
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v2 15/15] ld: testsuite: Mark --gc-sections as unsupported for PRU
2016-12-27 20:44 [PATCH v2 00/15] Binutils/gas/ld port for PRU Dimitar Dimitrov
` (6 preceding siblings ...)
2016-12-27 20:45 ` [PATCH v2 08/15] ld: testsuite: Mark sec64k case as too big for PRU Dimitar Dimitrov
@ 2016-12-27 20:45 ` Dimitar Dimitrov
2016-12-27 20:45 ` [PATCH v2 06/15] Add PRU ELF ID to elfcpp Dimitar Dimitrov
` (7 subsequent siblings)
15 siblings, 0 replies; 19+ messages in thread
From: Dimitar Dimitrov @ 2016-12-27 20:45 UTC (permalink / raw)
To: binutils; +Cc: Dimitar Dimitrov
2016-12-26 Dimitar Dimitrov <dimitar@dinux.eu>
ld/
testsuite/ld-elf/group8a.d: Disable for PRU.
testsuite/ld-elf/group8b.d: Disable for PRU.
testsuite/ld-elf/group9a.d: Disable for PRU.
testsuite/ld-elf/group9b.d: Disable for PRU.
testsuite/ld-elf/pr12851.d: Disable for PRU.
testsuite/lib/ld-lib.exp (check_gc_sections_available): Mark PRU
as not supporting --gc-sections.
Signed-off-by: Dimitar Dimitrov <dimitar@dinux.eu>
---
ld/testsuite/ld-elf/group8a.d | 2 +-
ld/testsuite/ld-elf/group8b.d | 2 +-
ld/testsuite/ld-elf/group9a.d | 2 +-
ld/testsuite/ld-elf/group9b.d | 2 +-
ld/testsuite/ld-elf/pr12851.d | 2 +-
ld/testsuite/lib/ld-lib.exp | 1 +
6 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/ld/testsuite/ld-elf/group8a.d b/ld/testsuite/ld-elf/group8a.d
index 45955ba390..52112e9208 100644
--- a/ld/testsuite/ld-elf/group8a.d
+++ b/ld/testsuite/ld-elf/group8a.d
@@ -1,7 +1,7 @@
#source: group8.s
#ld: -r --gc-sections --entry foo
#readelf: -g --wide
-#notarget: d30v-*-* dlx-*-* i960-*-* pj*-*-*
+#notarget: d30v-*-* dlx-*-* i960-*-* pj*-*-* pru-*-*
#notarget: hppa64-*-* i370-*-* i860-*-* ia64-*-* mep-*-* mn10200-*-*
#xfail: cr16-*-* crx-*-*
# generic linker targets don't support --gc-sections, nor do a bunch of others
diff --git a/ld/testsuite/ld-elf/group8b.d b/ld/testsuite/ld-elf/group8b.d
index 0175c7fac9..879cd1305d 100644
--- a/ld/testsuite/ld-elf/group8b.d
+++ b/ld/testsuite/ld-elf/group8b.d
@@ -1,7 +1,7 @@
#source: group8.s
#ld: -r --gc-sections --entry bar
#readelf: -g --wide
-#notarget: d30v-*-* dlx-*-* i960-*-* pj*-*-*
+#notarget: d30v-*-* dlx-*-* i960-*-* pj*-*-* pru-*-*
#notarget: hppa64-*-* i370-*-* i860-*-* ia64-*-* mep-*-* mn10200-*-*
#xfail: cr16-*-* crx-*-*
# generic linker targets don't support --gc-sections, nor do a bunch of others
diff --git a/ld/testsuite/ld-elf/group9a.d b/ld/testsuite/ld-elf/group9a.d
index 44fe606b36..346254b13f 100644
--- a/ld/testsuite/ld-elf/group9a.d
+++ b/ld/testsuite/ld-elf/group9a.d
@@ -1,7 +1,7 @@
#source: group9.s
#ld: -r --gc-sections --entry foo
#readelf: -g --wide
-#notarget: d30v-*-* dlx-*-* i960-*-* pj*-*-*
+#notarget: d30v-*-* dlx-*-* i960-*-* pj*-*-* pru-*-*
#notarget: alpha-*-* hppa64-*-* i370-*-* i860-*-* ia64-*-* mep-*-* mn10200-*-*
#xfail: cr16-*-* crx-*-*
# generic linker targets don't support --gc-sections, nor do a bunch of others
diff --git a/ld/testsuite/ld-elf/group9b.d b/ld/testsuite/ld-elf/group9b.d
index 4ab2ba6922..3005f8f4b7 100644
--- a/ld/testsuite/ld-elf/group9b.d
+++ b/ld/testsuite/ld-elf/group9b.d
@@ -1,7 +1,7 @@
#source: group9.s
#ld: -r --gc-sections --entry bar
#readelf: -g --wide
-#notarget: d30v-*-* dlx-*-* i960-*-* pj*-*-*
+#notarget: d30v-*-* dlx-*-* i960-*-* pj*-*-* pru-*-*
#notarget: alpha-*-* hppa64-*-* i370-*-* i860-*-* ia64-*-* mep-*-* mn10200-*-*
#xfail: cr16-*-* crx-*-*
# generic linker targets don't support --gc-sections, nor do a bunch of others
diff --git a/ld/testsuite/ld-elf/pr12851.d b/ld/testsuite/ld-elf/pr12851.d
index 48ecb09012..61c224d47d 100644
--- a/ld/testsuite/ld-elf/pr12851.d
+++ b/ld/testsuite/ld-elf/pr12851.d
@@ -2,7 +2,7 @@
#source: start.s
#ld: --gc-sections
#readelf: -s --wide
-#notarget: d30v-*-* dlx-*-* i960-*-* pj*-*-*
+#notarget: d30v-*-* dlx-*-* i960-*-* pj*-*-* pru-*-*
#notarget: hppa64-*-* i370-*-* i860-*-* ia64-*-* mep-*-* mn10200-*-*
# generic linker targets don't support --gc-sections, nor do a bunch of others
diff --git a/ld/testsuite/lib/ld-lib.exp b/ld/testsuite/lib/ld-lib.exp
index 30aea19e71..5049b12903 100644
--- a/ld/testsuite/lib/ld-lib.exp
+++ b/ld/testsuite/lib/ld-lib.exp
@@ -1705,6 +1705,7 @@ proc check_gc_sections_available { } {
|| [istarget dlx-*-*]
|| [istarget i960-*-*]
|| [istarget pj*-*-*]
+ || [istarget pru*-*-*]
|| [istarget alpha-*-*]
|| [istarget hppa*64-*-*]
|| [istarget i370-*-*]
--
2.11.0
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v2 04/15] PRU LD Port
2016-12-27 20:44 [PATCH v2 00/15] Binutils/gas/ld port for PRU Dimitar Dimitrov
` (12 preceding siblings ...)
2016-12-27 20:45 ` [PATCH v2 10/15] gas: testsuite: Mark lns-common-1-alt variant for PRU Dimitar Dimitrov
@ 2016-12-27 20:45 ` Dimitar Dimitrov
2016-12-27 20:45 ` [PATCH v2 11/15] ld: testsuite: PRU assembler does not support diff expressions mixing data and text labels Dimitar Dimitrov
2016-12-30 4:36 ` [PATCH v2 00/15] Binutils/gas/ld port for PRU Alan Modra
15 siblings, 0 replies; 19+ messages in thread
From: Dimitar Dimitrov @ 2016-12-27 20:45 UTC (permalink / raw)
To: binutils; +Cc: Dimitar Dimitrov
2016-12-26 Dimitar Dimitrov <dimitar@dinux.eu>
ld/
* Makefile.in: Regenerate.
* NEWS: Mention new PRU target.
* Makefile.am: Add PRU target.
* configure.tgt: Ditto.
* emulparams/pruelf.sh: New file.
* emultempl/pruelf.em: New file.
* scripttempl/pru.sc: New file.
* testsuite/ld-pru/emit-relocs-1.d: New PRU testcase file.
* testsuite/ld-pru/emit-relocs-1.ld: Ditto.
* testsuite/ld-pru/emit-relocs-1a.s: Ditto.
* testsuite/ld-pru/emit-relocs-1b.s
* testsuite/ld-pru/ldi32.d: Ditto.
* testsuite/ld-pru/ldi32.s: Ditto.
* testsuite/ld-pru/ldi32_symbol.s: Ditto.
* testsuite/ld-pru/norelax_ldi32-data.d: Ditto.
* testsuite/ld-pru/norelax_ldi32-dis.d: Ditto.
* testsuite/ld-pru/pcrel_s10.d: Ditto.
* testsuite/ld-pru/pcrel_s10.s: Ditto.
* testsuite/ld-pru/pcrel_s10_label.s: Ditto.
* testsuite/ld-pru/pcrel_u8-illegal.d: Ditto.
* testsuite/ld-pru/pcrel_u8-illegal.s: Ditto.
* testsuite/ld-pru/pcrel_u8-illegal2.d: Ditto.
* testsuite/ld-pru/pcrel_u8-illegal2.s: Ditto.
* testsuite/ld-pru/pcrel_u8-illegal3.d: Ditto.
* testsuite/ld-pru/pcrel_u8-illegal3.s: Ditto.
* testsuite/ld-pru/pcrel_u8.d: Ditto.
* testsuite/ld-pru/pcrel_u8.s: Ditto.
* testsuite/ld-pru/pcrel_u8_label.s: Ditto.
* testsuite/ld-pru/pmem.d: Ditto.
* testsuite/ld-pru/pmem.s: Ditto.
* testsuite/ld-pru/pmem_symbol.s: Ditto.
* testsuite/ld-pru/pru.exp: Ditto.
* testsuite/ld-pru/relax_ldi32-data.d: Ditto.
* testsuite/ld-pru/relax_ldi32-dis.d: Ditto.
* testsuite/ld-pru/relax_ldi32.s: Ditto.
* testsuite/ld-pru/relax_ldi32_symbol.s: Ditto.
* testsuite/ld-pru/reloc.d: Ditto.
* testsuite/ld-pru/reloc.s: Ditto.
* testsuite/ld-pru/reloc_symbol.s: Ditto.
* testsuite/ld-pru/u16.d: Ditto.
* testsuite/ld-pru/u16.s: Ditto.
* testsuite/ld-pru/u16_symbol.s: Ditto.
Signed-off-by: Dimitar Dimitrov <dimitar@dinux.eu>
---
ld/Makefile.am | 6 ++
ld/NEWS | 2 +
ld/configure.tgt | 1 +
ld/emulparams/pruelf.sh | 19 ++++
ld/emultempl/pruelf.em | 50 +++++++++
ld/scripttempl/pru.sc | 179 +++++++++++++++++++++++++++++++
ld/testsuite/ld-pru/emit-relocs-1.d | 37 +++++++
ld/testsuite/ld-pru/emit-relocs-1.ld | 20 ++++
ld/testsuite/ld-pru/emit-relocs-1a.s | 24 +++++
ld/testsuite/ld-pru/emit-relocs-1b.s | 18 ++++
ld/testsuite/ld-pru/ldi32.d | 12 +++
ld/testsuite/ld-pru/ldi32.s | 6 ++
ld/testsuite/ld-pru/ldi32_symbol.s | 3 +
ld/testsuite/ld-pru/norelax_ldi32-data.d | 20 ++++
ld/testsuite/ld-pru/norelax_ldi32-dis.d | 29 +++++
ld/testsuite/ld-pru/pcrel_s10.d | 18 ++++
ld/testsuite/ld-pru/pcrel_s10.s | 8 ++
ld/testsuite/ld-pru/pcrel_s10_label.s | 9 ++
ld/testsuite/ld-pru/pcrel_u8-illegal.d | 7 ++
ld/testsuite/ld-pru/pcrel_u8-illegal.s | 10 ++
ld/testsuite/ld-pru/pcrel_u8-illegal2.d | 7 ++
ld/testsuite/ld-pru/pcrel_u8-illegal2.s | 7 ++
ld/testsuite/ld-pru/pcrel_u8-illegal3.d | 7 ++
ld/testsuite/ld-pru/pcrel_u8-illegal3.s | 7 ++
ld/testsuite/ld-pru/pcrel_u8.d | 15 +++
ld/testsuite/ld-pru/pcrel_u8.s | 10 ++
ld/testsuite/ld-pru/pcrel_u8_label.s | 4 +
ld/testsuite/ld-pru/pmem.d | 15 +++
ld/testsuite/ld-pru/pmem.s | 15 +++
ld/testsuite/ld-pru/pmem_symbol.s | 15 +++
ld/testsuite/ld-pru/pru.exp | 9 ++
ld/testsuite/ld-pru/relax_ldi32-data.d | 19 ++++
ld/testsuite/ld-pru/relax_ldi32-dis.d | 27 +++++
ld/testsuite/ld-pru/relax_ldi32.s | 30 ++++++
ld/testsuite/ld-pru/relax_ldi32_symbol.s | 6 ++
ld/testsuite/ld-pru/reloc.d | 14 +++
ld/testsuite/ld-pru/reloc.s | 9 ++
ld/testsuite/ld-pru/reloc_symbol.s | 25 +++++
ld/testsuite/ld-pru/u16.d | 11 ++
ld/testsuite/ld-pru/u16.s | 4 +
ld/testsuite/ld-pru/u16_symbol.s | 3 +
41 files changed, 737 insertions(+)
create mode 100644 ld/emulparams/pruelf.sh
create mode 100644 ld/emultempl/pruelf.em
create mode 100644 ld/scripttempl/pru.sc
create mode 100644 ld/testsuite/ld-pru/emit-relocs-1.d
create mode 100644 ld/testsuite/ld-pru/emit-relocs-1.ld
create mode 100644 ld/testsuite/ld-pru/emit-relocs-1a.s
create mode 100644 ld/testsuite/ld-pru/emit-relocs-1b.s
create mode 100644 ld/testsuite/ld-pru/ldi32.d
create mode 100644 ld/testsuite/ld-pru/ldi32.s
create mode 100644 ld/testsuite/ld-pru/ldi32_symbol.s
create mode 100644 ld/testsuite/ld-pru/norelax_ldi32-data.d
create mode 100644 ld/testsuite/ld-pru/norelax_ldi32-dis.d
create mode 100644 ld/testsuite/ld-pru/pcrel_s10.d
create mode 100644 ld/testsuite/ld-pru/pcrel_s10.s
create mode 100644 ld/testsuite/ld-pru/pcrel_s10_label.s
create mode 100644 ld/testsuite/ld-pru/pcrel_u8-illegal.d
create mode 100644 ld/testsuite/ld-pru/pcrel_u8-illegal.s
create mode 100644 ld/testsuite/ld-pru/pcrel_u8-illegal2.d
create mode 100644 ld/testsuite/ld-pru/pcrel_u8-illegal2.s
create mode 100644 ld/testsuite/ld-pru/pcrel_u8-illegal3.d
create mode 100644 ld/testsuite/ld-pru/pcrel_u8-illegal3.s
create mode 100644 ld/testsuite/ld-pru/pcrel_u8.d
create mode 100644 ld/testsuite/ld-pru/pcrel_u8.s
create mode 100644 ld/testsuite/ld-pru/pcrel_u8_label.s
create mode 100644 ld/testsuite/ld-pru/pmem.d
create mode 100644 ld/testsuite/ld-pru/pmem.s
create mode 100644 ld/testsuite/ld-pru/pmem_symbol.s
create mode 100644 ld/testsuite/ld-pru/pru.exp
create mode 100644 ld/testsuite/ld-pru/relax_ldi32-data.d
create mode 100644 ld/testsuite/ld-pru/relax_ldi32-dis.d
create mode 100644 ld/testsuite/ld-pru/relax_ldi32.s
create mode 100644 ld/testsuite/ld-pru/relax_ldi32_symbol.s
create mode 100644 ld/testsuite/ld-pru/reloc.d
create mode 100644 ld/testsuite/ld-pru/reloc.s
create mode 100644 ld/testsuite/ld-pru/reloc_symbol.s
create mode 100644 ld/testsuite/ld-pru/u16.d
create mode 100644 ld/testsuite/ld-pru/u16.s
create mode 100644 ld/testsuite/ld-pru/u16_symbol.s
diff --git a/ld/Makefile.am b/ld/Makefile.am
index ac908bce85..524be3e097 100644
--- a/ld/Makefile.am
+++ b/ld/Makefile.am
@@ -1714,6 +1714,12 @@ eppcnw.c: $(srcdir)/emulparams/ppcnw.sh \
eppcpe.c: $(srcdir)/emulparams/ppcpe.sh \
$(srcdir)/emultempl/pe.em $(srcdir)/scripttempl/ppcpe.sc ${GEN_DEPENDS}
+epruelf.c: $(srcdir)/emulparams/pruelf.sh \
+ $(srcdir)/emultempl/elf32.em \
+ $(ELF_DEPS) $(srcdir)/scripttempl/pru.sc \
+ $(srcdir)/emultempl/pruelf.em ${GEN_DEPENDS}
+ ${GENSCRIPTS} pruelf "$(tdir_pruelf)"
+
eriscix.c: $(srcdir)/emulparams/riscix.sh \
$(srcdir)/emultempl/generic.em $(srcdir)/scripttempl/aout.sc ${GEN_DEPENDS}
diff --git a/ld/NEWS b/ld/NEWS
index 583d50a3b2..0a455505d1 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -1,5 +1,7 @@
-*- text -*-
+* Add support for the Texas Instruments PRU processor.
+
Changes in 2.28:
* The EXCLUDE_FILE linker script construct can now be applied outside of the
diff --git a/ld/configure.tgt b/ld/configure.tgt
index b9f4782b4d..5e0447e6b1 100644
--- a/ld/configure.tgt
+++ b/ld/configure.tgt
@@ -684,6 +684,7 @@ powerpc-*-aix*) targ_emul=aixppc ;;
powerpc-*-beos*) targ_emul=aixppc ;;
powerpc-*-windiss*) targ_emul=elf32ppcwindiss ;;
powerpc-*-lynxos*) targ_emul=ppclynx ;;
+pru*-*-*) targ_emul=pruelf ;;
riscv32*-*-*) targ_emul=elf32lriscv
targ_extra_emuls="elf64lriscv"
targ_extra_libpath=$targ_extra_emuls ;;
diff --git a/ld/emulparams/pruelf.sh b/ld/emulparams/pruelf.sh
new file mode 100644
index 0000000000..02debba764
--- /dev/null
+++ b/ld/emulparams/pruelf.sh
@@ -0,0 +1,19 @@
+SCRIPT_NAME=elf
+TEMPLATE_NAME=elf32
+OUTPUT_FORMAT="elf32-pru"
+LITTLE_OUTPUT_FORMAT="elf32-pru"
+SCRIPT_NAME=pru
+
+ARCH=pru
+MACHINE=
+MAXPAGESIZE="CONSTANT (MAXPAGESIZE)"
+COMMONPAGESIZE="CONSTANT (COMMONPAGESIZE)"
+EMBEDDED=yes
+
+TEXT_ORIGIN=0x20000000
+TEXT_LENGTH=8K
+DATA_ORIGIN=0x0
+DATA_LENGTH=8K
+
+ENTRY=_start
+EXTRA_EM_FILE=pruelf
diff --git a/ld/emultempl/pruelf.em b/ld/emultempl/pruelf.em
new file mode 100644
index 0000000000..dd3ec7669f
--- /dev/null
+++ b/ld/emultempl/pruelf.em
@@ -0,0 +1,50 @@
+# This shell script emits a C file. -*- C -*-
+# Copyright (C) 2016 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+
+# This file is sourced from elf32.em, and defines extra pru-elf
+# specific routines.
+#
+fragment <<EOF
+
+#include "ldctor.h"
+
+/* This is called after the sections have been attached to output
+ sections, but before any sizes or addresses have been set. */
+
+static void
+pruelf_before_allocation (void)
+{
+ /* Call the default first. */
+ gld${EMULATION_NAME}_before_allocation ();
+
+ /* Enable relaxation by default if the "--no-relax" option was not
+ specified. This is done here instead of in the before_parse hook
+ because there is a check in main() to prohibit use of --relax and
+ -r together. */
+ if (RELAXATION_DISABLED_BY_DEFAULT)
+ ENABLE_RELAXATION;
+}
+
+EOF
+
+# Put these extra pru-elf routines in ld_${EMULATION_NAME}_emulation
+#
+LDEMUL_BEFORE_ALLOCATION=pruelf_before_allocation
diff --git a/ld/scripttempl/pru.sc b/ld/scripttempl/pru.sc
new file mode 100644
index 0000000000..88fe06cb63
--- /dev/null
+++ b/ld/scripttempl/pru.sc
@@ -0,0 +1,179 @@
+cat <<EOF
+OUTPUT_FORMAT("${OUTPUT_FORMAT}","${OUTPUT_FORMAT}","${OUTPUT_FORMAT}")
+OUTPUT_ARCH(${ARCH})
+
+MEMORY
+{
+ imem (x) : ORIGIN = $TEXT_ORIGIN, LENGTH = $TEXT_LENGTH
+ dmem (rw!x) : ORIGIN = $DATA_ORIGIN, LENGTH = $DATA_LENGTH
+}
+
+__HEAP_SIZE = DEFINED(__HEAP_SIZE) ? __HEAP_SIZE : 32;
+__STACK_SIZE = DEFINED(__STACK_SIZE) ? __STACK_SIZE : 512;
+
+${RELOCATING+ PROVIDE (_stack_top = ORIGIN(dmem) + LENGTH(dmem)) ; }
+
+${RELOCATING+ENTRY (_start)}
+
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ ${TEXT_DYNAMIC+${DYNAMIC}}
+ .hash ${RELOCATING-0} : { *(.hash) }
+ .dynsym ${RELOCATING-0} : { *(.dynsym) }
+ .dynstr ${RELOCATING-0} : { *(.dynstr) }
+ .gnu.version ${RELOCATING-0} : { *(.gnu.version) }
+ .gnu.version_d ${RELOCATING-0} : { *(.gnu.version_d) }
+ .gnu.version_r ${RELOCATING-0} : { *(.gnu.version_r) }
+
+ .rel.init ${RELOCATING-0} : { *(.rel.init) }
+ .rela.init ${RELOCATING-0} : { *(.rela.init) }
+ .rel.text ${RELOCATING-0} :
+ {
+ *(.rel.text)
+ ${RELOCATING+*(.rel.text.*)}
+ ${RELOCATING+*(.rel.gnu.linkonce.t*)}
+ }
+ .rela.text ${RELOCATING-0} :
+ {
+ *(.rela.text)
+ ${RELOCATING+*(.rela.text.*)}
+ ${RELOCATING+*(.rela.gnu.linkonce.t*)}
+ }
+ .rel.fini ${RELOCATING-0} : { *(.rel.fini) }
+ .rela.fini ${RELOCATING-0} : { *(.rela.fini) }
+ .rel.rodata ${RELOCATING-0} :
+ {
+ *(.rel.rodata)
+ ${RELOCATING+*(.rel.rodata.*)}
+ ${RELOCATING+*(.rel.gnu.linkonce.r*)}
+ }
+ .rela.rodata ${RELOCATING-0} :
+ {
+ *(.rela.rodata)
+ ${RELOCATING+*(.rela.rodata.*)}
+ ${RELOCATING+*(.rela.gnu.linkonce.r*)}
+ }
+ .rel.data ${RELOCATING-0} :
+ {
+ *(.rel.data)
+ ${RELOCATING+*(.rel.data.*)}
+ ${RELOCATING+*(.rel.gnu.linkonce.d*)}
+ }
+ .rela.data ${RELOCATING-0} :
+ {
+ *(.rela.data)
+ ${RELOCATING+*(.rela.data.*)}
+ ${RELOCATING+*(.rela.gnu.linkonce.d*)}
+ }
+ .rel.ctors ${RELOCATING-0} : { *(.rel.ctors) }
+ .rela.ctors ${RELOCATING-0} : { *(.rela.ctors) }
+ .rel.dtors ${RELOCATING-0} : { *(.rel.dtors) }
+ .rela.dtors ${RELOCATING-0} : { *(.rela.dtors) }
+ .rel.got ${RELOCATING-0} : { *(.rel.got) }
+ .rela.got ${RELOCATING-0} : { *(.rela.got) }
+ .rel.bss ${RELOCATING-0} : { *(.rel.bss) }
+ .rela.bss ${RELOCATING-0} : { *(.rela.bss) }
+ .rel.plt ${RELOCATING-0} : { *(.rel.plt) }
+ .rela.plt ${RELOCATING-0} : { *(.rela.plt) }
+
+ /* Internal text space. */
+ .text ${RELOCATING-0} :
+ {
+ ${RELOCATING+ _text_start = . ; }
+
+ ${RELOCATING+. = ALIGN(4);}
+
+ ${RELOCATING+*(.init0) /* Start here after reset. */}
+ ${RELOCATING+KEEP (*(.init0))}
+
+ ${RELOCATING+. = ALIGN(4);}
+ *(.text)
+ ${RELOCATING+. = ALIGN(4);}
+ ${RELOCATING+*(.text.*)}
+ ${RELOCATING+. = ALIGN(4);}
+ ${RELOCATING+*(.gnu.linkonce.t*)}
+ ${RELOCATING+. = ALIGN(4);}
+
+ ${RELOCATING+ _text_end = . ; }
+ } ${RELOCATING+ > imem}
+
+ .data ${RELOCATING-0} :
+ {
+ /* Optional variable that user is prepared to have NULL address. */
+ ${RELOCATING+ *(.data.atzero*)}
+
+ /* CRT is prepared for constructor/destructor table to have
+ a "valid" NULL address. */
+ ${CONSTRUCTING+ _ctors_start = . ; }
+ ${CONSTRUCTING+ KEEP (*(SORT_BY_INIT_PRIORITY(.ctors.*)))}
+ ${CONSTRUCTING+ KEEP (*(.ctors))}
+ ${CONSTRUCTING+ _ctors_end = . ; }
+ ${CONSTRUCTING+ _dtors_start = . ; }
+ ${CONSTRUCTING+ KEEP (*(SORT_BY_INIT_PRIORITY(.dtors.*)))}
+ ${CONSTRUCTING+ KEEP (*(.dtors))}
+ ${CONSTRUCTING+ _dtors_end = . ; }
+
+ /* DATA memory starts at address 0. So to avoid placing a valid static
+ variable at the invalid NULL address, we introduce the .data.atzero
+ section. If CRT can make some use of it - great. Otherwise skip a
+ word. In all cases .data/.bss sections must start at non-zero. */
+ . += (. == 0 ? 4 : 0);
+
+ ${RELOCATING+ PROVIDE (_data_start = .) ; }
+ *(.data)
+ ${RELOCATING+ *(.data*)}
+ ${RELOCATING+ *(.rodata) /* We need to include .rodata here if gcc is used. */}
+ ${RELOCATING+ *(.rodata.*) /* with -fdata-sections. */}
+ ${RELOCATING+*(.gnu.linkonce.d*)}
+ ${RELOCATING+*(.gnu.linkonce.r*)}
+ ${RELOCATING+. = ALIGN(4);}
+ ${RELOCATING+ PROVIDE (_data_end = .) ; }
+ } ${RELOCATING+ > dmem }
+
+ .resource_table ${RELOCATING-0} :
+ {
+ *(.resource_table)
+ KEEP (*(.resource_table))
+ } > dmem
+
+ .bss ${RELOCATING-0} :
+ {
+ ${RELOCATING+ PROVIDE (_bss_start = .) ; }
+ *(.bss)
+ ${RELOCATING+ *(.bss.*)}
+ ${RELOCATING+*(.gnu.linkonce.b*)}
+ *(COMMON)
+ ${RELOCATING+ PROVIDE (_bss_end = .) ; }
+ } ${RELOCATING+ > dmem}
+
+ /* Global data not cleared after reset. */
+ .noinit ${RELOCATING-0}:
+ {
+ ${RELOCATING+ PROVIDE (_noinit_start = .) ; }
+ *(.noinit)
+ ${RELOCATING+ PROVIDE (_noinit_end = .) ; }
+ ${RELOCATING+ PROVIDE (_heap_start = .) ; }
+ ${RELOCATING+ . += __HEAP_SIZE ; }
+ /* Stack is not here really. It will be put at the end of DMEM.
+ But we take into account its size here, in order to allow
+ for MEMORY overflow checking during link time. */
+ ${RELOCATING+ . += __STACK_SIZE ; }
+ } ${RELOCATING+ > dmem}
+
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+ .note.gnu.build-id : { *(.note.gnu.build-id) }
+EOF
+
+. $srcdir/scripttempl/DWARF.sc
+
+cat <<EOF
+}
+EOF
diff --git a/ld/testsuite/ld-pru/emit-relocs-1.d b/ld/testsuite/ld-pru/emit-relocs-1.d
new file mode 100644
index 0000000000..414234f94d
--- /dev/null
+++ b/ld/testsuite/ld-pru/emit-relocs-1.d
@@ -0,0 +1,37 @@
+#name: Emit relocs 1
+#source: emit-relocs-1a.s
+#source: emit-relocs-1b.s
+#ld: -q -T emit-relocs-1.ld
+#objdump: -sr
+
+.*: file format .*
+
+RELOCATION RECORDS FOR \[\.data\]:
+OFFSET TYPE VALUE *
+00000000 R_PRU_BFD_RELOC32 \.data
+00000004 R_PRU_BFD_RELOC32 \.data\+0x00001000
+00000008 R_PRU_BFD_RELOC32 \.merge1\+0x00000002
+0000000c R_PRU_BFD_RELOC32 \.merge2
+00000010 R_PRU_BFD_RELOC32 \.merge3
+00000014 R_PRU_BFD_RELOC32 \.merge3\+0x00000004
+00000020 R_PRU_BFD_RELOC32 \.data\+0x00000020
+00000024 R_PRU_BFD_RELOC32 \.data\+0x00001020
+00000028 R_PRU_BFD_RELOC32 \.merge1
+0000002c R_PRU_BFD_RELOC32 \.merge2\+0x00000002
+00000030 R_PRU_BFD_RELOC32 \.merge3\+0x00000008
+00000034 R_PRU_BFD_RELOC32 \.merge3\+0x00000004
+
+
+Contents of section \.text:
+ 80000 e0e0e012 00000000 00000000 00000000 .*
+Contents of section \.merge1:
+ 80400 666c7574 74657200 flutter.*
+Contents of section \.merge2:
+ 80800 74617374 696e6700 tasting.*
+Contents of section \.merge3:
+ 80c00 00010000 00020000 00030000 .*
+Contents of section \.data:
+ 81000 00100800 00200800 02040800 00080800 .*
+ 81010 000c0800 040c0800 00000000 00000000 .*
+ 81020 20100800 20200800 00040800 02080800 .*
+ 81030 080c0800 040c0800 .*
diff --git a/ld/testsuite/ld-pru/emit-relocs-1.ld b/ld/testsuite/ld-pru/emit-relocs-1.ld
new file mode 100644
index 0000000000..1879ef4cbe
--- /dev/null
+++ b/ld/testsuite/ld-pru/emit-relocs-1.ld
@@ -0,0 +1,20 @@
+ENTRY(_start)
+SECTIONS
+{
+ . = 0x80000;
+ .text : { *(.text) }
+
+ . = ALIGN (0x400);
+ .merge1 : { *(.merge1) }
+
+ . = ALIGN (0x400);
+ .merge2 : { *(.merge2) }
+
+ . = ALIGN (0x400);
+ .merge3 : { *(.merge3) }
+
+ . = ALIGN (0x400);
+ .data : { *(.data) }
+
+ /DISCARD/ : { *(*) }
+}
diff --git a/ld/testsuite/ld-pru/emit-relocs-1a.s b/ld/testsuite/ld-pru/emit-relocs-1a.s
new file mode 100644
index 0000000000..bf0a8a1689
--- /dev/null
+++ b/ld/testsuite/ld-pru/emit-relocs-1a.s
@@ -0,0 +1,24 @@
+ .text
+ .align 4
+ .globl _start
+_start:
+ nop
+
+ .section .merge1,"aMS",@progbits,1
+A: .string "utter"
+
+ .section .merge2,"aMS",@progbits,1
+B: .string "tasting"
+
+ .section .merge3,"aM",@progbits,4
+C: .4byte 0x100
+D: .4byte 0x200
+
+ .data
+ .align 4
+E: .4byte E
+ .4byte E + 0x1000
+ .4byte A
+ .4byte B
+ .4byte C
+ .4byte D
diff --git a/ld/testsuite/ld-pru/emit-relocs-1b.s b/ld/testsuite/ld-pru/emit-relocs-1b.s
new file mode 100644
index 0000000000..82229c1495
--- /dev/null
+++ b/ld/testsuite/ld-pru/emit-relocs-1b.s
@@ -0,0 +1,18 @@
+ .section .merge1,"aMS",@progbits,1
+A: .string "flutter"
+
+ .section .merge2,"aMS",@progbits,1
+B: .string "sting"
+
+ .section .merge3,"aM",@progbits,4
+C: .4byte 0x300
+D: .4byte 0x200
+
+ .data
+ .align 4
+E: .4byte E
+ .4byte E + 0x1000
+ .4byte A
+ .4byte B
+ .4byte C
+ .4byte D
diff --git a/ld/testsuite/ld-pru/ldi32.d b/ld/testsuite/ld-pru/ldi32.d
new file mode 100644
index 0000000000..123ead310f
--- /dev/null
+++ b/ld/testsuite/ld-pru/ldi32.d
@@ -0,0 +1,12 @@
+#name: PRU R_PRU_LDI32
+#source: ldi32.s
+#source: ldi32_symbol.s
+#ld:
+#objdump: -dr --prefix-addresses
+
+# Test the ldi32 relocation
+.*: +file format elf32-pru
+
+Disassembly of section .text:
+[0-9a-f]+ <[^>]*> ldi r16, 48879
+[0-9a-f]+ <[^>]*> ldi r16.w2, 57005
diff --git a/ld/testsuite/ld-pru/ldi32.s b/ld/testsuite/ld-pru/ldi32.s
new file mode 100644
index 0000000000..629db5a15b
--- /dev/null
+++ b/ld/testsuite/ld-pru/ldi32.s
@@ -0,0 +1,6 @@
+# Test the ldi32 relocation
+
+.text
+.global _start
+_start:
+ ldi32 r16, long_symbol
diff --git a/ld/testsuite/ld-pru/ldi32_symbol.s b/ld/testsuite/ld-pru/ldi32_symbol.s
new file mode 100644
index 0000000000..88fdddccae
--- /dev/null
+++ b/ld/testsuite/ld-pru/ldi32_symbol.s
@@ -0,0 +1,3 @@
+.global long_symbol
+.set long_symbol, 0xDEADBEEF
+
diff --git a/ld/testsuite/ld-pru/norelax_ldi32-data.d b/ld/testsuite/ld-pru/norelax_ldi32-data.d
new file mode 100644
index 0000000000..988e24f067
--- /dev/null
+++ b/ld/testsuite/ld-pru/norelax_ldi32-data.d
@@ -0,0 +1,20 @@
+#name: PRU LDI32 disabled-relaxation data
+#source: relax_ldi32.s
+#source: relax_ldi32_symbol.s
+#as: --mlink-relax
+#ld: --no-relax
+#objdump: -s
+
+# Note: default linker script should put a guard at DRAM address 0
+
+.*: +file format elf32-pru
+
+Contents of section .text:
+ [0-9a-f]+ f0efbe24 d0adde24 0f00f630 f0efbe24 ................
+ [0-9a-f]+ d0adde24 f0cace24 d0000024 e0cace24 ................
+ [0-9a-f]+ f0cace24 d0010024 f0efbe24 d0acde24 ................
+ [0-9a-f]+ f0785624 d0341224 f0785624 d0000024 ................
+ [0-9a-f]+ f0120024 f100007e ........ ........ ................
+Contents of section .data:
+ 0000 00000000 48000020 40000000 12004000 ................
+ 0010 10000000 f0ffffff 100040aa ................
diff --git a/ld/testsuite/ld-pru/norelax_ldi32-dis.d b/ld/testsuite/ld-pru/norelax_ldi32-dis.d
new file mode 100644
index 0000000000..072de5fbd4
--- /dev/null
+++ b/ld/testsuite/ld-pru/norelax_ldi32-dis.d
@@ -0,0 +1,29 @@
+#name: PRU LDI32 disabled-relaxation
+#source: relax_ldi32.s
+#source: relax_ldi32_symbol.s
+#as: --mlink-relax
+#ld: --no-relax
+#objdump: -dr --prefix-addresses
+
+# Test the LDI32 relaxation
+.*: +file format elf32-pru
+
+Disassembly of section .text:
+..000000 <[^>]*> ldi r16, 48879
+..000004 <[^>]*> ldi r16.w2, 57005
+..000008 <[^>]*> loop ..000044 <__end_loop>, r22
+..00000c <[^>]*> ldi r16, 48879
+..000010 <[^>]*> ldi r16.w2, 57005
+..000014 <[^>]*> ldi r16, 52938
+..000018 <[^>]*> ldi r16.w2, 0
+..00001c <[^>]*> ldi r0, 52938
+..000020 <[^>]*> ldi r16, 52938
+..000024 <[^>]*> ldi r16.w2, 1
+..000028 <[^>]*> ldi r16, 48879
+..00002c <[^>]*> ldi r16.w2, 57004
+..000030 <[^>]*> ldi r16, 22136
+..000034 <[^>]*> ldi r16.w2, 4660
+..000038 <[^>]*> ldi r16, 22136
+..00003c <[^>]*> ldi r16.w2, 0
+..000040 <[^>]*> ldi r16, 18
+..000044 <[^>]*> qba ..000008 <__intermediate>
diff --git a/ld/testsuite/ld-pru/pcrel_s10.d b/ld/testsuite/ld-pru/pcrel_s10.d
new file mode 100644
index 0000000000..95602c586b
--- /dev/null
+++ b/ld/testsuite/ld-pru/pcrel_s10.d
@@ -0,0 +1,18 @@
+#name: PRU R_PRU_S10_PCREL
+#source: pcrel_s10.s
+#source: pcrel_s10_label.s
+#ld:
+#objdump: -dr --prefix-addresses
+
+# Test the relative quick branch relocations.
+.*: +file format elf32-pru
+
+Disassembly of section .text:
+[0-9a-f]+ <[^>]*> qba [0-9a-f]+ <ext_label>
+[0-9a-f]+ <[^>]*> qba [0-9a-f]+ <ext_label\+0x10>
+[0-9a-f]+ <[^>]*> nop
+[0-9a-f]+ <[^>]*> nop
+[0-9a-f]+ <[^>]*> nop
+[0-9a-f]+ <[^>]*> nop
+[0-9a-f]+ <[^>]*> nop
+[0-9a-f]+ <[^>]*> nop
diff --git a/ld/testsuite/ld-pru/pcrel_s10.s b/ld/testsuite/ld-pru/pcrel_s10.s
new file mode 100644
index 0000000000..fbec19a584
--- /dev/null
+++ b/ld/testsuite/ld-pru/pcrel_s10.s
@@ -0,0 +1,8 @@
+# Test for pc-relative relocations
+.text
+.section .init0, "x"
+.global _start
+_start:
+ qba ext_label
+ qba ext_label + 16
+
diff --git a/ld/testsuite/ld-pru/pcrel_s10_label.s b/ld/testsuite/ld-pru/pcrel_s10_label.s
new file mode 100644
index 0000000000..3aea34e2ba
--- /dev/null
+++ b/ld/testsuite/ld-pru/pcrel_s10_label.s
@@ -0,0 +1,9 @@
+.text
+ext_label:
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+.global ext_label
diff --git a/ld/testsuite/ld-pru/pcrel_u8-illegal.d b/ld/testsuite/ld-pru/pcrel_u8-illegal.d
new file mode 100644
index 0000000000..a88523747f
--- /dev/null
+++ b/ld/testsuite/ld-pru/pcrel_u8-illegal.d
@@ -0,0 +1,7 @@
+#name: PRU R_PRU_U8_PCREL illegal
+#source: pcrel_u8-illegal.s
+#source: pcrel_u8_label.s
+#ld:
+#error: [^\n]*: relocation truncated to fit: R_PRU_U8_PCREL against `.init0'
+
+# Check that LOOP cannot reference "prior" labels.
diff --git a/ld/testsuite/ld-pru/pcrel_u8-illegal.s b/ld/testsuite/ld-pru/pcrel_u8-illegal.s
new file mode 100644
index 0000000000..f592040abc
--- /dev/null
+++ b/ld/testsuite/ld-pru/pcrel_u8-illegal.s
@@ -0,0 +1,10 @@
+# Test for illegal pc-relative relocations
+.text
+.section .init0, "x"
+.global _start
+_start:
+foo:
+# Negative loop termination point
+ nop
+ loop foo, r20
+
diff --git a/ld/testsuite/ld-pru/pcrel_u8-illegal2.d b/ld/testsuite/ld-pru/pcrel_u8-illegal2.d
new file mode 100644
index 0000000000..604ea9838d
--- /dev/null
+++ b/ld/testsuite/ld-pru/pcrel_u8-illegal2.d
@@ -0,0 +1,7 @@
+#name: PRU R_PRU_U8_PCREL illegal offset 0
+#source: pcrel_u8-illegal2.s
+#source: pcrel_u8_label.s
+#ld:
+#error: [^\n]*: relocation out of range
+
+# Check that LOOP cannot reference "prior" labels.
diff --git a/ld/testsuite/ld-pru/pcrel_u8-illegal2.s b/ld/testsuite/ld-pru/pcrel_u8-illegal2.s
new file mode 100644
index 0000000000..afd40d666d
--- /dev/null
+++ b/ld/testsuite/ld-pru/pcrel_u8-illegal2.s
@@ -0,0 +1,7 @@
+# Test for illegal pc-relative relocations
+.text
+.section .init0, "x"
+.global _start
+_start:
+L0:
+ loop L0, r0
diff --git a/ld/testsuite/ld-pru/pcrel_u8-illegal3.d b/ld/testsuite/ld-pru/pcrel_u8-illegal3.d
new file mode 100644
index 0000000000..604ea9838d
--- /dev/null
+++ b/ld/testsuite/ld-pru/pcrel_u8-illegal3.d
@@ -0,0 +1,7 @@
+#name: PRU R_PRU_U8_PCREL illegal offset 0
+#source: pcrel_u8-illegal2.s
+#source: pcrel_u8_label.s
+#ld:
+#error: [^\n]*: relocation out of range
+
+# Check that LOOP cannot reference "prior" labels.
diff --git a/ld/testsuite/ld-pru/pcrel_u8-illegal3.s b/ld/testsuite/ld-pru/pcrel_u8-illegal3.s
new file mode 100644
index 0000000000..b90131eb7e
--- /dev/null
+++ b/ld/testsuite/ld-pru/pcrel_u8-illegal3.s
@@ -0,0 +1,7 @@
+# Test for illegal pc-relative relocations
+.text
+.section .init0, "x"
+.global _start
+_start:
+ loop L1, r0
+L1:
diff --git a/ld/testsuite/ld-pru/pcrel_u8.d b/ld/testsuite/ld-pru/pcrel_u8.d
new file mode 100644
index 0000000000..60ff05883c
--- /dev/null
+++ b/ld/testsuite/ld-pru/pcrel_u8.d
@@ -0,0 +1,15 @@
+#name: PRU R_PRU_U8_PCREL
+#source: pcrel_u8.s
+#source: pcrel_u8_label.s
+#ld:
+#objdump: -dr --prefix-addresses
+
+# Test the relative quick branch relocations.
+.*: +file format elf32-pru
+
+Disassembly of section .text:
+[0-9a-f]+ <[^>]*> loop [0-9a-f]+ <end_loop>, 5
+[0-9a-f]+ <[^>]*> nop
+[0-9a-f]+ <[^>]*> nop
+[0-9a-f]+ <[^>]*> nop
+[0-9a-f]+ <[^>]*> nop
diff --git a/ld/testsuite/ld-pru/pcrel_u8.s b/ld/testsuite/ld-pru/pcrel_u8.s
new file mode 100644
index 0000000000..c22a216e4e
--- /dev/null
+++ b/ld/testsuite/ld-pru/pcrel_u8.s
@@ -0,0 +1,10 @@
+# Test for pc-relative relocations
+.text
+.section .init0, "x"
+.global _start
+_start:
+ loop end_loop, 5
+ nop
+ nop
+ nop
+
diff --git a/ld/testsuite/ld-pru/pcrel_u8_label.s b/ld/testsuite/ld-pru/pcrel_u8_label.s
new file mode 100644
index 0000000000..b716ce5323
--- /dev/null
+++ b/ld/testsuite/ld-pru/pcrel_u8_label.s
@@ -0,0 +1,4 @@
+.text
+end_loop:
+ nop
+.global end_loop
diff --git a/ld/testsuite/ld-pru/pmem.d b/ld/testsuite/ld-pru/pmem.d
new file mode 100644
index 0000000000..2bb7c16733
--- /dev/null
+++ b/ld/testsuite/ld-pru/pmem.d
@@ -0,0 +1,15 @@
+#name: PRU R_PRU_BFD_*_PMEM
+#source: pmem.s
+#source: pmem_symbol.s
+#ld:
+#objdump: -s
+
+# Note: default linker script should put a guard at DRAM address 0
+
+.*: +file format elf32-pru
+
+Contents of section .text:
+ [0-9a-f]+ e0050024 e0070024 05000000 05000600 ................
+ [0-9a-f]+ e0e0e012 e0e0e012 ........
+Contents of section .data:
+ 0000 00000000 ....
diff --git a/ld/testsuite/ld-pru/pmem.s b/ld/testsuite/ld-pru/pmem.s
new file mode 100644
index 0000000000..8c9f3d4fae
--- /dev/null
+++ b/ld/testsuite/ld-pru/pmem.s
@@ -0,0 +1,15 @@
+# Test for PRU pmem relocations
+
+.global byte_sym
+.global short_sym
+.global long_sym
+
+.set byte_sym, 0xFA
+.set short_sym, 0xFACE
+.set long_sym, 0xDEADBEEF
+
+.text
+.global _text_label
+ nop
+_text_label:
+ nop
diff --git a/ld/testsuite/ld-pru/pmem_symbol.s b/ld/testsuite/ld-pru/pmem_symbol.s
new file mode 100644
index 0000000000..642ca437d5
--- /dev/null
+++ b/ld/testsuite/ld-pru/pmem_symbol.s
@@ -0,0 +1,15 @@
+.text
+.section .init0, "x"
+.global _start
+_start:
+
+ # U16_PMEMIMM
+ ldi r0, %pmem(_text_label)
+ ldi r0, %pmem(_text_label + 8)
+
+# Try 32/16_PMEM
+.4byte %pmem(_text_label)
+.2byte %pmem(_text_label)
+.2byte %pmem(_text_label + 4)
+
+
diff --git a/ld/testsuite/ld-pru/pru.exp b/ld/testsuite/ld-pru/pru.exp
new file mode 100644
index 0000000000..39161e8d42
--- /dev/null
+++ b/ld/testsuite/ld-pru/pru.exp
@@ -0,0 +1,9 @@
+if { ! [istarget pru-*-*] } {
+ return
+}
+
+foreach test [lsort [glob -nocomplain $srcdir/$subdir/*.d]] {
+ verbose [file rootname $test]
+ run_dump_test [file rootname $test]
+}
+
diff --git a/ld/testsuite/ld-pru/relax_ldi32-data.d b/ld/testsuite/ld-pru/relax_ldi32-data.d
new file mode 100644
index 0000000000..c59a105958
--- /dev/null
+++ b/ld/testsuite/ld-pru/relax_ldi32-data.d
@@ -0,0 +1,19 @@
+#name: PRU LDI32 relaxation data
+#source: relax_ldi32.s
+#source: relax_ldi32_symbol.s
+#as: --mlink-relax
+#ld: --relax
+#objdump: -s
+
+# Note: default linker script should put a guard at DRAM address 0
+
+.*: +file format elf32-pru
+
+Contents of section .text:
+ [0-9a-f]+ f0efbe24 d0adde24 0d00f630 f0efbe24 ................
+ [0-9a-f]+ d0adde24 f0cace24 e0cace24 f0cace24 ................
+ [0-9a-f]+ d0010024 f0efbe24 d0acde24 f0785624 ................
+ [0-9a-f]+ d0341224 f0785624 f0100024 f300007e ................
+Contents of section .data:
+ 0000 00000000 40000020 38000000 10003800 ................
+ 0010 0e000000 f2ffffff 0e0038aa ................
diff --git a/ld/testsuite/ld-pru/relax_ldi32-dis.d b/ld/testsuite/ld-pru/relax_ldi32-dis.d
new file mode 100644
index 0000000000..1371f1c644
--- /dev/null
+++ b/ld/testsuite/ld-pru/relax_ldi32-dis.d
@@ -0,0 +1,27 @@
+#name: PRU LDI32 relaxation
+#source: relax_ldi32.s
+#source: relax_ldi32_symbol.s
+#as: --mlink-relax
+#ld: --relax
+#objdump: -dr --prefix-addresses
+
+# Test the LDI32 relaxation
+.*: +file format elf32-pru
+
+Disassembly of section .text:
+..000000 <[^>]*> ldi r16, 48879
+..000004 <[^>]*> ldi r16.w2, 57005
+..000008 <[^>]*> loop ..00003c <__end_loop>, r22
+..00000c <[^>]*> ldi r16, 48879
+..000010 <[^>]*> ldi r16.w2, 57005
+..000014 <[^>]*> ldi r16, 52938
+..000018 <[^>]*> ldi r0, 52938
+..00001c <[^>]*> ldi r16, 52938
+..000020 <[^>]*> ldi r16.w2, 1
+..000024 <[^>]*> ldi r16, 48879
+..000028 <[^>]*> ldi r16.w2, 57004
+..00002c <[^>]*> ldi r16, 22136
+..000030 <[^>]*> ldi r16.w2, 4660
+..000034 <[^>]*> ldi r16, 22136
+..000038 <[^>]*> ldi r16, 16
+..00003c <[^>]*> qba ..000008 <__intermediate>
diff --git a/ld/testsuite/ld-pru/relax_ldi32.s b/ld/testsuite/ld-pru/relax_ldi32.s
new file mode 100644
index 0000000000..7c2473c30c
--- /dev/null
+++ b/ld/testsuite/ld-pru/relax_ldi32.s
@@ -0,0 +1,30 @@
+# Test LDI32 relaxation
+
+.text
+.global _start
+_start:
+ ldi32 r16, long_symbol
+__intermediate:
+ loop __end_loop, r22
+ ldi32 r16, long_symbol
+ ldi32 r16, short_symbol
+ ldi r0, short_symbol
+ ldi32 r16, short_symbol + 0x10000
+ ldi32 r16, long_symbol - 0x10000
+ ldi32 r16, 0x12345678
+ ldi32 r16, 0x5678
+ ldi r16, %pmem(__end)
+__end_loop:
+ qba __intermediate
+__end:
+
+.data
+ .4byte __end
+ .4byte (__end - __intermediate)
+ .2byte %pmem(__end)
+ .2byte (__end - __intermediate)
+ .4byte %pmem(__end - __intermediate)
+ .4byte %pmem(__intermediate - __end)
+ .2byte %pmem(__end - __intermediate)
+ .byte (__end - __intermediate)
+ .byte 0xaa
diff --git a/ld/testsuite/ld-pru/relax_ldi32_symbol.s b/ld/testsuite/ld-pru/relax_ldi32_symbol.s
new file mode 100644
index 0000000000..a34f6e1537
--- /dev/null
+++ b/ld/testsuite/ld-pru/relax_ldi32_symbol.s
@@ -0,0 +1,6 @@
+.global long_symbol
+.global short_symbol
+
+.set long_symbol, 0xDEADBEEF
+.set short_symbol, 0xceca
+
diff --git a/ld/testsuite/ld-pru/reloc.d b/ld/testsuite/ld-pru/reloc.d
new file mode 100644
index 0000000000..a494e0cc4a
--- /dev/null
+++ b/ld/testsuite/ld-pru/reloc.d
@@ -0,0 +1,14 @@
+#name: PRU R_PRU_BFD_RELOC_XX
+#source: reloc.s
+#source: reloc_symbol.s
+#ld:
+#objdump: -s
+
+# Note: default linker script should put a guard at DRAM address 0
+
+.*: +file format elf32-pru
+
+Contents of section .text:
+ [0-9a-f]+ fa00cefa efbeadde facefaef beadde00 ................
+Contents of section .data:
+ 0000 00000000 ....
diff --git a/ld/testsuite/ld-pru/reloc.s b/ld/testsuite/ld-pru/reloc.s
new file mode 100644
index 0000000000..4bf79bfcee
--- /dev/null
+++ b/ld/testsuite/ld-pru/reloc.s
@@ -0,0 +1,9 @@
+# Test for PRU 32-bit, 16 and 8-bit relocations
+
+.global byte_sym
+.global short_sym
+.global long_sym
+
+.set byte_sym, 0xFA
+.set short_sym, 0xFACE
+.set long_sym, 0xDEADBEEF
diff --git a/ld/testsuite/ld-pru/reloc_symbol.s b/ld/testsuite/ld-pru/reloc_symbol.s
new file mode 100644
index 0000000000..a72214c122
--- /dev/null
+++ b/ld/testsuite/ld-pru/reloc_symbol.s
@@ -0,0 +1,25 @@
+.text
+.section .init0, "x"
+.global _start
+_start:
+
+# byte aligned
+.align 0
+.byte byte_sym
+
+# short aligned
+.align 1
+.short short_sym
+
+# word aligned
+.align 2
+.long long_sym
+
+# now lets try some unaligned words and halfwords
+.byte byte_sym
+.2byte short_sym
+.4byte long_sym
+
+#.align 2
+#nop
+
diff --git a/ld/testsuite/ld-pru/u16.d b/ld/testsuite/ld-pru/u16.d
new file mode 100644
index 0000000000..9cc6482f9a
--- /dev/null
+++ b/ld/testsuite/ld-pru/u16.d
@@ -0,0 +1,11 @@
+#name: PRU R_PRU_U16
+#source: u16.s
+#source: u16_symbol.s
+#ld:
+#objdump: -dr --prefix-addresses
+
+# Test the regulard LDI relocation
+.*: +file format elf32-pru
+
+Disassembly of section .text:
+[0-9a-f]+ <[^>]*> ldi r16, 54321
diff --git a/ld/testsuite/ld-pru/u16.s b/ld/testsuite/ld-pru/u16.s
new file mode 100644
index 0000000000..a4c2adeab1
--- /dev/null
+++ b/ld/testsuite/ld-pru/u16.s
@@ -0,0 +1,4 @@
+.text
+.global _start
+_start:
+ ldi r16, short_symbol
diff --git a/ld/testsuite/ld-pru/u16_symbol.s b/ld/testsuite/ld-pru/u16_symbol.s
new file mode 100644
index 0000000000..b4a39c663c
--- /dev/null
+++ b/ld/testsuite/ld-pru/u16_symbol.s
@@ -0,0 +1,3 @@
+.global short_symbol
+.set short_symbol, 54321
+
--
2.11.0
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v2 07/15] ld: testsuite: Mark PRU as elf target that does not support shared libraries
2016-12-27 20:44 [PATCH v2 00/15] Binutils/gas/ld port for PRU Dimitar Dimitrov
` (9 preceding siblings ...)
2016-12-27 20:45 ` [PATCH v2 05/15] PRU Opcode Port Dimitar Dimitrov
@ 2016-12-27 20:45 ` Dimitar Dimitrov
2016-12-27 20:45 ` [PATCH v2 14/15] ld: testsuite: Sanitize output from ld Dimitar Dimitrov
` (4 subsequent siblings)
15 siblings, 0 replies; 19+ messages in thread
From: Dimitar Dimitrov @ 2016-12-27 20:45 UTC (permalink / raw)
To: binutils; +Cc: Dimitar Dimitrov
2016-12-26 Dimitar Dimitrov <dimitar@dinux.eu>
binutils/
* testsuite/lib/binutils-common.exp (is_elf_format): Return
false for PRU.
ld/
* testsuite/ld-elf/eh-frame-hdr.d: Disable for PRU.
* testsuite/ld-elf/sec-to-seg.exp: Disable for PRU.
* testsuite/lib/ld-lib.exp (check_shared_lib_support): No shared
libraries are supported for PRU.
Signed-off-by: Dimitar Dimitrov <dimitar@dinux.eu>
---
ld/testsuite/ld-elf/eh-frame-hdr.d | 2 +-
ld/testsuite/ld-elf/sec-to-seg.exp | 1 +
ld/testsuite/lib/ld-lib.exp | 1 +
3 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/ld/testsuite/ld-elf/eh-frame-hdr.d b/ld/testsuite/ld-elf/eh-frame-hdr.d
index f73d0e51e6..a76ac73866 100644
--- a/ld/testsuite/ld-elf/eh-frame-hdr.d
+++ b/ld/testsuite/ld-elf/eh-frame-hdr.d
@@ -2,7 +2,7 @@
#ld: -e _start --eh-frame-hdr
#objdump: -hw
#target: cfi
-#xfail: avr*-*-* or1k*-*-elf or1k*-*-rtems* visium-*-*
+#xfail: avr*-*-* or1k*-*-elf or1k*-*-rtems* pru-*-* visium-*-*
# These targets support CFI generation but not shared libraries.
#...
[0-9] .eh_frame_hdr 0*[12][048c] .*
diff --git a/ld/testsuite/ld-elf/sec-to-seg.exp b/ld/testsuite/ld-elf/sec-to-seg.exp
index 8847318aa7..af3d604e18 100644
--- a/ld/testsuite/ld-elf/sec-to-seg.exp
+++ b/ld/testsuite/ld-elf/sec-to-seg.exp
@@ -87,6 +87,7 @@ if { [istarget avr-*-*]
|| [istarget moxie-*-*]
|| [istarget msp430-*-*]
|| [istarget mt-*-*]
+ || [istarget pru-*-*]
|| [istarget visium-*-*]
} {
set B_test_same_seg 0
diff --git a/ld/testsuite/lib/ld-lib.exp b/ld/testsuite/lib/ld-lib.exp
index a2be49b25f..74dc998f14 100644
--- a/ld/testsuite/lib/ld-lib.exp
+++ b/ld/testsuite/lib/ld-lib.exp
@@ -1777,6 +1777,7 @@ proc check_shared_lib_support { } {
&& ![istarget nds32*-*-*]
&& ![istarget or1k*-*-*]
&& ![istarget pj-*-*]
+ && ![istarget pru-*-*]
&& ![istarget rl78-*-*]
&& ![istarget rx-*-*]
&& ![istarget spu-*-*]
--
2.11.0
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v2 14/15] ld: testsuite: Sanitize output from ld
2016-12-27 20:44 [PATCH v2 00/15] Binutils/gas/ld port for PRU Dimitar Dimitrov
` (10 preceding siblings ...)
2016-12-27 20:45 ` [PATCH v2 07/15] ld: testsuite: Mark PRU as elf target that does not support shared libraries Dimitar Dimitrov
@ 2016-12-27 20:45 ` Dimitar Dimitrov
2016-12-27 20:45 ` [PATCH v2 10/15] gas: testsuite: Mark lns-common-1-alt variant for PRU Dimitar Dimitrov
` (3 subsequent siblings)
15 siblings, 0 replies; 19+ messages in thread
From: Dimitar Dimitrov @ 2016-12-27 20:45 UTC (permalink / raw)
To: binutils; +Cc: Dimitar Dimitrov
Apparently the leading dashes from an LD error message confuse DejaGnu.
This patch fixes the following DejaGnu error:
--defsym:1: undefined symbol `foo2' referenced in expression
failed with: <--defsym:1: undefined symbol `foo2' referenced in expression>, no expected output
ERROR: tcl error sourcing /home/dinux/projects/misc/binutils-gdb/ld/testsuite/ld-gc/gc.exp.
ERROR: usage: send [args] string
while executing
"send_log "$comp_output\n""
(procedure "run_dump_test" line 376)
invoked from within
"run_dump_test "pr13683""
(file "/home/dinux/projects/misc/binutils-gdb/ld/testsuite/ld-gc/gc.exp" line 136)
invoked from within
"source /home/dinux/projects/misc/binutils-gdb/ld/testsuite/ld-gc/gc.exp"
("uplevel" body line 1)
invoked from within
"uplevel #0 source /home/dinux/projects/misc/binutils-gdb/ld/testsuite/ld-gc/gc.exp"
invoked from within
"catch "uplevel #0 source $test_file_name""
==============
2016-12-26 Dimitar Dimitrov <dimitar@dinux.eu>
ld/
* testsuite/lib/ld-lib.exp (run_dump_test): Sanitize output from
ld.
Signed-off-by: Dimitar Dimitrov <dimitar@dinux.eu>
---
ld/testsuite/lib/ld-lib.exp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/ld/testsuite/lib/ld-lib.exp b/ld/testsuite/lib/ld-lib.exp
index 74dc998f14..30aea19e71 100644
--- a/ld/testsuite/lib/ld-lib.exp
+++ b/ld/testsuite/lib/ld-lib.exp
@@ -857,7 +857,7 @@ proc run_dump_test { name {extra_options {}} } {
remote_file build delete "ld.tmp"
if { [lindex $cmdret 0] != 0 || ![string match "" $comp_output] } then {
- send_log "$comp_output\n"
+ send_log -- "$comp_output\n"
verbose "$comp_output" 3
set exitstat "succeeded"
@@ -880,7 +880,7 @@ proc run_dump_test { name {extra_options {}} } {
if { [lindex $cmdret 0] != 0 \
|| ![string match "" $comp_output] } {
- send_log "$comp_output\n"
+ send_log -- "$comp_output\n"
verbose "$comp_output" 3
set exitstat "succeeded"
@@ -996,7 +996,7 @@ proc run_dump_test { name {extra_options {}} } {
} else {
verbose -log "$exitstat with: <$comp_output>, no expected output"
}
- send_log "$comp_output\n"
+ send_log -- "$comp_output\n"
verbose "$comp_output" 3
if { (($check_ld(source) == "") == ($comp_output == "")) \
--
2.11.0
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v2 06/15] Add PRU ELF ID to elfcpp
2016-12-27 20:44 [PATCH v2 00/15] Binutils/gas/ld port for PRU Dimitar Dimitrov
` (7 preceding siblings ...)
2016-12-27 20:45 ` [PATCH v2 15/15] ld: testsuite: Mark --gc-sections as unsupported " Dimitar Dimitrov
@ 2016-12-27 20:45 ` Dimitar Dimitrov
2016-12-27 23:21 ` Cary Coutant
2016-12-27 20:45 ` [PATCH v2 05/15] PRU Opcode Port Dimitar Dimitrov
` (6 subsequent siblings)
15 siblings, 1 reply; 19+ messages in thread
From: Dimitar Dimitrov @ 2016-12-27 20:45 UTC (permalink / raw)
To: binutils; +Cc: Dimitar Dimitrov
elfcpp/
* elfcpp.h (enum EM): Add EM_TI_PRU.
Signed-off-by: Dimitar Dimitrov <dimitar@dinux.eu>
---
elfcpp/elfcpp.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/elfcpp/elfcpp.h b/elfcpp/elfcpp.h
index 7469bd8fd9..bee73df6f6 100644
--- a/elfcpp/elfcpp.h
+++ b/elfcpp/elfcpp.h
@@ -268,6 +268,7 @@ enum EM
EM_UNICORE = 110,
EM_ALTERA_NIOS2 = 113,
EM_CRX = 114,
+ EM_TI_PRU = 144,
EM_AARCH64 = 183,
EM_TILEGX = 191,
// The Morph MT.
--
2.11.0
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 06/15] Add PRU ELF ID to elfcpp
2016-12-27 20:45 ` [PATCH v2 06/15] Add PRU ELF ID to elfcpp Dimitar Dimitrov
@ 2016-12-27 23:21 ` Cary Coutant
0 siblings, 0 replies; 19+ messages in thread
From: Cary Coutant @ 2016-12-27 23:21 UTC (permalink / raw)
To: Dimitar Dimitrov; +Cc: Binutils
2016-12-27 12:43 GMT-08:00 Dimitar Dimitrov <dimitar@dinux.eu>:
> elfcpp/
>
> * elfcpp.h (enum EM): Add EM_TI_PRU.
This is OK.
-cary
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 00/15] Binutils/gas/ld port for PRU
2016-12-27 20:44 [PATCH v2 00/15] Binutils/gas/ld port for PRU Dimitar Dimitrov
` (14 preceding siblings ...)
2016-12-27 20:45 ` [PATCH v2 11/15] ld: testsuite: PRU assembler does not support diff expressions mixing data and text labels Dimitar Dimitrov
@ 2016-12-30 4:36 ` Alan Modra
2016-12-30 10:09 ` Dimitar Dimitrov
15 siblings, 1 reply; 19+ messages in thread
From: Alan Modra @ 2016-12-30 4:36 UTC (permalink / raw)
To: Dimitar Dimitrov; +Cc: binutils
On Tue, Dec 27, 2016 at 10:43:35PM +0200, Dimitar Dimitrov wrote:
> I hope I have addressed all comments from the initial submission.
This all looks good, with the exception of bfd/cpu-pru.c and
gas/doc/c-pru.texi which need 2016 to be mentioned in their copyright
notices. OK to apply with that fixed. There are a few whitespace
errors too, which can be fixed now or later. Shown by adding
whitespace = indent-with-non-tab,space-before-tab,trailing-space
to your binutils .git/config.
git am ~/Mail/dimitar
Applying: PRU BFD support
.git/rebase-apply/patch:1535: indent with spaces.
Set a regular LDI relocation for the first instruction
warning: 1 line adds whitespace errors.
Applying: PRU Binutils port
Applying: PRU GAS Port
.git/rebase-apply/patch:2893: trailing whitespace.
#
.git/rebase-apply/patch:2898: trailing whitespace.
#
.git/rebase-apply/patch:2901: trailing whitespace.
# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
.git/rebase-apply/patch:2909: trailing whitespace.
.git/rebase-apply/patch:2868: new blank line at EOF.
+
warning: 5 lines add whitespace errors.
Applying: PRU LD Port
.git/rebase-apply/patch:692: indent with spaces.
nop
.git/rebase-apply/patch:693: indent with spaces.
loop foo, r20
.git/rebase-apply/patch:812: trailing whitespace.
[0-9a-f]+ e0e0e012 e0e0e012 ........
.git/rebase-apply/patch:814: trailing whitespace.
0000 00000000 ....
.git/rebase-apply/patch:864: trailing whitespace.
return
warning: squelched 10 whitespace errors
warning: 15 lines add whitespace errors.
Applying: PRU Opcode Port
.git/rebase-apply/patch:146: indent with spaces.
instruction. */
.git/rebase-apply/patch:571: indent with spaces.
disassemble_info *info)
.git/rebase-apply/patch:603: indent with spaces.
can reuse some code. */
warning: 3 lines add whitespace errors.
Some of these of course can't be fixed. Testcase .d files and similar
must match the tool output.
--
Alan Modra
Australia Development Lab, IBM
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 00/15] Binutils/gas/ld port for PRU
2016-12-30 4:36 ` [PATCH v2 00/15] Binutils/gas/ld port for PRU Alan Modra
@ 2016-12-30 10:09 ` Dimitar Dimitrov
0 siblings, 0 replies; 19+ messages in thread
From: Dimitar Dimitrov @ 2016-12-30 10:09 UTC (permalink / raw)
To: binutils; +Cc: Alan Modra
On петък, 30 декември 2016 г. 15:05:47 EET Alan Modra wrote:
> On Tue, Dec 27, 2016 at 10:43:35PM +0200, Dimitar Dimitrov wrote:
> > I hope I have addressed all comments from the initial submission.
>
> This all looks good, with the exception of bfd/cpu-pru.c and
> gas/doc/c-pru.texi which need 2016 to be mentioned in their copyright
> notices. OK to apply with that fixed. There are a few whitespace
> errors too, which can be fixed now or later. Shown by adding
> whitespace = indent-with-non-tab,space-before-tab,trailing-space
> to your binutils .git/config.
I'll fix and resend. Thanks for the review.
^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2016-12-30 10:09 UTC | newest]
Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-12-27 20:44 [PATCH v2 00/15] Binutils/gas/ld port for PRU Dimitar Dimitrov
2016-12-27 20:44 ` [PATCH v2 03/15] PRU GAS Port Dimitar Dimitrov
2016-12-27 20:44 ` [PATCH v2 13/15] ld: testsuite: Disable endsym test case Dimitar Dimitrov
2016-12-27 20:44 ` [PATCH v2 02/15] PRU Binutils port Dimitar Dimitrov
2016-12-27 20:44 ` [PATCH v2 01/15] PRU BFD support Dimitar Dimitrov
2016-12-27 20:44 ` [PATCH v2 09/15] ld: testsuite: Fix srec test setup for PRU Dimitar Dimitrov
2016-12-27 20:45 ` [PATCH v2 12/15] ld: testsuite: PRU LD does not support arbitrary .text base addresses Dimitar Dimitrov
2016-12-27 20:45 ` [PATCH v2 08/15] ld: testsuite: Mark sec64k case as too big for PRU Dimitar Dimitrov
2016-12-27 20:45 ` [PATCH v2 15/15] ld: testsuite: Mark --gc-sections as unsupported " Dimitar Dimitrov
2016-12-27 20:45 ` [PATCH v2 06/15] Add PRU ELF ID to elfcpp Dimitar Dimitrov
2016-12-27 23:21 ` Cary Coutant
2016-12-27 20:45 ` [PATCH v2 05/15] PRU Opcode Port Dimitar Dimitrov
2016-12-27 20:45 ` [PATCH v2 07/15] ld: testsuite: Mark PRU as elf target that does not support shared libraries Dimitar Dimitrov
2016-12-27 20:45 ` [PATCH v2 14/15] ld: testsuite: Sanitize output from ld Dimitar Dimitrov
2016-12-27 20:45 ` [PATCH v2 10/15] gas: testsuite: Mark lns-common-1-alt variant for PRU Dimitar Dimitrov
2016-12-27 20:45 ` [PATCH v2 04/15] PRU LD Port Dimitar Dimitrov
2016-12-27 20:45 ` [PATCH v2 11/15] ld: testsuite: PRU assembler does not support diff expressions mixing data and text labels Dimitar Dimitrov
2016-12-30 4:36 ` [PATCH v2 00/15] Binutils/gas/ld port for PRU Alan Modra
2016-12-30 10:09 ` Dimitar Dimitrov
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).