summaryrefslogtreecommitdiffstats
path: root/bfd
diff options
context:
space:
mode:
Diffstat (limited to 'bfd')
-rw-r--r--bfd/ChangeLog30
-rw-r--r--bfd/Makefile.am20
-rw-r--r--bfd/Makefile.in24
-rw-r--r--bfd/archures.c4
-rw-r--r--bfd/bfd-in2.h34
-rw-r--r--bfd/config.bfd6
-rwxr-xr-xbfd/configure30
-rw-r--r--bfd/configure.in2
-rw-r--r--bfd/cpu-xtensa.c38
-rw-r--r--bfd/elf32-xtensa.c5846
-rw-r--r--bfd/libbfd.h10
-rw-r--r--bfd/reloc.c43
-rw-r--r--bfd/targets.c4
-rw-r--r--bfd/xtensa-isa.c593
-rw-r--r--bfd/xtensa-modules.c6090
15 files changed, 12754 insertions, 20 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 8ea9e6e14b..0ce8c01b1c 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,33 @@
+2003-04-01 Bob Wilson <bob.wilson@acm.org>
+
+ * Makefile.am (ALL_MACHINES): Add cpu-xtensa.lo.
+ (ALL_MACHINES_CFILES): Add cpu-xtensa.c.
+ (BFD32_BACKENDS): Add elf32-xtensa.lo, xtensa-isa.lo, and
+ xtensa-modules.lo.
+ (BFD32_BACKENDS_CFILES): Add elf32-xtensa.c, xtensa-isa.c, and
+ xtensa-modules.c.
+ (cpu-xtensa.lo): New target.
+ (elf32-xtensa.lo): Likewise.
+ (xtensa-isa.lo): Likewise.
+ (xtensa-modules.lo): Likewise.
+ * Makefile.in: Regenerate.
+ * archures.c (bfd_architecture): Add bfd_{arch,mach}_xtensa.
+ (bfd_archures_list): Add bfd_xtensa_arch.
+ * config.bfd: Handle xtensa-*-*.
+ * configure.in: Handle bfd_elf32_xtensa_{le,be}_vec.
+ * configure: Regenerate.
+ * reloc.c: Add BFD_RELOC_XTENSA_{RTLD,GLOB_DAT,JMP_SLOT,RELATIVE,
+ PLT,OP0,OP1,OP2,ASM_EXPAND,ASM_SIMPLIFY}.
+ * targets.c (bfd_elf32_xtensa_be_vec): Declare.
+ (bfd_elf32_xtensa_le_vec): Likewise.
+ (bfd_target_vector): Add bfd_elf32_xtensa_{be,le}_vec.
+ * cpu-xtensa.c: New file.
+ * elf32-xtensa.c: Likewise.
+ * xtensa-isa.c: Likewise.
+ * xtensa-modules.c: Likewise.
+ * libbfd.h: Regenerate.
+ * bfd-in2.h: Likewise.
+
2003-04-01 Nick Clifton <nickc@redhat.com>
* archures.c (bfd_mach_arm_unknown): Define.
diff --git a/bfd/Makefile.am b/bfd/Makefile.am
index 401568fa7d..ee04261549 100644
--- a/bfd/Makefile.am
+++ b/bfd/Makefile.am
@@ -101,6 +101,7 @@ ALL_MACHINES = \
cpu-we32k.lo \
cpu-w65.lo \
cpu-xstormy16.lo \
+ cpu-xtensa.lo \
cpu-z8k.lo
ALL_MACHINES_CFILES = \
@@ -155,6 +156,7 @@ ALL_MACHINES_CFILES = \
cpu-we32k.c \
cpu-w65.c \
cpu-xstormy16.c \
+ cpu-xtensa.c \
cpu-z8k.c
# The .o files needed by all of the 32 bit vectors that are configured into
@@ -249,6 +251,7 @@ BFD32_BACKENDS = \
elf32-v850.lo \
elf32-vax.lo \
elf32-xstormy16.lo \
+ elf32-xtensa.lo \
elf32.lo \
elflink.lo \
elf-strtab.lo \
@@ -317,7 +320,9 @@ BFD32_BACKENDS = \
vms-misc.lo \
vms-tir.lo \
xcofflink.lo \
- xsym.lo
+ xsym.lo \
+ xtensa-isa.lo \
+ xtensa-modules.lo
BFD32_BACKENDS_CFILES = \
aout-adobe.c \
@@ -408,6 +413,7 @@ BFD32_BACKENDS_CFILES = \
elf32-v850.c \
elf32-vax.c \
elf32-xstormy16.c \
+ elf32-xtensa.c \
elf32.c \
elflink.c \
elf-strtab.c \
@@ -475,7 +481,9 @@ BFD32_BACKENDS_CFILES = \
vms-misc.c \
vms-tir.c \
xcofflink.c \
- xsym.c
+ xsym.c \
+ xtensa-isa.c \
+ xtensa-modules.c
# The .o files needed by all of the 64 bit vectors that are configured into
# target_vector in targets.c if configured with --enable-targets=all
@@ -957,6 +965,7 @@ cpu-vax.lo: cpu-vax.c $(INCDIR)/filenames.h
cpu-we32k.lo: cpu-we32k.c $(INCDIR)/filenames.h
cpu-w65.lo: cpu-w65.c $(INCDIR)/filenames.h
cpu-xstormy16.lo: cpu-xstormy16.c $(INCDIR)/filenames.h
+cpu-xtensa.lo: cpu-xtensa.c $(INCDIR)/filenames.h
cpu-z8k.lo: cpu-z8k.c $(INCDIR)/filenames.h
aout-adobe.lo: aout-adobe.c $(INCDIR)/filenames.h $(INCDIR)/aout/adobe.h \
$(INCDIR)/aout/stab_gnu.h $(INCDIR)/aout/stab.def libaout.h \
@@ -1286,6 +1295,9 @@ elf32-xstormy16.lo: elf32-xstormy16.c $(INCDIR)/filenames.h \
$(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(INCDIR)/elf/xstormy16.h \
$(INCDIR)/elf/reloc-macros.h $(INCDIR)/libiberty.h \
elf32-target.h
+elf32-xtensa.lo: elf32-xtensa.c $(INCDIR)/bfdlink.h elf-bfd.h \
+ $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \
+ $(INCDIR)/elf/xtensa.h $(INCDIR)/xtensa-isa.h elf32-target.h
elf32.lo: elf32.c elfcode.h $(INCDIR)/filenames.h $(INCDIR)/libiberty.h \
$(INCDIR)/bfdlink.h elf-bfd.h $(INCDIR)/elf/common.h \
$(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h elfcore.h \
@@ -1490,6 +1502,10 @@ xcofflink.lo: xcofflink.c $(INCDIR)/filenames.h $(INCDIR)/bfdlink.h \
$(INCDIR)/coff/internal.h $(INCDIR)/coff/xcoff.h libcoff.h \
libxcoff.h
xsym.lo: xsym.c xsym.h $(INCDIR)/filenames.h
+xtensa-isa.lo: xtensa-isa.c $(INCDIR)/xtensa-isa.h \
+ $(INCDIR)/xtensa-isa-internal.h
+xtensa-modules.lo: xtensa-modules.c $(INCDIR)/xtensa-isa.h \
+ $(INCDIR)/xtensa-isa-internal.h
aix5ppc-core.lo: aix5ppc-core.c
aout64.lo: aout64.c aoutx.h $(INCDIR)/filenames.h $(INCDIR)/safe-ctype.h \
$(INCDIR)/bfdlink.h libaout.h $(INCDIR)/aout/aout64.h \
diff --git a/bfd/Makefile.in b/bfd/Makefile.in
index a05b3423e7..3de6121d8e 100644
--- a/bfd/Makefile.in
+++ b/bfd/Makefile.in
@@ -1,4 +1,4 @@
-# Makefile.in generated automatically by automake 1.4-p6 from Makefile.am
+# Makefile.in generated automatically by automake 1.4-p5 from Makefile.am
# Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
@@ -226,6 +226,7 @@ ALL_MACHINES = \
cpu-we32k.lo \
cpu-w65.lo \
cpu-xstormy16.lo \
+ cpu-xtensa.lo \
cpu-z8k.lo
@@ -281,6 +282,7 @@ ALL_MACHINES_CFILES = \
cpu-we32k.c \
cpu-w65.c \
cpu-xstormy16.c \
+ cpu-xtensa.c \
cpu-z8k.c
@@ -376,6 +378,7 @@ BFD32_BACKENDS = \
elf32-v850.lo \
elf32-vax.lo \
elf32-xstormy16.lo \
+ elf32-xtensa.lo \
elf32.lo \
elflink.lo \
elf-strtab.lo \
@@ -444,7 +447,9 @@ BFD32_BACKENDS = \
vms-misc.lo \
vms-tir.lo \
xcofflink.lo \
- xsym.lo
+ xsym.lo \
+ xtensa-isa.lo \
+ xtensa-modules.lo
BFD32_BACKENDS_CFILES = \
@@ -536,6 +541,7 @@ BFD32_BACKENDS_CFILES = \
elf32-v850.c \
elf32-vax.c \
elf32-xstormy16.c \
+ elf32-xtensa.c \
elf32.c \
elflink.c \
elf-strtab.c \
@@ -603,7 +609,9 @@ BFD32_BACKENDS_CFILES = \
vms-misc.c \
vms-tir.c \
xcofflink.c \
- xsym.c
+ xsym.c \
+ xtensa-isa.c \
+ xtensa-modules.c
# The .o files needed by all of the 64 bit vectors that are configured into
@@ -799,7 +807,7 @@ configure.in version.h
DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
-TAR = tar
+TAR = gtar
GZIP_ENV = --best
SOURCES = $(libbfd_a_SOURCES) $(libbfd_la_SOURCES)
OBJECTS = $(libbfd_a_OBJECTS) $(libbfd_la_OBJECTS)
@@ -1490,6 +1498,7 @@ cpu-vax.lo: cpu-vax.c $(INCDIR)/filenames.h
cpu-we32k.lo: cpu-we32k.c $(INCDIR)/filenames.h
cpu-w65.lo: cpu-w65.c $(INCDIR)/filenames.h
cpu-xstormy16.lo: cpu-xstormy16.c $(INCDIR)/filenames.h
+cpu-xtensa.lo: cpu-xtensa.c $(INCDIR)/filenames.h
cpu-z8k.lo: cpu-z8k.c $(INCDIR)/filenames.h
aout-adobe.lo: aout-adobe.c $(INCDIR)/filenames.h $(INCDIR)/aout/adobe.h \
$(INCDIR)/aout/stab_gnu.h $(INCDIR)/aout/stab.def libaout.h \
@@ -1819,6 +1828,9 @@ elf32-xstormy16.lo: elf32-xstormy16.c $(INCDIR)/filenames.h \
$(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h $(INCDIR)/elf/xstormy16.h \
$(INCDIR)/elf/reloc-macros.h $(INCDIR)/libiberty.h \
elf32-target.h
+elf32-xtensa.lo: elf32-xtensa.c $(INCDIR)/bfdlink.h elf-bfd.h \
+ $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \
+ $(INCDIR)/elf/xtensa.h $(INCDIR)/xtensa-isa.h elf32-target.h
elf32.lo: elf32.c elfcode.h $(INCDIR)/filenames.h $(INCDIR)/libiberty.h \
$(INCDIR)/bfdlink.h elf-bfd.h $(INCDIR)/elf/common.h \
$(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h elfcore.h \
@@ -2023,6 +2035,10 @@ xcofflink.lo: xcofflink.c $(INCDIR)/filenames.h $(INCDIR)/bfdlink.h \
$(INCDIR)/coff/internal.h $(INCDIR)/coff/xcoff.h libcoff.h \
libxcoff.h
xsym.lo: xsym.c xsym.h $(INCDIR)/filenames.h
+xtensa-isa.lo: xtensa-isa.c $(INCDIR)/xtensa-isa.h \
+ $(INCDIR)/xtensa-isa-internal.h
+xtensa-modules.lo: xtensa-modules.c $(INCDIR)/xtensa-isa.h \
+ $(INCDIR)/xtensa-isa-internal.h
aix5ppc-core.lo: aix5ppc-core.c
aout64.lo: aout64.c aoutx.h $(INCDIR)/filenames.h $(INCDIR)/safe-ctype.h \
$(INCDIR)/bfdlink.h libaout.h $(INCDIR)/aout/aout64.h \
diff --git a/bfd/archures.c b/bfd/archures.c
index 28e27dffe7..9337fb1927 100644
--- a/bfd/archures.c
+++ b/bfd/archures.c
@@ -308,6 +308,8 @@ DESCRIPTION
.#define bfd_mach_msp44 44
.#define bfd_mach_msp15 15
.#define bfd_mach_msp16 16
+. bfd_arch_xtensa, {* Tensilica's Xtensa cores. *}
+.#define bfd_mach_xtensa 1
. bfd_arch_last
. };
*/
@@ -399,6 +401,7 @@ extern const bfd_arch_info_type bfd_vax_arch;
extern const bfd_arch_info_type bfd_we32k_arch;
extern const bfd_arch_info_type bfd_w65_arch;
extern const bfd_arch_info_type bfd_xstormy16_arch;
+extern const bfd_arch_info_type bfd_xtensa_arch;
extern const bfd_arch_info_type bfd_z8k_arch;
static const bfd_arch_info_type * const bfd_archures_list[] =
@@ -456,6 +459,7 @@ static const bfd_arch_info_type * const bfd_archures_list[] =
&bfd_w65_arch,
&bfd_we32k_arch,
&bfd_xstormy16_arch,
+ &bfd_xtensa_arch,
&bfd_z8k_arch,
#endif
0
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index d15bcda823..a5ff0c0599 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -1774,6 +1774,8 @@ enum bfd_architecture
#define bfd_mach_msp44 44
#define bfd_mach_msp15 15
#define bfd_mach_msp16 16
+ bfd_arch_xtensa, /* Tensilica's Xtensa cores. */
+#define bfd_mach_xtensa 1
bfd_arch_last
};
@@ -3437,6 +3439,38 @@ to follow the 16K memory bank of 68HC12 (seen as mapped in the window). */
BFD_RELOC_IQ2000_OFFSET_16,
BFD_RELOC_IQ2000_OFFSET_21,
BFD_RELOC_IQ2000_UHI16,
+
+/* Special Xtensa relocation used only by PLT entries in ELF shared
+objects to indicate that the runtime linker should set the value
+to one of its own internal functions or data structures. */
+ BFD_RELOC_XTENSA_RTLD,
+
+/* Xtensa relocations for ELF shared objects. */
+ BFD_RELOC_XTENSA_GLOB_DAT,
+ BFD_RELOC_XTENSA_JMP_SLOT,
+ BFD_RELOC_XTENSA_RELATIVE,
+
+/* Xtensa relocation used in ELF object files for symbols that may require
+PLT entries. Otherwise, this is just a generic 32-bit relocation. */
+ BFD_RELOC_XTENSA_PLT,
+
+/* Generic Xtensa relocations. Only the operand number is encoded
+in the relocation. The details are determined by extracting the
+instruction opcode. */
+ BFD_RELOC_XTENSA_OP0,
+ BFD_RELOC_XTENSA_OP1,
+ BFD_RELOC_XTENSA_OP2,
+
+/* Xtensa relocation to mark that the assembler expanded the
+instructions from an original target. The expansion size is
+encoded in the reloc size. */
+ BFD_RELOC_XTENSA_ASM_EXPAND,
+
+/* Xtensa relocation to mark that the linker should simplify
+assembler-expanded instructions. This is commonly used
+internally by the linker after analysis of a
+BFD_RELOC_XTENSA_ASM_EXPAND. */
+ BFD_RELOC_XTENSA_ASM_SIMPLIFY,
BFD_RELOC_UNUSED };
typedef enum bfd_reloc_code_real bfd_reloc_code_real_type;
reloc_howto_type *
diff --git a/bfd/config.bfd b/bfd/config.bfd
index c678496dbd..d034ce8e9e 100644
--- a/bfd/config.bfd
+++ b/bfd/config.bfd
@@ -58,6 +58,7 @@ thumb*) targ_archs=bfd_arm_arch ;;
v850*) targ_archs=bfd_v850_arch ;;
x86_64) targ_archs=bfd_i386_arch ;;
xscale*) targ_archs=bfd_arm_arch ;;
+xtensa*) targ_archs=bfd_xtensa_arch ;;
z8k*) targ_archs=bfd_z8k_arch ;;
*) targ_archs=bfd_${targ_cpu}_arch ;;
esac
@@ -1214,6 +1215,11 @@ case "${targ}" in
targ_defvec=bfd_elf32_xstormy16_vec
;;
+ xtensa-*-*)
+ targ_defvec=bfd_elf32_xtensa_le_vec
+ targ_selvecs=bfd_elf32_xtensa_be_vec
+ ;;
+
z8k*-*-*)
targ_defvec=z8kcoff_vec
targ_underscore=yes
diff --git a/bfd/configure b/bfd/configure
index 6616dc01b3..ad1475dc32 100755
--- a/bfd/configure
+++ b/bfd/configure
@@ -6155,6 +6155,8 @@ do
bfd_elf32_v850_vec) tb="$tb elf32-v850.lo elf32.lo $elf" ;;
bfd_elf32_vax_vec) tb="$tb elf32-vax.lo elf32.lo $elf" ;;
bfd_elf32_xstormy16_vec) tb="$tb elf32-xstormy16.lo elf32.lo $elf" ;;
+ bfd_elf32_xtensa_le_vec) tb="$tb xtensa-isa.lo xtensa-modules.lo elf32-xtensa.lo elf32.lo $elf" ;;
+ bfd_elf32_xtensa_be_vec) tb="$tb xtensa-isa.lo xtensa-modules.lo elf32-xtensa.lo elf32.lo $elf" ;;
bfd_elf64_alpha_freebsd_vec) tb="$tb elf64-alpha.lo elf64.lo $elf"; target_size=64 ;;
bfd_elf64_alpha_vec) tb="$tb elf64-alpha.lo elf64.lo $elf"; target_size=64 ;;
bfd_elf64_big_generic_vec) tb="$tb elf64-gen.lo elf64.lo $elf"; target_size=64 ;;
@@ -6372,10 +6374,10 @@ case ${host64}-${target64}-${want64} in
if test -n "$GCC" ; then
bad_64bit_gcc=no;
echo $ac_n "checking for gcc version with buggy 64-bit support""... $ac_c" 1>&6
-echo "configure:6376: checking for gcc version with buggy 64-bit support" >&5
+echo "configure:6378: checking for gcc version with buggy 64-bit support" >&5
# Add more tests for gcc versions with non-working 64-bit support here.
cat > conftest.$ac_ext <<EOF
-#line 6379 "configure"
+#line 6381 "configure"
#include "confdefs.h"
:__GNUC__:__GNUC_MINOR__:__i386__:
EOF
@@ -6421,17 +6423,17 @@ for ac_hdr in unistd.h
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:6425: checking for $ac_hdr" >&5
+echo "configure:6427: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 6430 "configure"
+#line 6432 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:6435: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:6437: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
@@ -6460,12 +6462,12 @@ done
for ac_func in getpagesize
do
echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:6464: checking for $ac_func" >&5
+echo "configure:6466: checking for $ac_func" >&5
if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 6469 "configure"
+#line 6471 "configure"
#include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char $ac_func(); below. */
@@ -6488,7 +6490,7 @@ $ac_func();
; return 0; }
EOF
-if { (eval echo configure:6492: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:6494: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_func_$ac_func=yes"
else
@@ -6513,7 +6515,7 @@ fi
done
echo $ac_n "checking for working mmap""... $ac_c" 1>&6
-echo "configure:6517: checking for working mmap" >&5
+echo "configure:6519: checking for working mmap" >&5
if eval "test \"`echo '$''{'ac_cv_func_mmap_fixed_mapped'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -6521,7 +6523,7 @@ else
ac_cv_func_mmap_fixed_mapped=no
else
cat > conftest.$ac_ext <<EOF
-#line 6525 "configure"
+#line 6527 "configure"
#include "confdefs.h"
/* Thanks to Mike Haertel and Jim Avera for this test.
@@ -6661,7 +6663,7 @@ main()
}
EOF
-if { (eval echo configure:6665: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:6667: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
then
ac_cv_func_mmap_fixed_mapped=yes
else
@@ -6686,12 +6688,12 @@ fi
for ac_func in madvise mprotect
do
echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:6690: checking for $ac_func" >&5
+echo "configure:6692: checking for $ac_func" >&5
if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 6695 "configure"
+#line 6697 "configure"
#include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char $ac_func(); below. */
@@ -6714,7 +6716,7 @@ $ac_func();
; return 0; }
EOF
-if { (eval echo configure:6718: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:6720: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_func_$ac_func=yes"
else
diff --git a/bfd/configure.in b/bfd/configure.in
index ddb5e8b287..347ad97c1e 100644
--- a/bfd/configure.in
+++ b/bfd/configure.in
@@ -639,6 +639,8 @@ do
bfd_elf32_v850_vec) tb="$tb elf32-v850.lo elf32.lo $elf" ;;
bfd_elf32_vax_vec) tb="$tb elf32-vax.lo elf32.lo $elf" ;;
bfd_elf32_xstormy16_vec) tb="$tb elf32-xstormy16.lo elf32.lo $elf" ;;
+ bfd_elf32_xtensa_le_vec) tb="$tb xtensa-isa.lo xtensa-modules.lo elf32-xtensa.lo elf32.lo $elf" ;;
+ bfd_elf32_xtensa_be_vec) tb="$tb xtensa-isa.lo xtensa-modules.lo elf32-xtensa.lo elf32.lo $elf" ;;
bfd_elf64_alpha_freebsd_vec) tb="$tb elf64-alpha.lo elf64.lo $elf"; target_size=64 ;;
bfd_elf64_alpha_vec) tb="$tb elf64-alpha.lo elf64.lo $elf"; target_size=64 ;;
bfd_elf64_big_generic_vec) tb="$tb elf64-gen.lo elf64.lo $elf"; target_size=64 ;;
diff --git a/bfd/cpu-xtensa.c b/bfd/cpu-xtensa.c
new file mode 100644
index 0000000000..fbfff64b61
--- /dev/null
+++ b/bfd/cpu-xtensa.c
@@ -0,0 +1,38 @@
+/* BFD support for the Xtensa processor.
+ Copyright 2003 Free Software Foundation, Inc.
+
+ 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 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+
+const bfd_arch_info_type bfd_xtensa_arch =
+{
+ 32, /* Bits per word. */
+ 32, /* Bits per address. */
+ 8, /* Bits per byte. */
+ bfd_arch_xtensa, /* Architecture. */
+ bfd_mach_xtensa, /* Machine. */
+ "xtensa", /* Architecture name. */
+ "xtensa", /* Printable name. */
+ 4, /* Section align power. */
+ TRUE, /* The default? */
+ bfd_default_compatible, /* Architecture comparison fn. */
+ bfd_default_scan, /* String to architecture convert fn. */
+ NULL /* Next in list. */
+};
diff --git a/bfd/elf32-xtensa.c b/bfd/elf32-xtensa.c
new file mode 100644
index 0000000000..92fb98c772
--- /dev/null
+++ b/bfd/elf32-xtensa.c
@@ -0,0 +1,5846 @@
+/* Xtensa-specific support for 32-bit ELF.
+ Copyright 2003 Free Software Foundation, Inc.
+
+ 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 2 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., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA. */
+
+#include "bfd.h"
+#include "sysdep.h"
+
+#ifdef ANSI_PROTOTYPES
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include <strings.h>
+
+#include "bfdlink.h"
+#include "libbfd.h"
+#include "elf-bfd.h"
+#include "elf/xtensa.h"
+#include "xtensa-isa.h"
+#include "xtensa-config.h"
+
+/* Main interface functions. */
+static void elf_xtensa_info_to_howto_rela
+ PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
+static reloc_howto_type *elf_xtensa_reloc_type_lookup
+ PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
+extern int xtensa_read_table_entries
+ PARAMS ((bfd *, asection *, property_table_entry **, const char *));
+static bfd_boolean elf_xtensa_check_relocs
+ PARAMS ((bfd *, struct bfd_link_info *, asection *,
+ const Elf_Internal_Rela *));
+static void elf_xtensa_hide_symbol
+ PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *, bfd_boolean));
+static void elf_xtensa_copy_indirect_symbol
+ PARAMS ((struct elf_backend_data *, struct elf_link_hash_entry *,
+ struct elf_link_hash_entry *));
+static asection *elf_xtensa_gc_mark_hook
+ PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *,
+ struct elf_link_hash_entry *, Elf_Internal_Sym *));
+static bfd_boolean elf_xtensa_gc_sweep_hook
+ PARAMS ((bfd *, struct bfd_link_info *, asection *,
+ const Elf_Internal_Rela *));
+static bfd_boolean elf_xtensa_create_dynamic_sections
+ PARAMS ((bfd *, struct bfd_link_info *));
+static bfd_boolean elf_xtensa_adjust_dynamic_symbol
+ PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
+static bfd_boolean elf_xtensa_size_dynamic_sections
+ PARAMS ((bfd *, struct bfd_link_info *));
+static bfd_boolean elf_xtensa_modify_segment_map
+ PARAMS ((bfd *));
+static bfd_boolean elf_xtensa_relocate_section
+ PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
+ Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
+static bfd_boolean elf_xtensa_relax_section
+ PARAMS ((bfd *, asection *, struct bfd_link_info *, bfd_boolean *again));
+static bfd_boolean elf_xtensa_finish_dynamic_symbol
+ PARAMS ((bfd *, struct bfd_link_info *, struct elf_link_hash_entry *,
+ Elf_Internal_Sym *));
+static bfd_boolean elf_xtensa_finish_dynamic_sections
+ PARAMS ((bfd *, struct bfd_link_info *));
+static bfd_boolean elf_xtensa_merge_private_bfd_data
+ PARAMS ((bfd *, bfd *));
+static bfd_boolean elf_xtensa_set_private_flags
+ PARAMS ((bfd *, flagword));
+extern flagword elf_xtensa_get_private_bfd_flags
+ PARAMS ((bfd *));
+static bfd_boolean elf_xtensa_print_private_bfd_data
+ PARAMS ((bfd *, PTR));
+static bfd_boolean elf_xtensa_object_p
+ PARAMS ((bfd *));
+static void elf_xtensa_final_write_processing
+ PARAMS ((bfd *, bfd_boolean));
+static enum elf_reloc_type_class elf_xtensa_reloc_type_class
+ PARAMS ((const Elf_Internal_Rela *));
+static bfd_boolean elf_xtensa_discard_info
+ PARAMS ((bfd *, struct elf_reloc_cookie *, struct bfd_link_info *));
+static bfd_boolean elf_xtensa_ignore_discarded_relocs
+ PARAMS ((asection *));
+static bfd_boolean elf_xtensa_grok_prstatus
+ PARAMS ((bfd *, Elf_Internal_Note *));
+static bfd_boolean elf_xtensa_grok_psinfo
+ PARAMS ((bfd *, Elf_Internal_Note *));
+static bfd_boolean elf_xtensa_new_section_hook
+ PARAMS ((bfd *, asection *));
+
+
+/* Local helper functions. */
+
+static int property_table_compare
+ PARAMS ((const PTR, const PTR));
+static bfd_boolean elf_xtensa_in_literal_pool
+ PARAMS ((property_table_entry *, int, bfd_vma));
+static void elf_xtensa_make_sym_local
+ PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
+static bfd_boolean add_extra_plt_sections
+ PARAMS ((bfd *, int));
+static bfd_boolean elf_xtensa_fix_refcounts
+ PARAMS ((struct elf_link_hash_entry *, PTR));
+static bfd_boolean elf_xtensa_allocate_plt_size
+ PARAMS ((struct elf_link_hash_entry *, PTR));
+static bfd_boolean elf_xtensa_allocate_got_size
+ PARAMS ((struct elf_link_hash_entry *, PTR));
+static void elf_xtensa_allocate_local_got_size
+ PARAMS ((struct bfd_link_info *, asection *));
+static bfd_reloc_status_type elf_xtensa_do_reloc
+ PARAMS ((reloc_howto_type *, bfd *, asection *, bfd_vma, bfd_byte *,
+ bfd_vma, bfd_boolean, char **));
+static char * vsprint_msg
+ VPARAMS ((const char *, const char *, int, ...));
+static char *build_encoding_error_message
+ PARAMS ((xtensa_opcode, xtensa_encode_result));
+static bfd_reloc_status_type bfd_elf_xtensa_reloc
+ PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+static void do_fix_for_relocateable_link
+ PARAMS ((Elf_Internal_Rela *, bfd *, asection *));
+static void do_fix_for_final_link
+ PARAMS ((Elf_Internal_Rela *, asection *, bfd_vma *));
+static bfd_boolean xtensa_elf_dynamic_symbol_p
+ PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
+static bfd_vma elf_xtensa_create_plt_entry
+ PARAMS ((bfd *, bfd *, unsigned));
+static int elf_xtensa_combine_prop_entries
+ PARAMS ((bfd *, const char *));
+static bfd_boolean elf_xtensa_discard_info_for_section
+ PARAMS ((bfd *, struct elf_reloc_cookie *, struct bfd_link_info *,
+ asection *));
+
+/* Local functions to handle Xtensa configurability. */
+
+static void init_call_opcodes
+ PARAMS ((void));
+static bfd_boolean is_indirect_call_opcode
+ PARAMS ((xtensa_opcode));
+static bfd_boolean is_direct_call_opcode
+ PARAMS ((xtensa_opcode));
+static bfd_boolean is_windowed_call_opcode
+ PARAMS ((xtensa_opcode));
+static xtensa_opcode get_l32r_opcode
+ PARAMS ((void));
+static bfd_vma l32r_offset
+ PARAMS ((bfd_vma, bfd_vma));
+static int get_relocation_opnd
+ PARAMS ((Elf_Internal_Rela *));
+static xtensa_opcode get_relocation_opcode
+ PARAMS ((asection *, bfd_byte *, Elf_Internal_Rela *));
+static bfd_boolean is_l32r_relocation
+ PARAMS ((asection *, bfd_byte *, Elf_Internal_Rela *));
+
+/* Functions for link-time code simplifications. */
+
+static bfd_reloc_status_type elf_xtensa_do_asm_simplify
+ PARAMS ((bfd_byte *, bfd_vma, bfd_vma));
+static bfd_reloc_status_type contract_asm_expansion
+ PARAMS ((bfd_byte *, bfd_vma, Elf_Internal_Rela *));
+static xtensa_opcode swap_callx_for_call_opcode
+ PARAMS ((xtensa_opcode));
+static xtensa_opcode get_expanded_call_opcode
+ PARAMS ((bfd_byte *, int));
+
+/* Access to internal relocations, section contents and symbols. */
+
+static Elf_Internal_Rela *retrieve_internal_relocs
+ PARAMS ((bfd *, asection *, bfd_boolean));
+static void pin_internal_relocs
+ PARAMS ((asection *, Elf_Internal_Rela *));
+static void release_internal_relocs
+ PARAMS ((asection *, Elf_Internal_Rela *));
+static bfd_byte *retrieve_contents
+ PARAMS ((bfd *, asection *, bfd_boolean));
+static void pin_contents
+ PARAMS ((asection *, bfd_byte *));
+static void release_contents
+ PARAMS ((asection *, bfd_byte *));
+static Elf_Internal_Sym *retrieve_local_syms
+ PARAMS ((bfd *));
+
+/* Miscellaneous utility functions. */
+
+static asection *elf_xtensa_get_plt_section
+ PARAMS ((bfd *, int));
+static asection *elf_xtensa_get_gotplt_section
+ PARAMS ((bfd *, int));
+static asection *get_elf_r_symndx_section
+ PARAMS ((bfd *, unsigned long));
+static struct elf_link_hash_entry *get_elf_r_symndx_hash_entry
+ PARAMS ((bfd *, unsigned long));
+static bfd_vma get_elf_r_symndx_offset
+ PARAMS ((bfd *, unsigned long));
+static bfd_boolean pcrel_reloc_fits
+ PARAMS ((xtensa_operand, bfd_vma, bfd_vma));
+static bfd_boolean xtensa_is_property_section
+ PARAMS ((asection *));
+static bfd_boolean is_literal_section
+ PARAMS ((asection *));
+static int internal_reloc_compare
+ PARAMS ((const PTR, const PTR));
+static bfd_boolean get_is_linkonce_section
+ PARAMS ((bfd *, asection *));
+extern char *xtensa_get_property_section_name
+ PARAMS ((bfd *, asection *, const char *));
+
+/* Other functions called directly by the linker. */
+
+typedef void (*deps_callback_t)
+ PARAMS ((asection *, bfd_vma, asection *, bfd_vma, PTR));
+extern bfd_boolean xtensa_callback_required_dependence
+ PARAMS ((bfd *, asection *, struct bfd_link_info *,
+ deps_callback_t, PTR));
+
+
+typedef struct xtensa_relax_info_struct xtensa_relax_info;
+
+
+/* Total count of PLT relocations seen during check_relocs.
+ The actual PLT code must be split into multiple sections and all
+ the sections have to be created before size_dynamic_sections,
+ where we figure out the exact number of PLT entries that will be
+ needed. It is OK is this count is an overestimate, e.g., some
+ relocations may be removed by GC. */
+
+static int plt_reloc_count = 0;
+
+
+/* When this is true, relocations may have been modified to refer to
+ symbols from other input files. The per-section list of "fix"
+ records needs to be checked when resolving relocations. */
+
+static bfd_boolean relaxing_section = FALSE;
+
+
+static reloc_howto_type elf_howto_table[] =
+{
+ HOWTO (R_XTENSA_NONE, 0, 0, 0, FALSE, 0, complain_overflow_dont,
+ bfd_elf_xtensa_reloc, "R_XTENSA_NONE",
+ FALSE, 0x00000000, 0x00000000, FALSE),
+ HOWTO (R_XTENSA_32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
+ bfd_elf_xtensa_reloc, "R_XTENSA_32",
+ TRUE, 0xffffffff, 0xffffffff, FALSE),
+ /* Replace a 32-bit value with a value from the runtime linker (only
+ used by linker-generated stub functions). The r_addend value is
+ special: 1 means to substitute a pointer to the runtime linker's
+ dynamic resolver function; 2 means to substitute the link map for
+ the shared object. */
+ HOWTO (R_XTENSA_RTLD, 0, 2, 32, FALSE, 0, complain_overflow_dont,
+ NULL, "R_XTENSA_RTLD",
+ FALSE, 0x00000000, 0x00000000, FALSE),
+ HOWTO (R_XTENSA_GLOB_DAT, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
+ bfd_elf_generic_reloc, "R_XTENSA_GLOB_DAT",
+ FALSE, 0xffffffff, 0xffffffff, FALSE),
+ HOWTO (R_XTENSA_JMP_SLOT, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
+ bfd_elf_generic_reloc, "R_XTENSA_JMP_SLOT",
+ FALSE, 0xffffffff, 0xffffffff, FALSE),
+ HOWTO (R_XTENSA_RELATIVE, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
+ bfd_elf_generic_reloc, "R_XTENSA_RELATIVE",
+ FALSE, 0xffffffff, 0xffffffff, FALSE),
+ HOWTO (R_XTENSA_PLT, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
+ bfd_elf_xtensa_reloc, "R_XTENSA_PLT",
+ FALSE, 0xffffffff, 0xffffffff, FALSE),
+ EMPTY_HOWTO (7),
+ HOWTO (R_XTENSA_OP0, 0, 0, 0, TRUE, 0, complain_overflow_dont,
+ bfd_elf_xtensa_reloc, "R_XTENSA_OP0",
+ FALSE, 0x00000000, 0x00000000, TRUE),
+ HOWTO (R_XTENSA_OP1, 0, 0, 0, TRUE, 0, complain_overflow_dont,
+ bfd_elf_xtensa_reloc, "R_XTENSA_OP1",
+ FALSE, 0x00000000, 0x00000000, TRUE),
+ HOWTO (R_XTENSA_OP2, 0, 0, 0, TRUE, 0, complain_overflow_dont,
+ bfd_elf_xtensa_reloc, "R_XTENSA_OP2",
+ FALSE, 0x00000000, 0x00000000, TRUE),
+ /* Assembly auto-expansion. */
+ HOWTO (R_XTENSA_ASM_EXPAND, 0, 0, 0, TRUE, 0, complain_overflow_dont,
+ bfd_elf_xtensa_reloc, "R_XTENSA_ASM_EXPAND",
+ FALSE, 0x00000000, 0x00000000, FALSE),
+ /* Relax assembly auto-expansion. */
+ HOWTO (R_XTENSA_ASM_SIMPLIFY, 0, 0, 0, TRUE, 0, complain_overflow_dont,
+ bfd_elf_xtensa_reloc, "R_XTENSA_ASM_SIMPLIFY",
+ FALSE, 0x00000000, 0x00000000, TRUE),
+ EMPTY_HOWTO (13),
+ EMPTY_HOWTO (14),
+ /* GNU extension to record C++ vtable hierarchy. */
+ HOWTO (R_XTENSA_GNU_VTINHERIT, 0, 2, 0, FALSE, 0, complain_overflow_dont,
+ NULL, "R_XTENSA_GNU_VTINHERIT",
+ FALSE, 0x00000000, 0x00000000, FALSE),
+ /* GNU extension to record C++ vtable member usage. */
+ HOWTO (R_XTENSA_GNU_VTENTRY, 0, 2, 0, FALSE, 0, complain_overflow_dont,
+ _bfd_elf_rel_vtable_reloc_fn, "R_XTENSA_GNU_VTENTRY",
+ FALSE, 0x00000000, 0x00000000, FALSE)
+};
+
+#ifdef DEBUG_GEN_RELOC
+#define TRACE(str) \
+ fprintf (stderr, "Xtensa bfd reloc lookup %d (%s)\n", code, str)
+#else
+#define TRACE(str)
+#endif
+
+static reloc_howto_type *
+elf_xtensa_reloc_type_lookup (abfd, code)
+ bfd *abfd ATTRIBUTE_UNUSED;
+ bfd_reloc_code_real_type code;
+{
+ switch (code)
+ {
+ case BFD_RELOC_NONE:
+ TRACE ("BFD_RELOC_NONE");
+ return &elf_howto_table[(unsigned) R_XTENSA_NONE ];
+
+ case BFD_RELOC_32:
+ TRACE ("BFD_RELOC_32");
+ return &elf_howto_table[(unsigned) R_XTENSA_32 ];
+
+ case BFD_RELOC_XTENSA_RTLD:
+ TRACE ("BFD_RELOC_XTENSA_RTLD");
+ return &elf_howto_table[(unsigned) R_XTENSA_RTLD ];
+
+ case BFD_RELOC_XTENSA_GLOB_DAT:
+ TRACE ("BFD_RELOC_XTENSA_GLOB_DAT");
+ return &elf_howto_table[(unsigned) R_XTENSA_GLOB_DAT ];
+
+ case BFD_RELOC_XTENSA_JMP_SLOT:
+ TRACE ("BFD_RELOC_XTENSA_JMP_SLOT");
+ return &elf_howto_table[(unsigned) R_XTENSA_JMP_SLOT ];
+
+ case BFD_RELOC_XTENSA_RELATIVE:
+ TRACE ("BFD_RELOC_XTENSA_RELATIVE");
+ return &elf_howto_table[(unsigned) R_XTENSA_RELATIVE ];
+
+ case BFD_RELOC_XTENSA_PLT:
+ TRACE ("BFD_RELOC_XTENSA_PLT");
+ return &elf_howto_table[(unsigned) R_XTENSA_PLT ];
+
+ case BFD_RELOC_XTENSA_OP0:
+ TRACE ("BFD_RELOC_XTENSA_OP0");
+ return &elf_howto_table[(unsigned) R_XTENSA_OP0 ];
+
+ case BFD_RELOC_XTENSA_OP1:
+ TRACE ("BFD_RELOC_XTENSA_OP1");
+ return &elf_howto_table[(unsigned) R_XTENSA_OP1 ];
+
+ case BFD_RELOC_XTENSA_OP2:
+ TRACE ("BFD_RELOC_XTENSA_OP2");
+ return &elf_howto_table[(unsigned) R_XTENSA_OP2 ];
+
+ case BFD_RELOC_XTENSA_ASM_EXPAND:
+ TRACE ("BFD_RELOC_XTENSA_ASM_EXPAND");
+ return &elf_howto_table[(unsigned) R_XTENSA_ASM_EXPAND ];
+
+ case BFD_RELOC_XTENSA_ASM_SIMPLIFY:
+ TRACE ("BFD_RELOC_XTENSA_ASM_SIMPLIFY");
+ return &elf_howto_table[(unsigned) R_XTENSA_ASM_SIMPLIFY ];
+
+ case BFD_RELOC_VTABLE_INHERIT:
+ TRACE ("BFD_RELOC_VTABLE_INHERIT");
+ return &elf_howto_table[(unsigned) R_XTENSA_GNU_VTINHERIT ];
+
+ case BFD_RELOC_VTABLE_ENTRY:
+ TRACE ("BFD_RELOC_VTABLE_ENTRY");
+ return &elf_howto_table[(unsigned) R_XTENSA_GNU_VTENTRY ];
+
+ default:
+ break;
+ }
+
+ TRACE ("Unknown");
+ return NULL;
+}
+
+
+/* Given an ELF "rela" relocation, find the corresponding howto and record
+ it in the BFD internal arelent representation of the relocation. */
+
+static void
+elf_xtensa_info_to_howto_rela (abfd, cache_ptr, dst)
+ bfd *abfd ATTRIBUTE_UNUSED;
+ arelent *cache_ptr;
+ Elf_Internal_Rela *dst;
+{
+ unsigned int r_type = ELF32_R_TYPE (dst->r_info);
+
+ BFD_ASSERT (r_type < (unsigned int) R_XTENSA_max);
+ cache_ptr->howto = &elf_howto_table[r_type];
+}
+
+
+/* Functions for the Xtensa ELF linker. */
+
+/* The name of the dynamic interpreter. This is put in the .interp
+ section. */
+
+#define ELF_DYNAMIC_INTERPRETER "/lib/ld.so"
+
+/* The size in bytes of an entry in the procedure linkage table.
+ (This does _not_ include the space for the literals associated with
+ the PLT entry.) */
+
+#define PLT_ENTRY_SIZE 16
+
+/* For _really_ large PLTs, we may need to alternate between literals
+ and code to keep the literals within the 256K range of the L32R
+ instructions in the code. It's unlikely that anyone would ever need
+ such a big PLT, but an arbitrary limit on the PLT size would be bad.
+ Thus, we split the PLT into chunks. Since there's very little
+ overhead (2 extra literals) for each chunk, the chunk size is kept
+ small so that the code for handling multiple chunks get used and
+ tested regularly. With 254 entries, there are 1K of literals for
+ each chunk, and that seems like a nice round number. */
+
+#define PLT_ENTRIES_PER_CHUNK 254
+
+/* PLT entries are actually used as stub functions for lazy symbol
+ resolution. Once the symbol is resolved, the stub function is never
+ invoked. Note: the 32-byte frame size used here cannot be changed
+ without a corresponding change in the runtime linker. */
+
+static const bfd_byte elf_xtensa_be_plt_entry[PLT_ENTRY_SIZE] =
+{
+ 0x6c, 0x10, 0x04, /* entry sp, 32 */
+ 0x18, 0x00, 0x00, /* l32r a8, [got entry for rtld's resolver] */
+ 0x1a, 0x00, 0x00, /* l32r a10, [got entry for rtld's link map] */
+ 0x1b, 0x00, 0x00, /* l32r a11, [literal for reloc index] */
+ 0x0a, 0x80, 0x00, /* jx a8 */
+ 0 /* unused */
+};
+
+static const bfd_byte elf_xtensa_le_plt_entry[PLT_ENTRY_SIZE] =
+{
+ 0x36, 0x41, 0x00, /* entry sp, 32 */
+ 0x81, 0x00, 0x00, /* l32r a8, [got entry for rtld's resolver] */
+ 0xa1, 0x00, 0x00, /* l32r a10, [got entry for rtld's link map] */
+ 0xb1, 0x00, 0x00, /* l32r a11, [literal for reloc index] */
+ 0xa0, 0x08, 0x00, /* jx a8 */
+ 0 /* unused */
+};
+
+
+static int
+property_table_compare (ap, bp)
+ const PTR ap;
+ const PTR bp;
+{
+ const property_table_entry *a = (const property_table_entry *) ap;
+ const property_table_entry *b = (const property_table_entry *) bp;
+
+ /* Check if one entry overlaps with the other; this shouldn't happen
+ except when searching for a match. */
+ if ((b->address >= a->address && b->address < (a->address + a->size))
+ || (a->address >= b->address && a->address < (b->address + b->size)))
+ return 0;
+
+ return (a->address - b->address);
+}
+
+
+/* Get the literal table or instruction table entries for the given
+ section. Sets TABLE_P and returns the number of entries. On error,
+ returns a negative value. */
+
+int
+xtensa_read_table_entries (abfd, section, table_p, sec_name)
+ bfd *abfd;
+ asection *section;
+ property_table_entry **table_p;
+ const char *sec_name;
+{
+ asection *table_section;
+ char *table_section_name;
+ bfd_size_type table_size = 0;
+ bfd_byte *table_data;
+ property_table_entry *blocks;
+ int block_count;
+ bfd_size_type num_records;
+ Elf_Internal_Rela *internal_relocs;
+
+ table_section_name =
+ xtensa_get_property_section_name (abfd, section, sec_name);
+ table_section = bfd_get_section_by_name (abfd, table_section_name);
+ if (table_section != NULL)
+ table_size = bfd_get_section_size_before_reloc (table_section);
+
+ if (table_size == 0)
+ {
+ *table_p = NULL;
+ return 0;
+ }
+
+ num_records = table_size / sizeof (property_table_entry);
+ table_data = retrieve_contents (abfd, table_section, TRUE);
+ blocks = (property_table_entry *)
+ bfd_malloc (num_records * sizeof (property_table_entry));
+ block_count = 0;
+
+ /* If the file has not yet been relocated, process the relocations
+ and sort out the table entries that apply to the specified section. */
+ internal_relocs = retrieve_internal_relocs (abfd, table_section, TRUE);
+ if (internal_relocs)
+ {
+ unsigned i;
+
+ for (i = 0; i < table_section->reloc_count; i++)
+ {
+ Elf_Internal_Rela *rel = &internal_relocs[i];
+ unsigned long r_symndx;
+
+ if (ELF32_R_TYPE (rel->r_info) == R_XTENSA_NONE)
+ continue;
+
+ BFD_ASSERT (ELF32_R_TYPE (rel->r_info) == R_XTENSA_32);
+ r_symndx = ELF32_R_SYM (rel->r_info);
+
+ if (get_elf_r_symndx_section (abfd, r_symndx) == section)
+ {
+ bfd_vma sym_off = get_elf_r_symndx_offset (abfd, r_symndx);
+ blocks[block_count].address =
+ (section->vma + sym_off + rel->r_addend
+ + bfd_get_32 (abfd, table_data + rel->r_offset));
+ blocks[block_count].size =
+ bfd_get_32 (abfd, table_data + rel->r_offset + 4);
+ block_count++;
+ }
+ }
+ }
+ else
+ {
+ /* No relocations. Presumably the file has been relocated
+ and the addresses are already in the table. */
+ bfd_vma off;
+
+ for (off = 0; off < table_size; off += sizeof (property_table_entry))
+ {
+ bfd_vma address = bfd_get_32 (abfd, table_data + off);
+
+ if (address >= section->vma
+ && address < ( section->vma + section->_raw_size))
+ {
+ blocks[block_count].address = address;
+ blocks[block_count].size =
+ bfd_get_32 (abfd, table_data + off + 4);
+ block_count++;
+ }
+ }
+ }
+
+ release_contents (table_section, table_data);
+ release_internal_relocs (table_section, internal_relocs);
+
+ if (block_count > 0)
+ {
+ /* Now sort them into address order for easy reference. */
+ qsort (blocks, block_count, sizeof (property_table_entry),
+ property_table_compare);
+ }
+
+ *table_p = blocks;
+ return block_count;
+}
+
+
+static bfd_boolean
+elf_xtensa_in_literal_pool (lit_table, lit_table_size, addr)
+ property_table_entry *lit_table;
+ int lit_table_size;
+ bfd_vma addr;
+{
+ property_table_entry entry;
+
+ if (lit_table_size == 0)
+ return FALSE;
+
+ entry.address = addr;
+ entry.size = 1;
+
+ if (bsearch (&entry, lit_table, lit_table_size,
+ sizeof (property_table_entry), property_table_compare))
+ return TRUE;
+
+ return FALSE;
+}
+
+
+/* Look through the relocs for a section during the first phase, and
+ calculate needed space in the dynamic reloc sections. */
+
+static bfd_boolean
+elf_xtensa_check_relocs (abfd, info, sec, relocs)
+ bfd *abfd;
+ struct bfd_link_info *info;
+ asection *sec;
+ const Elf_Internal_Rela *relocs;
+{
+ Elf_Internal_Shdr *symtab_hdr;
+ struct elf_link_hash_entry **sym_hashes;
+ const Elf_Internal_Rela *rel;
+ const Elf_Internal_Rela *rel_end;
+ property_table_entry *lit_table;
+ int ltblsize;
+
+ if (info->relocateable)
+ return TRUE;
+
+ symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ sym_hashes = elf_sym_hashes (abfd);
+
+ ltblsize = xtensa_read_table_entries (abfd, sec, &lit_table,
+ XTENSA_LIT_SEC_NAME);
+ if (ltblsize < 0)
+ return FALSE;
+
+ rel_end = relocs + sec->reloc_count;
+ for (rel = relocs; rel < rel_end; rel++)
+ {
+ unsigned int r_type;
+ unsigned long r_symndx;
+ struct elf_link_hash_entry *h;
+
+ r_symndx = ELF32_R_SYM (rel->r_info);
+ r_type = ELF32_R_TYPE (rel->r_info);
+
+ if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr))
+ {
+ (*_bfd_error_handler) (_("%s: bad symbol index: %d"),
+ bfd_archive_filename (abfd),
+ r_symndx);
+ return FALSE;
+ }
+
+ if (r_symndx < symtab_hdr->sh_info)
+ h = NULL;
+ else
+ {
+ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+ while (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ }
+
+ switch (r_type)
+ {
+ case R_XTENSA_32:
+ if (h == NULL)
+ goto local_literal;
+
+ if ((sec->flags & SEC_ALLOC) != 0)
+ {
+ if ((sec->flags & SEC_READONLY) != 0
+ && !elf_xtensa_in_literal_pool (lit_table, ltblsize,
+ sec->vma + rel->r_offset))
+ h->elf_link_hash_flags |= ELF_LINK_NON_GOT_REF;
+
+ if (h->got.refcount <= 0)
+ h->got.refcount = 1;
+ else
+ h->got.refcount += 1;
+ }
+ break;
+
+ case R_XTENSA_PLT:
+ /* If this relocation is against a local symbol, then it's
+ exactly the same as a normal local GOT entry. */
+ if (h == NULL)
+ goto local_literal;
+
+ if ((sec->flags & SEC_ALLOC) != 0)
+ {
+ if ((sec->flags & SEC_READONLY) != 0
+ && !elf_xtensa_in_literal_pool (lit_table, ltblsize,
+ sec->vma + rel->r_offset))
+ h->elf_link_hash_flags |= ELF_LINK_NON_GOT_REF;
+
+ if (h->plt.refcount <= 0)
+ {
+ h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
+ h->plt.refcount = 1;
+ }
+ else
+ h->plt.refcount += 1;
+
+ /* Keep track of the total PLT relocation count even if we
+ don't yet know whether the dynamic sections will be
+ created. */
+ plt_reloc_count += 1;
+
+ if (elf_hash_table (info)->dynamic_sections_created)
+ {
+ if (!add_extra_plt_sections (elf_hash_table (info)->dynobj,
+ plt_reloc_count))
+ return FALSE;
+ }
+ }
+ break;
+
+ local_literal:
+ if ((sec->flags & SEC_ALLOC) != 0)
+ {
+ bfd_signed_vma *local_got_refcounts;
+
+ /* This is a global offset table entry for a local symbol. */
+ local_got_refcounts = elf_local_got_refcounts (abfd);
+ if (local_got_refcounts == NULL)
+ {
+ bfd_size_type size;
+
+ size = symtab_hdr->sh_info;
+ size *= sizeof (bfd_signed_vma);
+ local_got_refcounts = ((bfd_signed_vma *)
+ bfd_zalloc (abfd, size));
+ if (local_got_refcounts == NULL)
+ return FALSE;
+ elf_local_got_refcounts (abfd) = local_got_refcounts;
+ }
+ local_got_refcounts[r_symndx] += 1;
+
+ /* If the relocation is not inside the GOT, the DF_TEXTREL
+ flag needs to be set. */
+ if (info->shared
+ && (sec->flags & SEC_READONLY) != 0
+ && !elf_xtensa_in_literal_pool (lit_table, ltblsize,
+ sec->vma + rel->r_offset))
+ info->flags |= DF_TEXTREL;
+ }
+ break;
+
+ case R_XTENSA_OP0:
+ case R_XTENSA_OP1:
+ case R_XTENSA_OP2:
+ case R_XTENSA_ASM_EXPAND:
+ case R_XTENSA_ASM_SIMPLIFY:
+ /* Nothing to do for these. */
+ break;
+
+ case R_XTENSA_GNU_VTINHERIT:
+ /* This relocation describes the C++ object vtable hierarchy.
+ Reconstruct it for later use during GC. */
+ if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
+ return FALSE;
+ break;
+
+ case R_XTENSA_GNU_VTENTRY:
+ /* This relocation describes which C++ vtable entries are actually
+ used. Record for later use during GC. */
+ if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_addend))
+ return FALSE;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ free (lit_table);
+ return TRUE;
+}
+
+
+static void
+elf_xtensa_hide_symbol (info, h, force_local)
+ struct bfd_link_info *info;
+ struct elf_link_hash_entry *h;
+ bfd_boolean force_local;
+{
+ /* For a shared link, move the plt refcount to the got refcount to leave
+ space for RELATIVE relocs. */
+ elf_xtensa_make_sym_local (info, h);
+
+ _bfd_elf_link_hash_hide_symbol (info, h, force_local);
+}
+
+
+static void
+elf_xtensa_copy_indirect_symbol (bed, dir, ind)
+ struct elf_backend_data *bed;
+ struct elf_link_hash_entry *dir, *ind;
+{
+ _bfd_elf_link_hash_copy_indirect (bed, dir, ind);
+
+ /* The standard function doesn't copy the NEEDS_PLT flag. */
+ dir->elf_link_hash_flags |=
+ (ind->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT);
+}
+
+
+/* Return the section that should be marked against GC for a given
+ relocation. */
+
+static asection *
+elf_xtensa_gc_mark_hook (sec, info, rel, h, sym)
+ asection *sec;
+ struct bfd_link_info *info ATTRIBUTE_UNUSED;
+ Elf_Internal_Rela *rel;
+ struct elf_link_hash_entry *h;
+ Elf_Internal_Sym *sym;
+{
+ if (h != NULL)
+ {
+ switch (ELF32_R_TYPE (rel->r_info))
+ {
+ case R_XTENSA_GNU_VTINHERIT:
+ case R_XTENSA_GNU_VTENTRY:
+ break;
+
+ default:
+ switch (h->root.type)
+ {
+ case bfd_link_hash_defined:
+ case bfd_link_hash_defweak:
+ return h->root.u.def.section;
+
+ case bfd_link_hash_common:
+ return h->root.u.c.p->section;
+
+ default:
+ break;
+ }
+ }
+ }
+ else
+ return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
+
+ return NULL;
+}
+
+/* Update the GOT & PLT entry reference counts
+ for the section being removed. */
+
+static bfd_boolean
+elf_xtensa_gc_sweep_hook (abfd, info, sec, relocs)
+ bfd *abfd;
+ struct bfd_link_info *info ATTRIBUTE_UNUSED;
+ asection *sec;
+ const Elf_Internal_Rela *relocs;
+{
+ Elf_Internal_Shdr *symtab_hdr;
+ struct elf_link_hash_entry **sym_hashes;
+ bfd_signed_vma *local_got_refcounts;
+ const Elf_Internal_Rela *rel, *relend;
+
+ if ((sec->flags & SEC_ALLOC) == 0)
+ return TRUE;
+
+ symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ sym_hashes = elf_sym_hashes (abfd);
+ local_got_refcounts = elf_local_got_refcounts (abfd);
+
+ relend = relocs + sec->reloc_count;
+ for (rel = relocs; rel < relend; rel++)
+ {
+ unsigned long r_symndx;
+ unsigned int r_type;
+ struct elf_link_hash_entry *h = NULL;
+
+ r_symndx = ELF32_R_SYM (rel->r_info);
+ if (r_symndx >= symtab_hdr->sh_info)
+ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+
+ r_type = ELF32_R_TYPE (rel->r_info);
+ switch (r_type)
+ {
+ case R_XTENSA_32:
+ if (h == NULL)
+ goto local_literal;
+ if (h->got.refcount > 0)
+ h->got.refcount--;
+ break;
+
+ case R_XTENSA_PLT:
+ if (h == NULL)
+ goto local_literal;
+ if (h->plt.refcount > 0)
+ h->plt.refcount--;
+ break;
+
+ local_literal:
+ if (local_got_refcounts[r_symndx] > 0)
+ local_got_refcounts[r_symndx] -= 1;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return TRUE;
+}
+
+
+/* Create all the dynamic sections. */
+
+static bfd_boolean
+elf_xtensa_create_dynamic_sections (dynobj, info)
+ bfd *dynobj;
+ struct bfd_link_info *info;
+{
+ flagword flags;
+ asection *s;
+
+ /* First do all the standard stuff. */
+ if (! _bfd_elf_create_dynamic_sections (dynobj, info))
+ return FALSE;
+
+ /* Create any extra PLT sections in case check_relocs has already
+ been called on all the non-dynamic input files. */
+ if (!add_extra_plt_sections (dynobj, plt_reloc_count))
+ return FALSE;
+
+ flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED | SEC_READONLY);
+
+ /* Mark the ".got.plt" section READONLY. */
+ s = bfd_get_section_by_name (dynobj, ".got.plt");
+ if (s == NULL
+ || ! bfd_set_section_flags (dynobj, s, flags))
+ return FALSE;
+
+ /* Create ".rela.got". */
+ s = bfd_make_section (dynobj, ".rela.got");
+ if (s == NULL
+ || ! bfd_set_section_flags (dynobj, s, flags)
+ || ! bfd_set_section_alignment (dynobj, s, 2))
+ return FALSE;
+
+ /* Create ".xt.lit.plt" (literal table for ".got.plt*"). */
+ s = bfd_make_section (dynobj, ".xt.lit.plt");
+ if (s == NULL
+ || ! bfd_set_section_flags (dynobj, s, flags)
+ || ! bfd_set_section_alignment (dynobj, s, 2))
+ return FALSE;
+
+ return TRUE;
+}
+
+
+static bfd_boolean
+add_extra_plt_sections (dynobj, count)
+ bfd *dynobj;
+ int count;
+{
+ int chunk;
+
+ /* Iterate over all chunks except 0 which uses the standard ".plt" and
+ ".got.plt" sections. */
+ for (chunk = count / PLT_ENTRIES_PER_CHUNK; chunk > 0; chunk--)
+ {
+ char *sname;
+ flagword flags;
+ asection *s;
+
+ /* Stop when we find a section has already been created. */
+ if (elf_xtensa_get_plt_section (dynobj, chunk))
+ break;
+
+ flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED | SEC_READONLY);
+
+ sname = (char *) bfd_malloc (10);
+ sprintf (sname, ".plt.%u", chunk);
+ s = bfd_make_section (dynobj, sname);
+ if (s == NULL
+ || ! bfd_set_section_flags (dynobj, s, flags | SEC_CODE)
+ || ! bfd_set_section_alignment (dynobj, s, 2))
+ return FALSE;
+
+ sname = (char *) bfd_malloc (14);
+ sprintf (sname, ".got.plt.%u", chunk);
+ s = bfd_make_section (dynobj, sname);
+ if (s == NULL
+ || ! bfd_set_section_flags (dynobj, s, flags)
+ || ! bfd_set_section_alignment (dynobj, s, 2))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/* Adjust a symbol defined by a dynamic object and referenced by a
+ regular object. The current definition is in some section of the
+ dynamic object, but we're not including those sections. We have to
+ change the definition to something the rest of the link can
+ understand. */
+
+static bfd_boolean
+elf_xtensa_adjust_dynamic_symbol (info, h)
+ struct bfd_link_info *info ATTRIBUTE_UNUSED;
+ struct elf_link_hash_entry *h;
+{
+ /* If this is a weak symbol, and there is a real definition, the
+ processor independent code will have arranged for us to see the
+ real definition first, and we can just use the same value. */
+ if (h->weakdef != NULL)
+ {
+ BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined
+ || h->weakdef->root.type == bfd_link_hash_defweak);
+ h->root.u.def.section = h->weakdef->root.u.def.section;
+ h->root.u.def.value = h->weakdef->root.u.def.value;
+ return TRUE;
+ }
+
+ /* This is a reference to a symbol defined by a dynamic object. The
+ reference must go through the GOT, so there's no need for COPY relocs,
+ .dynbss, etc. */
+
+ return TRUE;
+}
+
+
+static void
+elf_xtensa_make_sym_local (info, h)
+ struct bfd_link_info *info;
+ struct elf_link_hash_entry *h;
+{
+ if (info->shared)
+ {
+ if (h->plt.refcount > 0)
+ {
+ /* Will use RELATIVE relocs instead of JMP_SLOT relocs. */
+ if (h->got.refcount < 0)
+ h->got.refcount = 0;
+ h->got.refcount += h->plt.refcount;
+ h->plt.refcount = 0;
+ }
+ }
+ else
+ {
+ /* Don't need any dynamic relocations at all. */
+ h->elf_link_hash_flags &= ~ELF_LINK_NON_GOT_REF;
+ h->plt.refcount = 0;
+ h->got.refcount = 0;
+ }
+}
+
+
+static bfd_boolean
+elf_xtensa_fix_refcounts (h, arg)
+ struct elf_link_hash_entry *h;
+ PTR arg;
+{
+ struct bfd_link_info *info = (struct bfd_link_info *) arg;
+
+ if (h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+ if (! xtensa_elf_dynamic_symbol_p (info, h))
+ elf_xtensa_make_sym_local (info, h);
+
+ /* If the symbol has a relocation outside the GOT, set the
+ DF_TEXTREL flag. */
+ if ((h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) != 0)
+ info->flags |= DF_TEXTREL;
+
+ return TRUE;
+}
+
+
+static bfd_boolean
+elf_xtensa_allocate_plt_size (h, arg)
+ struct elf_link_hash_entry *h;
+ PTR arg;
+{
+ asection *srelplt = (asection *) arg;
+
+ if (h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+ if (h->plt.refcount > 0)
+ srelplt->_raw_size += (h->plt.refcount * sizeof (Elf32_External_Rela));
+
+ return TRUE;
+}
+
+
+static bfd_boolean
+elf_xtensa_allocate_got_size (h, arg)
+ struct elf_link_hash_entry *h;
+ PTR arg;
+{
+ asection *srelgot = (asection *) arg;
+
+ if (h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+ if (h->got.refcount > 0)
+ srelgot->_raw_size += (h->got.refcount * sizeof (Elf32_External_Rela));
+
+ return TRUE;
+}
+
+
+static void
+elf_xtensa_allocate_local_got_size (info, srelgot)
+ struct bfd_link_info *info;
+ asection *srelgot;
+{
+ bfd *i;
+
+ for (i = info->input_bfds; i; i = i->link_next)
+ {
+ bfd_signed_vma *local_got_refcounts;
+ bfd_size_type j, cnt;
+ Elf_Internal_Shdr *symtab_hdr;
+
+ local_got_refcounts = elf_local_got_refcounts (i);
+ if (!local_got_refcounts)
+ continue;
+
+ symtab_hdr = &elf_tdata (i)->symtab_hdr;
+ cnt = symtab_hdr->sh_info;
+
+ for (j = 0; j < cnt; ++j)
+ {
+ if (local_got_refcounts[j] > 0)
+ srelgot->_raw_size += (local_got_refcounts[j]
+ * sizeof (Elf32_External_Rela));
+ }
+ }
+}
+
+
+/* Set the sizes of the dynamic sections. */
+
+static bfd_boolean
+elf_xtensa_size_dynamic_sections (output_bfd, info)
+ bfd *output_bfd ATTRIBUTE_UNUSED;
+ struct bfd_link_info *info;
+{
+ bfd *dynobj;
+ asection *s, *srelplt, *splt, *sgotplt, *srelgot, *spltlittbl;
+ bfd_boolean relplt, relgot;
+ int plt_entries, plt_chunks, chunk;
+
+ plt_entries = 0;
+ plt_chunks = 0;
+ srelgot = 0;
+
+ dynobj = elf_hash_table (info)->dynobj;
+ if (dynobj == NULL)
+ abort ();
+
+ if (elf_hash_table (info)->dynamic_sections_created)
+ {
+ /* Set the contents of the .interp section to the interpreter. */
+ if (! info->shared)
+ {
+ s = bfd_get_section_by_name (dynobj, ".interp");
+ if (s == NULL)
+ abort ();
+ s->_raw_size = sizeof ELF_DYNAMIC_INTERPRETER;
+ s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
+ }
+
+ /* Allocate room for one word in ".got". */
+ s = bfd_get_section_by_name (dynobj, ".got");
+ if (s == NULL)
+ abort ();
+ s->_raw_size = 4;
+
+ /* Adjust refcounts for symbols that we now know are not "dynamic". */
+ elf_link_hash_traverse (elf_hash_table (info),
+ elf_xtensa_fix_refcounts,
+ (PTR) info);
+
+ /* Allocate space in ".rela.got" for literals that reference
+ global symbols. */
+ srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+ if (srelgot == NULL)
+ abort ();
+ elf_link_hash_traverse (elf_hash_table (info),
+ elf_xtensa_allocate_got_size,
+ (PTR) srelgot);
+
+ /* If we are generating a shared object, we also need space in
+ ".rela.got" for R_XTENSA_RELATIVE relocs for literals that
+ reference local symbols. */
+ if (info->shared)
+ elf_xtensa_allocate_local_got_size (info, srelgot);
+
+ /* Allocate space in ".rela.plt" for literals that have PLT entries. */
+ srelplt = bfd_get_section_by_name (dynobj, ".rela.plt");
+ if (srelplt == NULL)
+ abort ();
+ elf_link_hash_traverse (elf_hash_table (info),
+ elf_xtensa_allocate_plt_size,
+ (PTR) srelplt);
+
+ /* Allocate space in ".plt" to match the size of ".rela.plt". For
+ each PLT entry, we need the PLT code plus a 4-byte literal.
+ For each chunk of ".plt", we also need two more 4-byte
+ literals, two corresponding entries in ".rela.got", and an
+ 8-byte entry in ".xt.lit.plt". */
+ spltlittbl = bfd_get_section_by_name (dynobj, ".xt.lit.plt");
+ if (spltlittbl == NULL)
+ abort ();
+
+ plt_entries = srelplt->_raw_size / sizeof (Elf32_External_Rela);
+ plt_chunks =
+ (plt_entries + PLT_ENTRIES_PER_CHUNK - 1) / PLT_ENTRIES_PER_CHUNK;
+
+ /* Iterate over all the PLT chunks, including any extra sections
+ created earlier because the initial count of PLT relocations
+ was an overestimate. */
+ for (chunk = 0;
+ (splt = elf_xtensa_get_plt_section (dynobj, chunk)) != NULL;
+ chunk++)
+ {
+ int chunk_entries;
+
+ sgotplt = elf_xtensa_get_gotplt_section (dynobj, chunk);
+ if (sgotplt == NULL)
+ abort ();
+
+ if (chunk < plt_chunks - 1)
+ chunk_entries = PLT_ENTRIES_PER_CHUNK;
+ else if (chunk == plt_chunks - 1)
+ chunk_entries = plt_entries - (chunk * PLT_ENTRIES_PER_CHUNK);
+ else
+ chunk_entries = 0;
+
+ if (chunk_entries != 0)
+ {
+ sgotplt->_raw_size = 4 * (chunk_entries + 2);
+ splt->_raw_size = PLT_ENTRY_SIZE * chunk_entries;
+ srelgot->_raw_size += 2 * sizeof (Elf32_External_Rela);
+ spltlittbl->_raw_size += 8;
+ }
+ else
+ {
+ sgotplt->_raw_size = 0;
+ splt->_raw_size = 0;
+ }
+ }
+ }
+
+ /* Allocate memory for dynamic sections. */
+ relplt = FALSE;
+ relgot = FALSE;
+ for (s = dynobj->sections; s != NULL; s = s->next)
+ {
+ const char *name;
+ bfd_boolean strip;
+
+ if ((s->flags & SEC_LINKER_CREATED) == 0)
+ continue;
+
+ /* It's OK to base decisions on the section name, because none
+ of the dynobj section names depend upon the input files. */
+ name = bfd_get_section_name (dynobj, s);
+
+ strip = FALSE;
+
+ if (strncmp (name, ".rela", 5) == 0)
+ {
+ if (strcmp (name, ".rela.plt") == 0)
+ relplt = TRUE;
+ else if (strcmp (name, ".rela.got") == 0)
+ relgot = TRUE;
+
+ /* We use the reloc_count field as a counter if we need
+ to copy relocs into the output file. */
+ s->reloc_count = 0;
+ }
+ else if (strncmp (name, ".plt.", 5) == 0
+ || strncmp (name, ".got.plt.", 9) == 0)
+ {
+ if (s->_raw_size == 0)
+ {
+ /* If we don't need this section, strip it from the output
+ file. We must create the ".plt*" and ".got.plt*"
+ sections in create_dynamic_sections and/or check_relocs
+ based on a conservative estimate of the PLT relocation
+ count, because the sections must be created before the
+ linker maps input sections to output sections. The
+ linker does that before size_dynamic_sections, where we
+ compute the exact size of the PLT, so there may be more
+ of these sections than are actually needed. */
+ strip = TRUE;
+ }
+ }
+ else if (strcmp (name, ".got") != 0
+ && strcmp (name, ".plt") != 0
+ && strcmp (name, ".got.plt") != 0
+ && strcmp (name, ".xt.lit.plt") != 0)
+ {
+ /* It's not one of our sections, so don't allocate space. */
+ continue;
+ }
+
+ if (strip)
+ _bfd_strip_section_from_output (info, s);
+ else
+ {
+ /* Allocate memory for the section contents. */
+ s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->_raw_size);
+ if (s->contents == NULL && s->_raw_size != 0)
+ return FALSE;
+ }
+ }
+
+ if (elf_hash_table (info)->dynamic_sections_created)
+ {
+ /* Add the special XTENSA_RTLD relocations now. The offsets won't be
+ known until finish_dynamic_sections, but we need to get the relocs
+ in place before they are sorted. */
+ if (srelgot == NULL)
+ abort ();
+ for (chunk = 0; chunk < plt_chunks; chunk++)
+ {
+ Elf_Internal_Rela irela;
+ bfd_byte *loc;
+
+ irela.r_offset = 0;
+ irela.r_info = ELF32_R_INFO (0, R_XTENSA_RTLD);
+ irela.r_addend = 0;
+
+ loc = (srelgot->contents
+ + srelgot->reloc_count * sizeof (Elf32_External_Rela));
+ bfd_elf32_swap_reloca_out (output_bfd, &irela, loc);
+ bfd_elf32_swap_reloca_out (output_bfd, &irela,
+ loc + sizeof (Elf32_External_Rela));
+ srelgot->reloc_count += 2;
+ }
+
+ /* Add some entries to the .dynamic section. We fill in the
+ values later, in elf_xtensa_finish_dynamic_sections, but we
+ must add the entries now so that we get the correct size for
+ the .dynamic section. The DT_DEBUG entry is filled in by the
+ dynamic linker and used by the debugger. */
+#define add_dynamic_entry(TAG, VAL) \
+ bfd_elf32_add_dynamic_entry (info, (bfd_vma) (TAG), (bfd_vma) (VAL))
+
+ if (! info->shared)
+ {
+ if (!add_dynamic_entry (DT_DEBUG, 0))
+ return FALSE;
+ }
+
+ if (relplt)
+ {
+ if (!add_dynamic_entry (DT_PLTGOT, 0)
+ || !add_dynamic_entry (DT_PLTRELSZ, 0)
+ || !add_dynamic_entry (DT_PLTREL, DT_RELA)
+ || !add_dynamic_entry (DT_JMPREL, 0))
+ return FALSE;
+ }
+
+ if (relgot)
+ {
+ if (!add_dynamic_entry (DT_RELA, 0)
+ || !add_dynamic_entry (DT_RELASZ, 0)
+ || !add_dynamic_entry (DT_RELAENT, sizeof (Elf32_External_Rela)))
+ return FALSE;
+ }
+
+ if ((info->flags & DF_TEXTREL) != 0)
+ {
+ if (!add_dynamic_entry (DT_TEXTREL, 0))
+ return FALSE;
+ }
+
+ if (!add_dynamic_entry (DT_XTENSA_GOT_LOC_OFF, 0)
+ || !add_dynamic_entry (DT_XTENSA_GOT_LOC_SZ, 0))
+ return FALSE;
+ }
+#undef add_dynamic_entry
+
+ return TRUE;
+}
+
+
+/* Remove any PT_LOAD segments with no allocated sections. Prior to
+ binutils 2.13, this function used to remove the non-SEC_ALLOC
+ sections from PT_LOAD segments, but that task has now been moved
+ into elf.c. We still need this function to remove any empty
+ segments that result, but there's nothing Xtensa-specific about
+ this and it probably ought to be moved into elf.c as well. */
+
+static bfd_boolean
+elf_xtensa_modify_segment_map (abfd)
+ bfd *abfd;
+{
+ struct elf_segment_map **m_p;
+
+ m_p = &elf_tdata (abfd)->segment_map;
+ while (*m_p != NULL)
+ {
+ if ((*m_p)->p_type == PT_LOAD && (*m_p)->count == 0)
+ *m_p = (*m_p)->next;
+ else
+ m_p = &(*m_p)->next;
+ }
+ return TRUE;
+}
+
+
+/* Perform the specified relocation. The instruction at (contents + address)
+ is modified to set one operand to represent the value in "relocation". The
+ operand position is determined by the relocation type recorded in the
+ howto. */
+
+#define CALL_SEGMENT_BITS (30)
+#define CALL_SEGMENT_SIZE (1<<CALL_SEGMENT_BITS)
+
+static bfd_reloc_status_type
+elf_xtensa_do_reloc (howto, abfd, input_section, relocation,
+ contents, address, is_weak_undef, error_message)
+ reloc_howto_type *howto;
+ bfd *abfd;
+ asection *input_section;
+ bfd_vma relocation;
+ bfd_byte *contents;
+ bfd_vma address;
+ bfd_boolean is_weak_undef;
+ char **error_message;
+{
+ xtensa_opcode opcode;
+ xtensa_operand operand;
+ xtensa_encode_result encode_result;
+ xtensa_isa isa = xtensa_default_isa;
+ xtensa_insnbuf ibuff;
+ bfd_vma self_address;
+ int opnd;
+ uint32 newval;
+
+ switch (howto->type)
+ {
+ case R_XTENSA_NONE:
+ return bfd_reloc_ok;
+
+ case R_XTENSA_ASM_EXPAND:
+ if (!is_weak_undef)
+ {
+ /* Check for windowed CALL across a 1GB boundary. */
+ xtensa_opcode opcode =
+ get_expanded_call_opcode (contents + address,
+ input_section->_raw_size - address);
+ if (is_windowed_call_opcode (opcode))
+ {
+ self_address = (input_section->output_section->vma
+ + input_section->output_offset
+ + address);
+ if ((self_address >> CALL_SEGMENT_BITS) !=
+ (relocation >> CALL_SEGMENT_BITS))
+ {
+ *error_message = "windowed longcall crosses 1GB boundary; "
+ "return may fail";
+ return bfd_reloc_dangerous;
+ }
+ }
+ }
+ return bfd_reloc_ok;
+
+ case R_XTENSA_ASM_SIMPLIFY:
+ {
+ /* Convert the L32R/CALLX to CALL. */
+ bfd_reloc_status_type retval =
+ elf_xtensa_do_asm_simplify (contents, address,
+ input_section->_raw_size);
+ if (retval != bfd_reloc_ok)
+ return retval;
+
+ /* The CALL needs to be relocated. Continue below for that part. */
+ address += 3;
+ howto = &elf_howto_table[(unsigned) R_XTENSA_OP0 ];
+ }
+ break;
+
+ case R_XTENSA_32:
+ case R_XTENSA_PLT:
+ {
+ bfd_vma x;
+ x = bfd_get_32 (abfd, contents + address);
+ x = x + relocation;
+ bfd_put_32 (abfd, x, contents + address);
+ }
+ return bfd_reloc_ok;
+ }
+
+ /* Read the instruction into a buffer and decode the opcode. */
+ ibuff = xtensa_insnbuf_alloc (isa);
+ xtensa_insnbuf_from_chars (isa, ibuff, contents + address);
+ opcode = xtensa_decode_insn (isa, ibuff);
+
+ /* Determine which operand is being relocated. */
+ if (opcode == XTENSA_UNDEFINED)
+ {
+ *error_message = "cannot decode instruction";
+ return bfd_reloc_dangerous;
+ }
+
+ if (howto->type < R_XTENSA_OP0 || howto->type > R_XTENSA_OP2)
+ {
+ *error_message = "unexpected relocation";
+ return bfd_reloc_dangerous;
+ }
+
+ opnd = howto->type - R_XTENSA_OP0;
+
+ /* Calculate the PC address for this instruction. */
+ if (!howto->pc_relative)
+ {
+ *error_message = "expected PC-relative relocation";
+ return bfd_reloc_dangerous;
+ }
+
+ self_address = (input_section->output_section->vma
+ + input_section->output_offset
+ + address);
+
+ /* Apply the relocation. */
+ operand = xtensa_get_operand (isa, opcode, opnd);
+ newval = xtensa_operand_do_reloc (operand, relocation, self_address);
+ encode_result = xtensa_operand_encode (operand, &newval);
+ xtensa_operand_set_field (operand, ibuff, newval);
+
+ /* Write the modified instruction back out of the buffer. */
+ xtensa_insnbuf_to_chars (isa, ibuff, contents + address);
+ free (ibuff);
+
+ if (encode_result != xtensa_encode_result_ok)
+ {
+ char *message = build_encoding_error_message (opcode, encode_result);
+ *error_message = message;
+ return bfd_reloc_dangerous;
+ }
+
+ /* Final check for call. */
+ if (is_direct_call_opcode (opcode)
+ && is_windowed_call_opcode (opcode))
+ {
+ if ((self_address >> CALL_SEGMENT_BITS) !=
+ (relocation >> CALL_SEGMENT_BITS))
+ {
+ *error_message = "windowed call crosses 1GB boundary; "
+ "return may fail";
+ return bfd_reloc_dangerous;
+ }
+ }
+
+ return bfd_reloc_ok;
+}
+
+
+static char *
+vsprint_msg VPARAMS ((const char *origmsg, const char *fmt, int arglen, ...))
+{
+ /* To reduce the size of the memory leak,
+ we only use a single message buffer. */
+ static bfd_size_type alloc_size = 0;
+ static char *message = NULL;
+ bfd_size_type orig_len, len = 0;
+ bfd_boolean is_append;
+
+ VA_OPEN (ap, arglen);
+ VA_FIXEDARG (ap, const char *, origmsg);
+
+ is_append = (origmsg == message);
+
+ orig_len = strlen (origmsg);
+ len = orig_len + strlen (fmt) + arglen + 20;
+ if (len > alloc_size)
+ {
+ message = (char *) bfd_realloc (message, len);
+ alloc_size = len;
+ }
+ if (!is_append)
+ memcpy (message, origmsg, orig_len);
+ vsprintf (message + orig_len, fmt, ap);
+ VA_CLOSE (ap);
+ return message;
+}
+
+
+static char *
+build_encoding_error_message (opcode, encode_result)
+ xtensa_opcode opcode;
+ xtensa_encode_result encode_result;
+{
+ const char *opname = xtensa_opcode_name (xtensa_default_isa, opcode);
+ const char *msg = NULL;
+
+ switch (encode_result)
+ {
+ case xtensa_encode_result_ok:
+ msg = "unexpected valid encoding";
+ break;
+ case xtensa_encode_result_align:
+ msg = "misaligned encoding";
+ break;
+ case xtensa_encode_result_not_in_table:
+ msg = "encoding not in lookup table";
+ break;
+ case xtensa_encode_result_too_low:
+ msg = "encoding out of range: too low";
+ break;
+ case xtensa_encode_result_too_high:
+ msg = "encoding out of range: too high";
+ break;
+ case xtensa_encode_result_not_ok:
+ default:
+ msg = "could not encode";
+ break;
+ }
+
+ if (is_direct_call_opcode (opcode)
+ && (encode_result == xtensa_encode_result_too_low
+ || encode_result == xtensa_encode_result_too_high))
+
+ msg = "direct call out of range";
+
+ else if (opcode == get_l32r_opcode ())
+ {
+ /* L32Rs have the strange interaction with encoding in that they
+ have an unsigned immediate field, so libisa returns "too high"
+ when the absolute value is out of range and never returns "too
+ low", but I leave the "too low" message in case anything
+ changes. */
+ if (encode_result == xtensa_encode_result_too_low)
+ msg = "literal out of range";
+ else if (encode_result == xtensa_encode_result_too_high)
+ msg = "literal placed after use";
+ }
+
+ return vsprint_msg (opname, ": %s", strlen (msg) + 2, msg);
+}
+
+
+/* This function is registered as the "special_function" in the
+ Xtensa howto for handling simplify operations.
+ bfd_perform_relocation / bfd_install_relocation use it to
+ perform (install) the specified relocation. Since this replaces the code
+ in bfd_perform_relocation, it is basically an Xtensa-specific,
+ stripped-down version of bfd_perform_relocation. */
+
+static bfd_reloc_status_type
+bfd_elf_xtensa_reloc (abfd, reloc_entry, symbol, data, input_section,
+ output_bfd, error_message)
+ bfd *abfd;
+ arelent *reloc_entry;
+ asymbol *symbol;
+ PTR data;
+ asection *input_section;
+ bfd *output_bfd;
+ char **error_message;
+{
+ bfd_vma relocation;
+ bfd_reloc_status_type flag;
+ bfd_size_type octets = reloc_entry->address * bfd_octets_per_byte (abfd);
+ bfd_vma output_base = 0;
+ reloc_howto_type *howto = reloc_entry->howto;
+ asection *reloc_target_output_section;
+ bfd_boolean is_weak_undef;
+
+ /* ELF relocs are against symbols. If we are producing relocateable
+ output, and the reloc is against an external symbol, the resulting
+ reloc will also be against the same symbol. In such a case, we
+ don't want to change anything about the way the reloc is handled,
+ since it will all be done at final link time. This test is similar
+ to what bfd_elf_generic_reloc does except that it lets relocs with
+ howto->partial_inplace go through even if the addend is non-zero.
+ (The real problem is that partial_inplace is set for XTENSA_32
+ relocs to begin with, but that's a long story and there's little we
+ can do about it now....) */
+
+ if (output_bfd != (bfd *) NULL
+ && (symbol->flags & BSF_SECTION_SYM) == 0)
+ {
+ reloc_entry->address += input_section->output_offset;
+ return bfd_reloc_ok;
+ }
+
+ /* Is the address of the relocation really within the section? */
+ if (reloc_entry->address > (input_section->_cooked_size
+ / bfd_octets_per_byte (abfd)))
+ return bfd_reloc_outofrange;
+
+ /* Work out which section the relocation is targetted at and the
+ initial relocation command value. */
+
+ /* Get symbol value. (Common symbols are special.) */
+ if (bfd_is_com_section (symbol->section))
+ relocation = 0;
+ else
+ relocation = symbol->value;
+
+ reloc_target_output_section = symbol->section->output_section;
+
+ /* Convert input-section-relative symbol value to absolute. */
+ if ((output_bfd && !howto->partial_inplace)
+ || reloc_target_output_section == NULL)
+ output_base = 0;
+ else
+ output_base = reloc_target_output_section->vma;
+
+ relocation += output_base + symbol->section->output_offset;
+
+ /* Add in supplied addend. */
+ relocation += reloc_entry->addend;
+
+ /* Here the variable relocation holds the final address of the
+ symbol we are relocating against, plus any addend. */
+ if (output_bfd)
+ {
+ if (!howto->partial_inplace)
+ {
+ /* This is a partial relocation, and we want to apply the relocation
+ to the reloc entry rather than the raw data. Everything except
+ relocations against section symbols has already been handled
+ above. */
+
+ BFD_ASSERT (symbol->flags & BSF_SECTION_SYM);
+ reloc_entry->addend = relocation;
+ reloc_entry->address += input_section->output_offset;
+ return bfd_reloc_ok;
+ }
+ else
+ {
+ reloc_entry->address += input_section->output_offset;
+ reloc_entry->addend = 0;
+ }
+ }
+
+ is_weak_undef = (bfd_is_und_section (symbol->section)
+ && (symbol->flags & BSF_WEAK) != 0);
+ flag = elf_xtensa_do_reloc (howto, abfd, input_section, relocation,
+ (bfd_byte *) data, (bfd_vma) octets,
+ is_weak_undef, error_message);
+
+ if (flag == bfd_reloc_dangerous)
+ {
+ /* Add the symbol name to the error message. */
+ if (! *error_message)
+ *error_message = "";
+ *error_message = vsprint_msg (*error_message, ": (%s + 0x%lx)",
+ strlen (symbol->name) + 17,
+ symbol->name, reloc_entry->addend);
+ }
+
+ return flag;
+}
+
+
+/* Set up an entry in the procedure linkage table. */
+
+static bfd_vma
+elf_xtensa_create_plt_entry (dynobj, output_bfd, reloc_index)
+ bfd *dynobj;
+ bfd *output_bfd;
+ unsigned reloc_index;
+{
+ asection *splt, *sgotplt;
+ bfd_vma plt_base, got_base;
+ bfd_vma code_offset, lit_offset;
+ int chunk;
+
+ chunk = reloc_index / PLT_ENTRIES_PER_CHUNK;
+ splt = elf_xtensa_get_plt_section (dynobj, chunk);
+ sgotplt = elf_xtensa_get_gotplt_section (dynobj, chunk);
+ BFD_ASSERT (splt != NULL && sgotplt != NULL);
+
+ plt_base = splt->output_section->vma + splt->output_offset;
+ got_base = sgotplt->output_section->vma + sgotplt->output_offset;
+
+ lit_offset = 8 + (reloc_index % PLT_ENTRIES_PER_CHUNK) * 4;
+ code_offset = (reloc_index % PLT_ENTRIES_PER_CHUNK) * PLT_ENTRY_SIZE;
+
+ /* Fill in the literal entry. This is the offset of the dynamic
+ relocation entry. */
+ bfd_put_32 (output_bfd, reloc_index * sizeof (Elf32_External_Rela),
+ sgotplt->contents + lit_offset);
+
+ /* Fill in the entry in the procedure linkage table. */
+ memcpy (splt->contents + code_offset,
+ (bfd_big_endian (output_bfd)
+ ? elf_xtensa_be_plt_entry
+ : elf_xtensa_le_plt_entry),
+ PLT_ENTRY_SIZE);
+ bfd_put_16 (output_bfd, l32r_offset (got_base + 0,
+ plt_base + code_offset + 3),
+ splt->contents + code_offset + 4);
+ bfd_put_16 (output_bfd, l32r_offset (got_base + 4,
+ plt_base + code_offset + 6),
+ splt->contents + code_offset + 7);
+ bfd_put_16 (output_bfd, l32r_offset (got_base + lit_offset,
+ plt_base + code_offset + 9),
+ splt->contents + code_offset + 10);
+
+ return plt_base + code_offset;
+}
+
+
+static bfd_boolean
+xtensa_elf_dynamic_symbol_p (info, h)
+ struct bfd_link_info *info;
+ struct elf_link_hash_entry *h;
+{
+ if (h == NULL)
+ return FALSE;
+
+ while (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+ if (h->dynindx == -1)
+ return FALSE;
+
+ if (h->root.type == bfd_link_hash_undefweak
+ || h->root.type == bfd_link_hash_defweak)
+ return TRUE;
+
+ switch (ELF_ST_VISIBILITY (h->other))
+ {
+ case STV_DEFAULT:
+ break;
+ case STV_HIDDEN:
+ case STV_INTERNAL:
+ return FALSE;
+ case STV_PROTECTED:
+ if (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)
+ return FALSE;
+ break;
+ }
+
+ if ((info->shared && !info->symbolic)
+ || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+ return TRUE;
+
+ return FALSE;
+}
+
+
+/* Relocate an Xtensa ELF section. This is invoked by the linker for
+ both relocateable and final links. */
+
+static bfd_boolean
+elf_xtensa_relocate_section (output_bfd, info, input_bfd,
+ input_section, contents, relocs,
+ local_syms, local_sections)
+ 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;
+ Elf_Internal_Rela *rel;
+ Elf_Internal_Rela *relend;
+ struct elf_link_hash_entry **sym_hashes;
+ asection *srelgot, *srelplt;
+ bfd *dynobj;
+ char *error_message = NULL;
+
+ if (xtensa_default_isa == NULL)
+ xtensa_isa_init ();
+
+ dynobj = elf_hash_table (info)->dynobj;
+ symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+ sym_hashes = elf_sym_hashes (input_bfd);
+
+ srelgot = NULL;
+ srelplt = NULL;
+ if (dynobj != NULL)
+ {
+ srelgot = bfd_get_section_by_name (dynobj, ".rela.got");;
+ srelplt = bfd_get_section_by_name (dynobj, ".rela.plt");
+ }
+
+ rel = relocs;
+ relend = relocs + input_section->reloc_count;
+ for (; rel < relend; rel++)
+ {
+ int r_type;
+ reloc_howto_type *howto;
+ unsigned long r_symndx;
+ struct elf_link_hash_entry *h;
+ Elf_Internal_Sym *sym;
+ asection *sec;
+ bfd_vma relocation;
+ bfd_reloc_status_type r;
+ bfd_boolean is_weak_undef;
+ bfd_boolean unresolved_reloc;
+
+ r_type = ELF32_R_TYPE (rel->r_info);
+ if (r_type == (int) R_XTENSA_GNU_VTINHERIT
+ || r_type == (int) R_XTENSA_GNU_VTENTRY)
+ continue;
+
+ if (r_type < 0 || r_type >= (int) R_XTENSA_max)
+ {
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+ howto = &elf_howto_table[r_type];
+
+ r_symndx = ELF32_R_SYM (rel->r_info);
+
+ if (info->relocateable)
+ {
+ /* This is a relocateable link.
+ 1) If the reloc is against a section symbol, adjust
+ according to the output section.
+ 2) If there is a new target for this relocation,
+ the new target will be in the same output section.
+ We adjust the relocation by the output section
+ difference. */
+
+ if (relaxing_section)
+ {
+ /* Check if this references a section in another input file. */
+ do_fix_for_relocateable_link (rel, input_bfd, input_section);
+ r_type = ELF32_R_TYPE (rel->r_info);
+ }
+
+ if (r_type == R_XTENSA_ASM_SIMPLIFY)
+ {
+ /* Convert ASM_SIMPLIFY into the simpler relocation
+ so that they never escape a relaxing link. */
+ contract_asm_expansion (contents, input_section->_raw_size, rel);
+ r_type = ELF32_R_TYPE (rel->r_info);
+ }
+
+ /* This is a relocateable link, so we don't have to change
+ anything unless the reloc is against a section symbol,
+ in which case we have to adjust according to where the
+ section symbol winds up in the output section. */
+ if (r_symndx < symtab_hdr->sh_info)
+ {
+ sym = local_syms + r_symndx;
+ if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
+ {
+ sec = local_sections[r_symndx];
+ rel->r_addend += sec->output_offset + sym->st_value;
+ }
+ }
+
+ /* If there is an addend with a partial_inplace howto,
+ then move the addend to the contents. This is a hack
+ to work around problems with DWARF in relocateable links
+ with some previous version of BFD. Now we can't easily get
+ rid of the hack without breaking backward compatibility.... */
+ if (rel->r_addend)
+ {
+ howto = &elf_howto_table[r_type];
+ if (howto->partial_inplace)
+ {
+ r = elf_xtensa_do_reloc (howto, input_bfd, input_section,
+ rel->r_addend, contents,
+ rel->r_offset, FALSE,
+ &error_message);
+ if (r != bfd_reloc_ok)
+ {
+ if (!((*info->callbacks->reloc_dangerous)
+ (info, error_message, input_bfd, input_section,
+ rel->r_offset)))
+ return FALSE;
+ }
+ rel->r_addend = 0;
+ }
+ }
+
+ /* Done with work for relocateable link; continue with next reloc. */
+ continue;
+ }
+
+ /* This is a final link. */
+
+ h = NULL;
+ sym = NULL;
+ sec = NULL;
+ is_weak_undef = FALSE;
+ unresolved_reloc = FALSE;
+
+ if (howto->partial_inplace)
+ {
+ /* Because R_XTENSA_32 was made partial_inplace to fix some
+ problems with DWARF info in partial links, there may be
+ an addend stored in the contents. Take it out of there
+ and move it back into the addend field of the reloc. */
+ rel->r_addend += bfd_get_32 (input_bfd, contents + rel->r_offset);
+ bfd_put_32 (input_bfd, 0, contents + rel->r_offset);
+ }
+
+ 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
+ {
+ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+
+ while (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+ relocation = 0;
+ if (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ {
+ sec = h->root.u.def.section;
+
+ if (sec->output_section == NULL)
+ /* Set a flag that will be cleared later if we find a
+ relocation value for this symbol. output_section
+ is typically NULL for symbols satisfied by a shared
+ library. */
+ unresolved_reloc = TRUE;
+ else
+ relocation = (h->root.u.def.value
+ + sec->output_section->vma
+ + sec->output_offset);
+ }
+ else if (h->root.type == bfd_link_hash_undefweak)
+ is_weak_undef = TRUE;
+ else if (info->shared
+ && !info->no_undefined
+ && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
+ ;
+ else
+ {
+ if (! ((*info->callbacks->undefined_symbol)
+ (info, h->root.root.string, input_bfd,
+ input_section, rel->r_offset,
+ (!info->shared || info->no_undefined
+ || ELF_ST_VISIBILITY (h->other)))))
+ return FALSE;
+
+ /* To avoid any more warning messages, like "call out of
+ range", we continue immediately to the next relocation. */
+ continue;
+ }
+ }
+
+ if (relaxing_section)
+ {
+ /* Check if this references a section in another input file. */
+ do_fix_for_final_link (rel, input_section, &relocation);
+
+ /* Update some already cached values. */
+ r_type = ELF32_R_TYPE (rel->r_info);
+ howto = &elf_howto_table[r_type];
+ }
+
+ /* Sanity check the address. */
+ if (rel->r_offset >= input_section->_raw_size
+ && ELF32_R_TYPE (rel->r_info) != R_XTENSA_NONE)
+ {
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+
+ /* Generate dynamic relocations. */
+ if (elf_hash_table (info)->dynamic_sections_created)
+ {
+ bfd_boolean dynamic_symbol = xtensa_elf_dynamic_symbol_p (info, h);
+
+ if (dynamic_symbol && (r_type == R_XTENSA_OP0
+ || r_type == R_XTENSA_OP1
+ || r_type == R_XTENSA_OP2))
+ {
+ /* This is an error. The symbol's real value won't be known
+ until runtime and it's likely to be out of range anyway. */
+ const char *name = h->root.root.string;
+ error_message = vsprint_msg ("invalid relocation for dynamic "
+ "symbol", ": %s",
+ strlen (name) + 2, name);
+ if (!((*info->callbacks->reloc_dangerous)
+ (info, error_message, input_bfd, input_section,
+ rel->r_offset)))
+ return FALSE;
+ }
+ else if ((r_type == R_XTENSA_32 || r_type == R_XTENSA_PLT)
+ && (input_section->flags & SEC_ALLOC) != 0
+ && (dynamic_symbol || info->shared))
+ {
+ Elf_Internal_Rela outrel;
+ bfd_byte *loc;
+ asection *srel;
+
+ if (dynamic_symbol && r_type == R_XTENSA_PLT)
+ srel = srelplt;
+ else
+ srel = srelgot;
+
+ BFD_ASSERT (srel != NULL);
+
+ outrel.r_offset =
+ _bfd_elf_section_offset (output_bfd, info,
+ input_section, rel->r_offset);
+
+ if ((outrel.r_offset | 1) == (bfd_vma) -1)
+ memset (&outrel, 0, sizeof outrel);
+ else
+ {
+ outrel.r_offset = (input_section->output_section->vma
+ + input_section->output_offset);
+
+ if (dynamic_symbol)
+ {
+ outrel.r_addend = rel->r_addend;
+ rel->r_addend = 0;
+
+ if (r_type == R_XTENSA_32)
+ {
+ outrel.r_info =
+ ELF32_R_INFO (h->dynindx, R_XTENSA_GLOB_DAT);
+ relocation = 0;
+ }
+ else /* r_type == R_XTENSA_PLT */
+ {
+ outrel.r_info =
+ ELF32_R_INFO (h->dynindx, R_XTENSA_JMP_SLOT);
+
+ /* Create the PLT entry and set the initial
+ contents of the literal entry to the address of
+ the PLT entry. */
+ relocation =
+ elf_xtensa_create_plt_entry (dynobj, output_bfd,
+ srel->reloc_count);
+ }
+ unresolved_reloc = FALSE;
+ }
+ else
+ {
+ /* Generate a RELATIVE relocation. */
+ outrel.r_info = ELF32_R_INFO (0, R_XTENSA_RELATIVE);
+ outrel.r_addend = 0;
+ }
+ }
+
+ loc = (srel->contents
+ + srel->reloc_count++ * sizeof (Elf32_External_Rela));
+ bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
+ BFD_ASSERT (sizeof (Elf32_External_Rela) * srel->reloc_count
+ <= srel->_cooked_size);
+ }
+ }
+
+ /* Dynamic relocs are not propagated for SEC_DEBUGGING sections
+ because such sections are not SEC_ALLOC and thus ld.so will
+ not process them. */
+ if (unresolved_reloc
+ && !((input_section->flags & SEC_DEBUGGING) != 0
+ && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0))
+ (*_bfd_error_handler)
+ (_("%s(%s+0x%lx): unresolvable relocation against symbol `%s'"),
+ bfd_archive_filename (input_bfd),
+ bfd_get_section_name (input_bfd, input_section),
+ (long) rel->r_offset,
+ h->root.root.string);
+
+ /* There's no point in calling bfd_perform_relocation here.
+ Just go directly to our "special function". */
+ r = elf_xtensa_do_reloc (howto, input_bfd, input_section,
+ relocation + rel->r_addend,
+ contents, rel->r_offset, is_weak_undef,
+ &error_message);
+
+ if (r != bfd_reloc_ok)
+ {
+ const char *name;
+
+ BFD_ASSERT (r == bfd_reloc_dangerous);
+ BFD_ASSERT (error_message != (char *) NULL);
+
+ 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 && *name == '\0')
+ name = bfd_section_name (input_bfd, sec);
+ }
+ if (name)
+ error_message = vsprint_msg (error_message, ": %s",
+ strlen (name), name);
+ if (!((*info->callbacks->reloc_dangerous)
+ (info, error_message, input_bfd, input_section,
+ rel->r_offset)))
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+/* Finish up dynamic symbol handling. There's not much to do here since
+ the PLT and GOT entries are all set up by relocate_section. */
+
+static bfd_boolean
+elf_xtensa_finish_dynamic_symbol (output_bfd, info, h, sym)
+ bfd *output_bfd ATTRIBUTE_UNUSED;
+ struct bfd_link_info *info ATTRIBUTE_UNUSED;
+ struct elf_link_hash_entry *h;
+ Elf_Internal_Sym *sym;
+{
+ if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0
+ && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+ {
+ /* Mark the symbol as undefined, rather than as defined in
+ the .plt section. Leave the value alone. */
+ sym->st_shndx = SHN_UNDEF;
+ }
+
+ /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */
+ if (strcmp (h->root.root.string, "_DYNAMIC") == 0
+ || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
+ sym->st_shndx = SHN_ABS;
+
+ return TRUE;
+}
+
+
+/* Combine adjacent literal table entries in the output. Adjacent
+ entries within each input section may have been removed during
+ relaxation, but we repeat the process here, even though it's too late
+ to shrink the output section, because it's important to minimize the
+ number of literal table entries to reduce the start-up work for the
+ runtime linker. Returns the number of remaining table entries or -1
+ on error. */
+
+static int
+elf_xtensa_combine_prop_entries (output_bfd, secname)
+ bfd *output_bfd;
+ const char *secname;
+{
+ asection *sec;
+ bfd_byte *contents;
+ property_table_entry *table;
+ bfd_size_type section_size;
+ bfd_vma offset;
+ int n, m, num;
+
+ sec = bfd_get_section_by_name (output_bfd, secname);
+ if (!sec)
+ return -1;
+
+ section_size = (sec->_cooked_size != 0 ? sec->_cooked_size : sec->_raw_size);
+ BFD_ASSERT (section_size % 8 == 0);
+ num = section_size / 8;
+
+ contents = (bfd_byte *) bfd_malloc (section_size);
+ table = (property_table_entry *)
+ bfd_malloc (num * sizeof (property_table_entry));
+ if (contents == 0 || table == 0)
+ return -1;
+
+ /* The ".xt.lit.plt" section has the SEC_IN_MEMORY flag set and this
+ propagates to the output section, where it doesn't really apply and
+ where it breaks the following call to bfd_get_section_contents. */
+ sec->flags &= ~SEC_IN_MEMORY;
+
+ if (! bfd_get_section_contents (output_bfd, sec, contents, 0, section_size))
+ return -1;
+
+ /* There should never be any relocations left at this point, so this
+ is quite a bit easier than what is done during relaxation. */
+
+ /* Copy the raw contents into a property table array and sort it. */
+ offset = 0;
+ for (n = 0; n < num; n++)
+ {
+ table[n].address = bfd_get_32 (output_bfd, &contents[offset]);
+ table[n].size = bfd_get_32 (output_bfd, &contents[offset + 4]);
+ offset += 8;
+ }
+ qsort (table, num, sizeof (property_table_entry), property_table_compare);
+
+ for (n = 0; n < num; n++)
+ {
+ bfd_boolean remove = FALSE;
+
+ if (table[n].size == 0)
+ remove = TRUE;
+ else if (n > 0 &&
+ (table[n-1].address + table[n-1].size == table[n].address))
+ {
+ table[n-1].size += table[n].size;
+ remove = TRUE;
+ }
+
+ if (remove)
+ {
+ for (m = n; m < num - 1; m++)
+ {
+ table[m].address = table[m+1].address;
+ table[m].size = table[m+1].size;
+ }
+
+ n--;
+ num--;
+ }
+ }
+
+ /* Copy the data back to the raw contents. */
+ offset = 0;
+ for (n = 0; n < num; n++)
+ {
+ bfd_put_32 (output_bfd, table[n].address, &contents[offset]);
+ bfd_put_32 (output_bfd, table[n].size, &contents[offset + 4]);
+ offset += 8;
+ }
+
+ /* Clear the removed bytes. */
+ if ((bfd_size_type) (num * 8) < section_size)
+ {
+ memset (&contents[num * 8], 0, section_size - num * 8);
+ sec->_cooked_size = num * 8;
+ }
+
+ if (! bfd_set_section_contents (output_bfd, sec, contents, 0, section_size))
+ return -1;
+
+ free (contents);
+ return num;
+}
+
+
+/* Finish up the dynamic sections. */
+
+static bfd_boolean
+elf_xtensa_finish_dynamic_sections (output_bfd, info)
+ bfd *output_bfd;
+ struct bfd_link_info *info;
+{
+ bfd *dynobj;
+ asection *sdyn, *srelplt, *sgot;
+ Elf32_External_Dyn *dyncon, *dynconend;
+ int num_xtlit_entries;
+
+ if (! elf_hash_table (info)->dynamic_sections_created)
+ return TRUE;
+
+ dynobj = elf_hash_table (info)->dynobj;
+ sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
+ BFD_ASSERT (sdyn != NULL);
+
+ /* Set the first entry in the global offset table to the address of
+ the dynamic section. */
+ sgot = bfd_get_section_by_name (dynobj, ".got");
+ if (sgot)
+ {
+ BFD_ASSERT (sgot->_raw_size == 4);
+ if (sdyn == NULL)
+ bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents);
+ else
+ bfd_put_32 (output_bfd,
+ sdyn->output_section->vma + sdyn->output_offset,
+ sgot->contents);
+ }
+
+ srelplt = bfd_get_section_by_name (dynobj, ".rela.plt");
+ if (srelplt != NULL && srelplt->_raw_size != 0)
+ {
+ asection *sgotplt, *srelgot, *spltlittbl;
+ int chunk, plt_chunks, plt_entries;
+ Elf_Internal_Rela irela;
+ bfd_byte *loc;
+ unsigned rtld_reloc;
+
+ srelgot = bfd_get_section_by_name (dynobj, ".rela.got");;
+ BFD_ASSERT (srelgot != NULL);
+
+ spltlittbl = bfd_get_section_by_name (dynobj, ".xt.lit.plt");
+ BFD_ASSERT (spltlittbl != NULL);
+
+ /* Find the first XTENSA_RTLD relocation. Presumably the rest
+ of them follow immediately after.... */
+ for (rtld_reloc = 0; rtld_reloc < srelgot->reloc_count; rtld_reloc++)
+ {
+ loc = srelgot->contents + rtld_reloc * sizeof (Elf32_External_Rela);
+ bfd_elf32_swap_reloca_in (output_bfd, loc, &irela);
+ if (ELF32_R_TYPE (irela.r_info) == R_XTENSA_RTLD)
+ break;
+ }
+ BFD_ASSERT (rtld_reloc < srelgot->reloc_count);
+
+ plt_entries = (srelplt->_raw_size / sizeof (Elf32_External_Rela));
+ plt_chunks =
+ (plt_entries + PLT_ENTRIES_PER_CHUNK - 1) / PLT_ENTRIES_PER_CHUNK;
+
+ for (chunk = 0; chunk < plt_chunks; chunk++)
+ {
+ int chunk_entries = 0;
+
+ sgotplt = elf_xtensa_get_gotplt_section (dynobj, chunk);
+ BFD_ASSERT (sgotplt != NULL);
+
+ /* Emit special RTLD relocations for the first two entries in
+ each chunk of the .got.plt section. */
+
+ loc = srelgot->contents + rtld_reloc * sizeof (Elf32_External_Rela);
+ bfd_elf32_swap_reloca_in (output_bfd, loc, &irela);
+ BFD_ASSERT (ELF32_R_TYPE (irela.r_info) == R_XTENSA_RTLD);
+ irela.r_offset = (sgotplt->output_section->vma
+ + sgotplt->output_offset);
+ irela.r_addend = 1; /* tell rtld to set value to resolver function */
+ bfd_elf32_swap_reloca_out (output_bfd, &irela, loc);
+ rtld_reloc += 1;
+ BFD_ASSERT (rtld_reloc <= srelgot->reloc_count);
+
+ /* Next literal immediately follows the first. */
+ loc += sizeof (Elf32_External_Rela);
+ bfd_elf32_swap_reloca_in (output_bfd, loc, &irela);
+ BFD_ASSERT (ELF32_R_TYPE (irela.r_info) == R_XTENSA_RTLD);
+ irela.r_offset = (sgotplt->output_section->vma
+ + sgotplt->output_offset + 4);
+ /* Tell rtld to set value to object's link map. */
+ irela.r_addend = 2;
+ bfd_elf32_swap_reloca_out (output_bfd, &irela, loc);
+ rtld_reloc += 1;
+ BFD_ASSERT (rtld_reloc <= srelgot->reloc_count);
+
+ /* Fill in the literal table. */
+ if (chunk < plt_chunks - 1)
+ chunk_entries = PLT_ENTRIES_PER_CHUNK;
+ else
+ chunk_entries = plt_entries - (chunk * PLT_ENTRIES_PER_CHUNK);
+
+ BFD_ASSERT ((unsigned) (chunk + 1) * 8 <= spltlittbl->_cooked_size);
+ bfd_put_32 (output_bfd,
+ sgotplt->output_section->vma + sgotplt->output_offset,
+ spltlittbl->contents + (chunk * 8) + 0);
+ bfd_put_32 (output_bfd,
+ 8 + (chunk_entries * 4),
+ spltlittbl->contents + (chunk * 8) + 4);
+ }
+
+ /* All the dynamic relocations have been emitted at this point.
+ Make sure the relocation sections are the correct size. */
+ if (srelgot->_cooked_size != (sizeof (Elf32_External_Rela)
+ * srelgot->reloc_count)
+ || srelplt->_cooked_size != (sizeof (Elf32_External_Rela)
+ * srelplt->reloc_count))
+ abort ();
+
+ /* The .xt.lit.plt section has just been modified. This must
+ happen before the code below which combines adjacent literal
+ table entries, and the .xt.lit.plt contents have to be forced to
+ the output here. */
+ if (! bfd_set_section_contents (output_bfd,
+ spltlittbl->output_section,
+ spltlittbl->contents,
+ spltlittbl->output_offset,
+ spltlittbl->_raw_size))
+ return FALSE;
+ /* Clear SEC_HAS_CONTENTS so the contents won't be output again. */
+ spltlittbl->flags &= ~SEC_HAS_CONTENTS;
+ }
+
+ /* Combine adjacent literal table entries. */
+ BFD_ASSERT (! info->relocateable);
+ num_xtlit_entries = elf_xtensa_combine_prop_entries (output_bfd, ".xt.lit");
+ if (num_xtlit_entries < 0)
+ return FALSE;
+
+ dyncon = (Elf32_External_Dyn *) sdyn->contents;
+ dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->_raw_size);
+ for (; dyncon < dynconend; dyncon++)
+ {
+ Elf_Internal_Dyn dyn;
+ const char *name;
+ asection *s;
+
+ bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn);
+
+ switch (dyn.d_tag)
+ {
+ default:
+ break;
+
+ case DT_XTENSA_GOT_LOC_SZ:
+ s = bfd_get_section_by_name (output_bfd, ".xt.lit");
+ BFD_ASSERT (s);
+ dyn.d_un.d_val = num_xtlit_entries;
+ break;
+
+ case DT_XTENSA_GOT_LOC_OFF:
+ name = ".xt.lit";
+ goto get_vma;
+ case DT_PLTGOT:
+ name = ".got";
+ goto get_vma;
+ case DT_JMPREL:
+ name = ".rela.plt";
+ get_vma:
+ s = bfd_get_section_by_name (output_bfd, name);
+ BFD_ASSERT (s);
+ dyn.d_un.d_ptr = s->vma;
+ break;
+
+ case DT_PLTRELSZ:
+ s = bfd_get_section_by_name (output_bfd, ".rela.plt");
+ BFD_ASSERT (s);
+ dyn.d_un.d_val = (s->_cooked_size ? s->_cooked_size : s->_raw_size);
+ break;
+
+ case DT_RELASZ:
+ /* Adjust RELASZ to not include JMPREL. This matches what
+ glibc expects and what is done for several other ELF
+ targets (e.g., i386, alpha), but the "correct" behavior
+ seems to be unresolved. Since the linker script arranges
+ for .rela.plt to follow all other relocation sections, we
+ don't have to worry about changing the DT_RELA entry. */
+ s = bfd_get_section_by_name (output_bfd, ".rela.plt");
+ if (s)
+ {
+ dyn.d_un.d_val -=
+ (s->_cooked_size ? s->_cooked_size : s->_raw_size);
+ }
+ break;
+ }
+
+ bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
+ }
+
+ return TRUE;
+}
+
+
+/* Functions for dealing with the e_flags field. */
+
+/* Merge backend specific data from an object file to the output
+ object file when linking. */
+
+static bfd_boolean
+elf_xtensa_merge_private_bfd_data (ibfd, obfd)
+ bfd *ibfd;
+ bfd *obfd;
+{
+ unsigned out_mach, in_mach;
+ flagword out_flag, in_flag;
+
+ /* Check if we have the same endianess. */
+ if (!_bfd_generic_verify_endian_match (ibfd, obfd))
+ return FALSE;
+
+ /* Don't even pretend to support mixed-format linking. */
+ if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+ || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+ return FALSE;
+
+ out_flag = elf_elfheader (obfd)->e_flags;
+ in_flag = elf_elfheader (ibfd)->e_flags;
+
+ out_mach = out_flag & EF_XTENSA_MACH;
+ in_mach = in_flag & EF_XTENSA_MACH;
+ if (out_mach != in_mach)
+ {
+ (*_bfd_error_handler)
+ ("%s: incompatible machine type. Output is 0x%x. Input is 0x%x\n",
+ bfd_archive_filename (ibfd), out_mach, in_mach);
+ bfd_set_error (bfd_error_wrong_format);
+ return FALSE;
+ }
+
+ if (! elf_flags_init (obfd))
+ {
+ elf_flags_init (obfd) = TRUE;
+ elf_elfheader (obfd)->e_flags = in_flag;
+
+ if (bfd_get_arch (obfd) == bfd_get_arch (ibfd)
+ && bfd_get_arch_info (obfd)->the_default)
+ return bfd_set_arch_mach (obfd, bfd_get_arch (ibfd),
+ bfd_get_mach (ibfd));
+
+ return TRUE;
+ }
+
+ if ((out_flag & EF_XTENSA_XT_INSN) !=
+ (in_flag & EF_XTENSA_XT_INSN))
+ elf_elfheader(obfd)->e_flags &= (~ EF_XTENSA_XT_INSN);
+
+ if ((out_flag & EF_XTENSA_XT_LIT) !=
+ (in_flag & EF_XTENSA_XT_LIT))
+ elf_elfheader(obfd)->e_flags &= (~ EF_XTENSA_XT_LIT);
+
+ return TRUE;
+}
+
+
+static bfd_boolean
+elf_xtensa_set_private_flags (abfd, flags)
+ bfd *abfd;
+ flagword flags;
+{
+ BFD_ASSERT (!elf_flags_init (abfd)
+ || elf_elfheader (abfd)->e_flags == flags);
+
+ elf_elfheader (abfd)->e_flags |= flags;
+ elf_flags_init (abfd) = TRUE;
+
+ return TRUE;
+}
+
+
+extern flagword
+elf_xtensa_get_private_bfd_flags (abfd)
+ bfd *abfd;
+{
+ return elf_elfheader (abfd)->e_flags;
+}
+
+
+static bfd_boolean
+elf_xtensa_print_private_bfd_data (abfd, farg)
+ bfd *abfd;
+ PTR farg;
+{
+ FILE *f = (FILE *) farg;
+ flagword e_flags = elf_elfheader (abfd)->e_flags;
+
+ fprintf (f, "\nXtensa header:\n");
+ if ((e_flags & EF_XTENSA_MACH) == E_XTENSA_MACH)
+ fprintf (f, "\nMachine = Base\n");
+ else
+ fprintf (f, "\nMachine Id = 0x%x\n", e_flags & EF_XTENSA_MACH);
+
+ fprintf (f, "Insn tables = %s\n",
+ (e_flags & EF_XTENSA_XT_INSN) ? "true" : "false");
+
+ fprintf (f, "Literal tables = %s\n",
+ (e_flags & EF_XTENSA_XT_LIT) ? "true" : "false");
+
+ return _bfd_elf_print_private_bfd_data (abfd, farg);
+}
+
+
+/* Set the right machine number for an Xtensa ELF file. */
+
+static bfd_boolean
+elf_xtensa_object_p (abfd)
+ bfd *abfd;
+{
+ int mach;
+ unsigned long arch = elf_elfheader (abfd)->e_flags & EF_XTENSA_MACH;
+
+ switch (arch)
+ {
+ case E_XTENSA_MACH:
+ mach = bfd_mach_xtensa;
+ break;
+ default:
+ return FALSE;
+ }
+
+ (void) bfd_default_set_arch_mach (abfd, bfd_arch_xtensa, mach);
+ return TRUE;
+}
+
+
+/* The final processing done just before writing out an Xtensa ELF object
+ file. This gets the Xtensa architecture right based on the machine
+ number. */
+
+static void
+elf_xtensa_final_write_processing (abfd, linker)
+ bfd *abfd;
+ bfd_boolean linker ATTRIBUTE_UNUSED;
+{
+ int mach;
+ unsigned long val;
+
+ switch (mach = bfd_get_mach (abfd))
+ {
+ case bfd_mach_xtensa:
+ val = E_XTENSA_MACH;
+ break;
+ default:
+ return;
+ }
+
+ elf_elfheader (abfd)->e_flags &= (~ EF_XTENSA_MACH);
+ elf_elfheader (abfd)->e_flags |= val;
+}
+
+
+static enum elf_reloc_type_class
+elf_xtensa_reloc_type_class (rela)
+ const Elf_Internal_Rela *rela;
+{
+ switch ((int) ELF32_R_TYPE (rela->r_info))
+ {
+ case R_XTENSA_RELATIVE:
+ return reloc_class_relative;
+ case R_XTENSA_JMP_SLOT:
+ return reloc_class_plt;
+ default:
+ return reloc_class_normal;
+ }
+}
+
+
+static bfd_boolean
+elf_xtensa_discard_info_for_section (abfd, cookie, info, sec)
+ bfd *abfd;
+ struct elf_reloc_cookie *cookie;
+ struct bfd_link_info *info;
+ asection *sec;
+{
+ bfd_byte *contents;
+ bfd_vma section_size;
+ bfd_vma offset, actual_offset;
+ size_t removed_bytes = 0;
+
+ section_size = (sec->_cooked_size ? sec->_cooked_size : sec->_raw_size);
+ if (section_size == 0 || section_size % 8 != 0)
+ return FALSE;
+
+ if (sec->output_section
+ && bfd_is_abs_section (sec->output_section))
+ return FALSE;
+
+ contents = retrieve_contents (abfd, sec, info->keep_memory);
+ if (!contents)
+ return FALSE;
+
+ cookie->rels = retrieve_internal_relocs (abfd, sec, info->keep_memory);
+ if (!cookie->rels)
+ {
+ release_contents (sec, contents);
+ return FALSE;
+ }
+
+ cookie->rel = cookie->rels;
+ cookie->relend = cookie->rels + sec->reloc_count;
+
+ for (offset = 0; offset < section_size; offset += 8)
+ {
+ actual_offset = offset - removed_bytes;
+
+ /* The ...symbol_deleted_p function will skip over relocs but it
+ won't adjust their offsets, so do that here. */
+ while (cookie->rel < cookie->relend
+ && cookie->rel->r_offset < offset)
+ {
+ cookie->rel->r_offset -= removed_bytes;
+ cookie->rel++;
+ }
+
+ while (cookie->rel < cookie->relend
+ && cookie->rel->r_offset == offset)
+ {
+ if (_bfd_elf32_reloc_symbol_deleted_p (offset, cookie))
+ {
+ /* Remove the table entry. (If the reloc type is NONE, then
+ the entry has already been merged with another and deleted
+ during relaxation.) */
+ if (ELF32_R_TYPE (cookie->rel->r_info) != R_XTENSA_NONE)
+ {
+ /* Shift the contents up. */
+ if (offset + 8 < section_size)
+ memmove (&contents[actual_offset],
+ &contents[actual_offset+8],
+ section_size - offset - 8);
+ removed_bytes += 8;
+ }
+
+ /* Remove this relocation. */
+ cookie->rel->r_info = ELF32_R_INFO (0, R_XTENSA_NONE);
+ }
+
+ /* Adjust the relocation offset for previous removals. This
+ should not be done before calling ...symbol_deleted_p
+ because it might mess up the offset comparisons there.
+ Make sure the offset doesn't underflow in the case where
+ the first entry is removed. */
+ if (cookie->rel->r_offset >= removed_bytes)
+ cookie->rel->r_offset -= removed_bytes;
+ else
+ cookie->rel->r_offset = 0;
+
+ cookie->rel++;
+ }
+ }
+
+ if (removed_bytes != 0)
+ {
+ /* Adjust any remaining relocs (shouldn't be any). */
+ for (; cookie->rel < cookie->relend; cookie->rel++)
+ {
+ if (cookie->rel->r_offset >= removed_bytes)
+ cookie->rel->r_offset -= removed_bytes;
+ else
+ cookie->rel->r_offset = 0;
+ }
+
+ /* Clear the removed bytes. */
+ memset (&contents[section_size - removed_bytes], 0, removed_bytes);
+
+ pin_contents (sec, contents);
+ pin_internal_relocs (sec, cookie->rels);
+
+ sec->_cooked_size = section_size - removed_bytes;
+ /* Also shrink _raw_size. See comments in relax_property_section. */
+ sec->_raw_size = sec->_cooked_size;
+ }
+ else
+ {
+ release_contents (sec, contents);
+ release_internal_relocs (sec, cookie->rels);
+ }
+
+ return (removed_bytes != 0);
+}
+
+
+static bfd_boolean
+elf_xtensa_discard_info (abfd, cookie, info)
+ bfd *abfd;
+ struct elf_reloc_cookie *cookie;
+ struct bfd_link_info *info;
+{
+ asection *sec;
+ bfd_boolean changed = FALSE;
+
+ for (sec = abfd->sections; sec != NULL; sec = sec->next)
+ {
+ if (xtensa_is_property_section (sec))
+ {
+ if (elf_xtensa_discard_info_for_section (abfd, cookie, info, sec))
+ changed = TRUE;
+ }
+ }
+
+ return changed;
+}
+
+
+static bfd_boolean
+elf_xtensa_ignore_discarded_relocs (sec)
+ asection *sec;
+{
+ return xtensa_is_property_section (sec);
+}
+
+
+/* Support for core dump NOTE sections. */
+
+static bfd_boolean
+elf_xtensa_grok_prstatus (abfd, note)
+ bfd *abfd;
+ Elf_Internal_Note *note;
+{
+ int offset;
+ unsigned int raw_size;
+
+ /* The size for Xtensa is variable, so don't try to recognize the format
+ based on the size. Just assume this is GNU/Linux. */
+
+ /* pr_cursig */
+ elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12);
+
+ /* pr_pid */
+ elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 24);
+
+ /* pr_reg */
+ offset = 72;
+ raw_size = note->descsz - offset - 4;
+
+ /* Make a ".reg/999" section. */
+ return _bfd_elfcore_make_pseudosection (abfd, ".reg",
+ raw_size, note->descpos + offset);
+}
+
+
+static bfd_boolean
+elf_xtensa_grok_psinfo (abfd, note)
+ bfd *abfd;
+ Elf_Internal_Note *note;
+{
+ switch (note->descsz)
+ {
+ default:
+ return FALSE;
+
+ case 128: /* GNU/Linux elf_prpsinfo */
+ elf_tdata (abfd)->core_program
+ = _bfd_elfcore_strndup (abfd, note->descdata + 32, 16);
+ elf_tdata (abfd)->core_command
+ = _bfd_elfcore_strndup (abfd, note->descdata + 48, 80);
+ }
+
+ /* Note that for some reason, a spurious space is tacked
+ onto the end of the args in some (at least one anyway)
+ implementations, so strip it off if it exists. */
+
+ {
+ char *command = elf_tdata (abfd)->core_command;
+ int n = strlen (command);
+
+ if (0 < n && command[n - 1] == ' ')
+ command[n - 1] = '\0';
+ }
+
+ return TRUE;
+}
+
+
+/* Generic Xtensa configurability stuff. */
+
+static xtensa_opcode callx0_op = XTENSA_UNDEFINED;
+static xtensa_opcode callx4_op = XTENSA_UNDEFINED;
+static xtensa_opcode callx8_op = XTENSA_UNDEFINED;
+static xtensa_opcode callx12_op = XTENSA_UNDEFINED;
+static xtensa_opcode call0_op = XTENSA_UNDEFINED;
+static xtensa_opcode call4_op = XTENSA_UNDEFINED;
+static xtensa_opcode call8_op = XTENSA_UNDEFINED;
+static xtensa_opcode call12_op = XTENSA_UNDEFINED;
+
+static void
+init_call_opcodes ()
+{
+ if (callx0_op == XTENSA_UNDEFINED)
+ {
+ callx0_op = xtensa_opcode_lookup (xtensa_default_isa, "callx0");
+ callx4_op = xtensa_opcode_lookup (xtensa_default_isa, "callx4");
+ callx8_op = xtensa_opcode_lookup (xtensa_default_isa, "callx8");
+ callx12_op = xtensa_opcode_lookup (xtensa_default_isa, "callx12");
+ call0_op = xtensa_opcode_lookup (xtensa_default_isa, "call0");
+ call4_op = xtensa_opcode_lookup (xtensa_default_isa, "call4");
+ call8_op = xtensa_opcode_lookup (xtensa_default_isa, "call8");
+ call12_op = xtensa_opcode_lookup (xtensa_default_isa, "call12");
+ }
+}
+
+
+static bfd_boolean
+is_indirect_call_opcode (opcode)
+ xtensa_opcode opcode;
+{
+ init_call_opcodes ();
+ return (opcode == callx0_op
+ || opcode == callx4_op
+ || opcode == callx8_op
+ || opcode == callx12_op);
+}
+
+
+static bfd_boolean
+is_direct_call_opcode (opcode)
+ xtensa_opcode opcode;
+{
+ init_call_opcodes ();
+ return (opcode == call0_op
+ || opcode == call4_op
+ || opcode == call8_op
+ || opcode == call12_op);
+}
+
+
+static bfd_boolean
+is_windowed_call_opcode (opcode)
+ xtensa_opcode opcode;
+{
+ init_call_opcodes ();
+ return (opcode == call4_op
+ || opcode == call8_op
+ || opcode == call12_op
+ || opcode == callx4_op
+ || opcode == callx8_op
+ || opcode == callx12_op);
+}
+
+
+static xtensa_opcode
+get_l32r_opcode (void)
+{
+ static xtensa_opcode l32r_opcode = XTENSA_UNDEFINED;
+ if (l32r_opcode == XTENSA_UNDEFINED)
+ {
+ l32r_opcode = xtensa_opcode_lookup (xtensa_default_isa, "l32r");
+ BFD_ASSERT (l32r_opcode != XTENSA_UNDEFINED);
+ }
+ return l32r_opcode;
+}
+
+
+static bfd_vma
+l32r_offset (addr, pc)
+ bfd_vma addr;
+ bfd_vma pc;
+{
+ bfd_vma offset;
+
+ offset = addr - ((pc+3) & -4);
+ BFD_ASSERT ((offset & ((1 << 2) - 1)) == 0);
+ offset = (signed int) offset >> 2;
+ BFD_ASSERT ((signed int) offset >> 16 == -1);
+ return offset;
+}
+
+
+/* Get the operand number for a PC-relative relocation.
+ If the relocation is not a PC-relative one, return (-1). */
+
+static int
+get_relocation_opnd (irel)
+ Elf_Internal_Rela *irel;
+{
+ if (ELF32_R_TYPE (irel->r_info) < R_XTENSA_OP0
+ || ELF32_R_TYPE (irel->r_info) >= R_XTENSA_max)
+ return -1;
+ return ELF32_R_TYPE (irel->r_info) - R_XTENSA_OP0;
+}
+
+
+/* Get the opcode for a relocation. */
+
+static xtensa_opcode
+get_relocation_opcode (sec, contents, irel)
+ asection *sec;
+ bfd_byte *contents;
+ Elf_Internal_Rela *irel;
+{
+ static xtensa_insnbuf ibuff = NULL;
+ xtensa_isa isa = xtensa_default_isa;
+
+ if (get_relocation_opnd (irel) == -1)
+ return XTENSA_UNDEFINED;
+
+ if (contents == NULL)
+ return XTENSA_UNDEFINED;
+
+ if (sec->_raw_size <= irel->r_offset)
+ return XTENSA_UNDEFINED;
+
+ if (ibuff == NULL)
+ ibuff = xtensa_insnbuf_alloc (isa);
+
+ /* Decode the instruction. */
+ xtensa_insnbuf_from_chars (isa, ibuff, &contents[irel->r_offset]);
+ return xtensa_decode_insn (isa, ibuff);
+}
+
+
+bfd_boolean
+is_l32r_relocation (sec, contents, irel)
+ asection *sec;
+ bfd_byte *contents;
+ Elf_Internal_Rela *irel;
+{
+ xtensa_opcode opcode;
+
+ if (ELF32_R_TYPE (irel->r_info) != R_XTENSA_OP1)
+ return FALSE;
+
+ opcode = get_relocation_opcode (sec, contents, irel);
+ return (opcode == get_l32r_opcode ());
+}
+
+
+/* Code for transforming CALLs at link-time. */
+
+static bfd_reloc_status_type
+elf_xtensa_do_asm_simplify (contents, address, content_length)
+ bfd_byte *contents;
+ bfd_vma address;
+ bfd_vma content_length;
+{
+ static xtensa_insnbuf insnbuf = NULL;
+ xtensa_opcode opcode;
+ xtensa_operand operand;
+ xtensa_opcode direct_call_opcode;
+ xtensa_isa isa = xtensa_default_isa;
+ bfd_byte *chbuf = contents + address;
+ int opn;
+
+ if (insnbuf == NULL)
+ insnbuf = xtensa_insnbuf_alloc (isa);
+
+ if (content_length < address)
+ {
+ (*_bfd_error_handler)
+ ("Attempt to convert L32R/CALLX to CALL failed\n");
+ return bfd_reloc_other;
+ }
+
+ opcode = get_expanded_call_opcode (chbuf, content_length - address);
+ direct_call_opcode = swap_callx_for_call_opcode (opcode);
+ if (direct_call_opcode == XTENSA_UNDEFINED)
+ {
+ (*_bfd_error_handler)
+ ("Attempt to convert L32R/CALLX to CALL failed\n");
+ return bfd_reloc_other;
+ }
+
+ /* Assemble a NOP ("or a1, a1, a1") into the 0 byte offset. */
+ opcode = xtensa_opcode_lookup (isa, "or");
+ xtensa_encode_insn (isa, opcode, insnbuf);
+ for (opn = 0; opn < 3; opn++)
+ {
+ operand = xtensa_get_operand (isa, opcode, opn);
+ xtensa_operand_set_field (operand, insnbuf, 1);
+ }
+ xtensa_insnbuf_to_chars (isa, insnbuf, chbuf);
+
+ /* Assemble a CALL ("callN 0") into the 3 byte offset. */
+ xtensa_encode_insn (isa, direct_call_opcode, insnbuf);
+ operand = xtensa_get_operand (isa, opcode, 0);
+ xtensa_operand_set_field (operand, insnbuf, 0);
+ xtensa_insnbuf_to_chars (isa, insnbuf, chbuf + 3);
+
+ return bfd_reloc_ok;
+}
+
+
+static bfd_reloc_status_type
+contract_asm_expansion (contents, content_length, irel)
+ bfd_byte *contents;
+ bfd_vma content_length;
+ Elf_Internal_Rela *irel;
+{
+ bfd_reloc_status_type retval =
+ elf_xtensa_do_asm_simplify (contents, irel->r_offset, content_length);
+
+ if (retval != bfd_reloc_ok)
+ return retval;
+
+ /* Update the irel->r_offset field so that the right immediate and
+ the right instruction are modified during the relocation. */
+ irel->r_offset += 3;
+ irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), R_XTENSA_OP0);
+ return bfd_reloc_ok;
+}
+
+
+static xtensa_opcode
+swap_callx_for_call_opcode (opcode)
+ xtensa_opcode opcode;
+{
+ init_call_opcodes ();
+
+ if (opcode == callx0_op) return call0_op;
+ if (opcode == callx4_op) return call4_op;
+ if (opcode == callx8_op) return call8_op;
+ if (opcode == callx12_op) return call12_op;
+
+ /* Return XTENSA_UNDEFINED if the opcode is not an indirect call. */
+ return XTENSA_UNDEFINED;
+}
+
+
+/* Check if "buf" is pointing to a "L32R aN; CALLX aN" sequence, and
+ if so, return the CALLX opcode. If not, return XTENSA_UNDEFINED. */
+
+#define L32R_TARGET_REG_OPERAND 0
+#define CALLN_SOURCE_OPERAND 0
+
+static xtensa_opcode
+get_expanded_call_opcode (buf, bufsize)
+ bfd_byte *buf;
+ int bufsize;
+{
+ static xtensa_insnbuf insnbuf = NULL;
+ xtensa_opcode opcode;
+ xtensa_operand operand;
+ xtensa_isa isa = xtensa_default_isa;
+ uint32 regno, call_regno;
+
+ /* Buffer must be at least 6 bytes. */
+ if (bufsize < 6)
+ return XTENSA_UNDEFINED;
+
+ if (insnbuf == NULL)
+ insnbuf = xtensa_insnbuf_alloc (isa);
+
+ xtensa_insnbuf_from_chars (isa, insnbuf, buf);
+ opcode = xtensa_decode_insn (isa, insnbuf);
+
+ if (opcode != get_l32r_opcode ())
+ return XTENSA_UNDEFINED;
+
+ operand = xtensa_get_operand (isa, opcode, L32R_TARGET_REG_OPERAND);
+ regno = xtensa_operand_decode
+ (operand, xtensa_operand_get_field (operand, insnbuf));
+
+ /* Next instruction should be an CALLXn with operand 0 == regno. */
+ xtensa_insnbuf_from_chars (isa, insnbuf,
+ buf + xtensa_insn_length (isa, opcode));
+ opcode = xtensa_decode_insn (isa, insnbuf);
+
+ if (!is_indirect_call_opcode (opcode))
+ return XTENSA_UNDEFINED;
+
+ operand = xtensa_get_operand (isa, opcode, CALLN_SOURCE_OPERAND);
+ call_regno = xtensa_operand_decode
+ (operand, xtensa_operand_get_field (operand, insnbuf));
+ if (call_regno != regno)
+ return XTENSA_UNDEFINED;
+
+ return opcode;
+}
+
+
+/* Data structures used during relaxation. */
+
+/* r_reloc: relocation values. */
+
+/* Through the relaxation process, we need to keep track of the values
+ that will result from evaluating relocations. The standard ELF
+ relocation structure is not sufficient for this purpose because we're
+ operating on multiple input files at once, so we need to know which
+ input file a relocation refers to. The r_reloc structure thus
+ records both the input file (bfd) and ELF relocation.
+
+ For efficiency, an r_reloc also contains a "target_offset" field to
+ cache the target-section-relative offset value that is represented by
+ the relocation. */
+
+typedef struct r_reloc_struct r_reloc;
+
+struct r_reloc_struct
+{
+ bfd *abfd;
+ Elf_Internal_Rela rela;
+ bfd_vma target_offset;
+};
+
+static bfd_boolean r_reloc_is_const
+ PARAMS ((const r_reloc *));
+static void r_reloc_init
+ PARAMS ((r_reloc *, bfd *, Elf_Internal_Rela *));
+static bfd_vma r_reloc_get_target_offset
+ PARAMS ((const r_reloc *));
+static asection *r_reloc_get_section
+ PARAMS ((const r_reloc *));
+static bfd_boolean r_reloc_is_defined
+ PARAMS ((const r_reloc *));
+static struct elf_link_hash_entry *r_reloc_get_hash_entry
+ PARAMS ((const r_reloc *));
+
+
+/* The r_reloc structure is included by value in literal_value, but not
+ every literal_value has an associated relocation -- some are simple
+ constants. In such cases, we set all the fields in the r_reloc
+ struct to zero. The r_reloc_is_const function should be used to
+ detect this case. */
+
+static bfd_boolean
+r_reloc_is_const (r_rel)
+ const r_reloc *r_rel;
+{
+ return (r_rel->abfd == NULL);
+}
+
+
+static void
+r_reloc_init (r_rel, abfd, irel)
+ r_reloc *r_rel;
+ bfd *abfd;
+ Elf_Internal_Rela *irel;
+{
+ if (irel != NULL)
+ {
+ r_rel->rela = *irel;
+ r_rel->abfd = abfd;
+ r_rel->target_offset = r_reloc_get_target_offset (r_rel);
+ }
+ else
+ memset (r_rel, 0, sizeof (r_reloc));
+}
+
+
+static bfd_vma
+r_reloc_get_target_offset (r_rel)
+ const r_reloc *r_rel;
+{
+ bfd_vma target_offset;
+ unsigned long r_symndx;
+
+ BFD_ASSERT (!r_reloc_is_const (r_rel));
+ r_symndx = ELF32_R_SYM (r_rel->rela.r_info);
+ target_offset = get_elf_r_symndx_offset (r_rel->abfd, r_symndx);
+ return (target_offset + r_rel->rela.r_addend);
+}
+
+
+static struct elf_link_hash_entry *
+r_reloc_get_hash_entry (r_rel)
+ const r_reloc *r_rel;
+{
+ unsigned long r_symndx = ELF32_R_SYM (r_rel->rela.r_info);
+ return get_elf_r_symndx_hash_entry (r_rel->abfd, r_symndx);
+}
+
+
+static asection *
+r_reloc_get_section (r_rel)
+ const r_reloc *r_rel;
+{
+ unsigned long r_symndx = ELF32_R_SYM (r_rel->rela.r_info);
+ return get_elf_r_symndx_section (r_rel->abfd, r_symndx);
+}
+
+
+static bfd_boolean
+r_reloc_is_defined (r_rel)
+ const r_reloc *r_rel;
+{
+ asection *sec = r_reloc_get_section (r_rel);
+ if (sec == bfd_abs_section_ptr
+ || sec == bfd_com_section_ptr
+ || sec == bfd_und_section_ptr)
+ return FALSE;
+ return TRUE;
+}
+
+
+/* source_reloc: relocations that reference literal sections. */
+
+/* To determine whether literals can be coalesced, we need to first
+ record all the relocations that reference the literals. The
+ source_reloc structure below is used for this purpose. The
+ source_reloc entries are kept in a per-literal-section array, sorted
+ by offset within the literal section (i.e., target offset).
+
+ The source_sec and r_rel.rela.r_offset fields identify the source of
+ the relocation. The r_rel field records the relocation value, i.e.,
+ the offset of the literal being referenced. The opnd field is needed
+ to determine the range of the immediate field to which the relocation
+ applies, so we can determine whether another literal with the same
+ value is within range. The is_null field is true when the relocation
+ is being removed (e.g., when an L32R is being removed due to a CALLX
+ that is converted to a direct CALL). */
+
+typedef struct source_reloc_struct source_reloc;
+
+struct source_reloc_struct
+{
+ asection *source_sec;
+ r_reloc r_rel;
+ xtensa_operand opnd;
+ bfd_boolean is_null;
+};
+
+
+static void init_source_reloc
+ PARAMS ((source_reloc *, asection *, const r_reloc *, xtensa_operand));
+static source_reloc *find_source_reloc
+ PARAMS ((source_reloc *, int, asection *, Elf_Internal_Rela *));
+static int source_reloc_compare
+ PARAMS ((const PTR, const PTR));
+
+
+static void
+init_source_reloc (reloc, source_sec, r_rel, opnd)
+ source_reloc *reloc;
+ asection *source_sec;
+ const r_reloc *r_rel;
+ xtensa_operand opnd;
+{
+ reloc->source_sec = source_sec;
+ reloc->r_rel = *r_rel;
+ reloc->opnd = opnd;
+ reloc->is_null = FALSE;
+}
+
+
+/* Find the source_reloc for a particular source offset and relocation
+ type. Note that the array is sorted by _target_ offset, so this is
+ just a linear search. */
+
+static source_reloc *
+find_source_reloc (src_relocs, src_count, sec, irel)
+ source_reloc *src_relocs;
+ int src_count;
+ asection *sec;
+ Elf_Internal_Rela *irel;
+{
+ int i;
+
+ for (i = 0; i < src_count; i++)
+ {
+ if (src_relocs[i].source_sec == sec
+ && src_relocs[i].r_rel.rela.r_offset == irel->r_offset
+ && (ELF32_R_TYPE (src_relocs[i].r_rel.rela.r_info)
+ == ELF32_R_TYPE (irel->r_info)))
+ return &src_relocs[i];
+ }
+
+ return NULL;
+}
+
+
+static int
+source_reloc_compare (ap, bp)
+ const PTR ap;
+ const PTR bp;
+{
+ const source_reloc *a = (const source_reloc *) ap;
+ const source_reloc *b = (const source_reloc *) bp;
+
+ return (a->r_rel.target_offset - b->r_rel.target_offset);
+}
+
+
+/* Literal values and value hash tables. */
+
+/* Literals with the same value can be coalesced. The literal_value
+ structure records the value of a literal: the "r_rel" field holds the
+ information from the relocation on the literal (if there is one) and
+ the "value" field holds the contents of the literal word itself.
+
+ The value_map structure records a literal value along with the
+ location of a literal holding that value. The value_map hash table
+ is indexed by the literal value, so that we can quickly check if a
+ particular literal value has been seen before and is thus a candidate
+ for coalescing. */
+
+typedef struct literal_value_struct literal_value;
+typedef struct value_map_struct value_map;
+typedef struct value_map_hash_table_struct value_map_hash_table;
+
+struct literal_value_struct
+{
+ r_reloc r_rel;
+ unsigned long value;
+};
+
+struct value_map_struct
+{
+ literal_value val; /* The literal value. */
+ r_reloc loc; /* Location of the literal. */
+ value_map *next;
+};
+
+struct value_map_hash_table_struct
+{
+ unsigned bucket_count;
+ value_map **buckets;
+ unsigned count;
+};
+
+
+static bfd_boolean is_same_value
+ PARAMS ((const literal_value *, const literal_value *));
+static value_map_hash_table *value_map_hash_table_init
+ PARAMS ((void));
+static unsigned hash_literal_value
+ PARAMS ((const literal_value *));
+static unsigned hash_bfd_vma
+ PARAMS ((bfd_vma));
+static value_map *get_cached_value
+ PARAMS ((value_map_hash_table *, const literal_value *));
+static value_map *add_value_map
+ PARAMS ((value_map_hash_table *, const literal_value *, const r_reloc *));
+
+
+static bfd_boolean
+is_same_value (src1, src2)
+ const literal_value *src1;
+ const literal_value *src2;
+{
+ if (r_reloc_is_const (&src1->r_rel) != r_reloc_is_const (&src2->r_rel))
+ return FALSE;
+
+ if (r_reloc_is_const (&src1->r_rel))
+ return (src1->value == src2->value);
+
+ if (ELF32_R_TYPE (src1->r_rel.rela.r_info)
+ != ELF32_R_TYPE (src2->r_rel.rela.r_info))
+ return FALSE;
+
+ if (r_reloc_get_target_offset (&src1->r_rel)
+ != r_reloc_get_target_offset (&src2->r_rel))
+ return FALSE;
+
+ if (src1->value != src2->value)
+ return FALSE;
+
+ /* Now check for the same section and the same elf_hash. */
+ if (r_reloc_is_defined (&src1->r_rel))
+ {
+ if (r_reloc_get_section (&src1->r_rel)
+ != r_reloc_get_section (&src2->r_rel))
+ return FALSE;
+ }
+ else
+ {
+ if (r_reloc_get_hash_entry (&src1->r_rel)
+ != r_reloc_get_hash_entry (&src2->r_rel))
+ return FALSE;
+
+ if (r_reloc_get_hash_entry (&src1->r_rel) == 0)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/* Must be power of 2. */
+#define INITIAL_HASH_RELOC_BUCKET_COUNT 1024
+
+static value_map_hash_table *
+value_map_hash_table_init ()
+{
+ value_map_hash_table *values;
+
+ values = (value_map_hash_table *)
+ bfd_malloc (sizeof (value_map_hash_table));
+
+ values->bucket_count = INITIAL_HASH_RELOC_BUCKET_COUNT;
+ values->count = 0;
+ values->buckets = (value_map **)
+ bfd_zmalloc (sizeof (value_map *) * values->bucket_count);
+
+ return values;
+}
+
+
+static unsigned
+hash_bfd_vma (val)
+ bfd_vma val;
+{
+ return (val >> 2) + (val >> 10);
+}
+
+
+static unsigned
+hash_literal_value (src)
+ const literal_value *src;
+{
+ unsigned hash_val;
+ if (r_reloc_is_const (&src->r_rel))
+ return hash_bfd_vma (src->value);
+
+ hash_val = (hash_bfd_vma (r_reloc_get_target_offset (&src->r_rel))
+ + hash_bfd_vma (src->value));
+
+ /* Now check for the same section and the same elf_hash. */
+ if (r_reloc_is_defined (&src->r_rel))
+ hash_val += hash_bfd_vma ((bfd_vma) r_reloc_get_section (&src->r_rel));
+ else
+ hash_val += hash_bfd_vma ((bfd_vma) r_reloc_get_hash_entry (&src->r_rel));
+
+ return hash_val;
+}
+
+
+/* Check if the specified literal_value has been seen before. */
+
+static value_map *
+get_cached_value (map, val)
+ value_map_hash_table *map;
+ const literal_value *val;
+{
+ value_map *map_e;
+ value_map *bucket;
+ unsigned idx;
+
+ idx = hash_literal_value (val);
+ idx = idx & (map->bucket_count - 1);
+ bucket = map->buckets[idx];
+ for (map_e = bucket; map_e; map_e = map_e->next)
+ {
+ if (is_same_value (&map_e->val, val))
+ return map_e;
+ }
+ return NULL;
+}
+
+
+/* Record a new literal value. It is illegal to call this if VALUE
+ already has an entry here. */
+
+static value_map *
+add_value_map (map, val, loc)
+ value_map_hash_table *map;
+ const literal_value *val;
+ const r_reloc *loc;
+{
+ value_map **bucket_p;
+ unsigned idx;
+
+ value_map *val_e = (value_map *) bfd_zmalloc (sizeof (value_map));
+
+ BFD_ASSERT (get_cached_value (map, val) == NULL);
+ val_e->val = *val;
+ val_e->loc = *loc;
+
+ idx = hash_literal_value (val);
+ idx = idx & (map->bucket_count - 1);
+ bucket_p = &map->buckets[idx];
+
+ val_e->next = *bucket_p;
+ *bucket_p = val_e;
+ map->count++;
+ /* FIXME: consider resizing the hash table if we get too many entries */
+
+ return val_e;
+}
+
+
+/* Lists of literals being coalesced or removed. */
+
+/* In the usual case, the literal identified by "from" is being
+ coalesced with another literal identified by "to". If the literal is
+ unused and is being removed altogether, "to.abfd" will be NULL.
+ The removed_literal entries are kept on a per-section list, sorted
+ by the "from" offset field. */
+
+typedef struct removed_literal_struct removed_literal;
+typedef struct removed_literal_list_struct removed_literal_list;
+
+struct removed_literal_struct
+{
+ r_reloc from;
+ r_reloc to;
+ removed_literal *next;
+};
+
+struct removed_literal_list_struct
+{
+ removed_literal *head;
+ removed_literal *tail;
+};
+
+
+static void add_removed_literal
+ PARAMS ((removed_literal_list *, const r_reloc *, const r_reloc *));
+static removed_literal *find_removed_literal
+ PARAMS ((removed_literal_list *, bfd_vma));
+static bfd_vma offset_with_removed_literals
+ PARAMS ((removed_literal_list *, bfd_vma));
+
+
+/* Record that the literal at "from" is being removed. If "to" is not
+ NULL, the "from" literal is being coalesced with the "to" literal. */
+
+static void
+add_removed_literal (removed_list, from, to)
+ removed_literal_list *removed_list;
+ const r_reloc *from;
+ const r_reloc *to;
+{
+ removed_literal *r, *new_r, *next_r;
+
+ new_r = (removed_literal *) bfd_zmalloc (sizeof (removed_literal));
+
+ new_r->from = *from;
+ if (to)
+ new_r->to = *to;
+ else
+ new_r->to.abfd = NULL;
+ new_r->next = NULL;
+
+ r = removed_list->head;
+ if (r == NULL)
+ {
+ removed_list->head = new_r;
+ removed_list->tail = new_r;
+ }
+ /* Special check for common case of append. */
+ else if (removed_list->tail->from.target_offset < from->target_offset)
+ {
+ removed_list->tail->next = new_r;
+ removed_list->tail = new_r;
+ }
+ else
+ {
+ while (r->from.target_offset < from->target_offset
+ && r->next != NULL)
+ {
+ r = r->next;
+ }
+ next_r = r->next;
+ r->next = new_r;
+ new_r->next = next_r;
+ if (next_r == NULL)
+ removed_list->tail = new_r;
+ }
+}
+
+
+/* Check if the list of removed literals contains an entry for the
+ given address. Return the entry if found. */
+
+static removed_literal *
+find_removed_literal (removed_list, addr)
+ removed_literal_list *removed_list;
+ bfd_vma addr;
+{
+ removed_literal *r = removed_list->head;
+ while (r && r->from.target_offset < addr)
+ r = r->next;
+ if (r && r->from.target_offset == addr)
+ return r;
+ return NULL;
+}
+
+
+/* Adjust an offset in a section to compensate for literals that are
+ being removed. Search the list of removed literals and subtract
+ 4 bytes for every removed literal prior to the given address. */
+
+static bfd_vma
+offset_with_removed_literals (removed_list, addr)
+ removed_literal_list *removed_list;
+ bfd_vma addr;
+{
+ removed_literal *r = removed_list->head;
+ unsigned num_bytes = 0;
+
+ if (r == NULL)
+ return addr;
+
+ while (r && r->from.target_offset <= addr)
+ {
+ num_bytes += 4;
+ r = r->next;
+ }
+ if (num_bytes > addr)
+ return 0;
+ return (addr - num_bytes);
+}
+
+
+/* Coalescing literals may require a relocation to refer to a section in
+ a different input file, but the standard relocation information
+ cannot express that. Instead, the reloc_bfd_fix structures are used
+ to "fix" the relocations that refer to sections in other input files.
+ These structures are kept on per-section lists. The "src_type" field
+ records the relocation type in case there are multiple relocations on
+ the same location. FIXME: This is ugly; an alternative might be to
+ add new symbols with the "owner" field to some other input file. */
+
+typedef struct reloc_bfd_fix_struct reloc_bfd_fix;
+
+struct reloc_bfd_fix_struct
+{
+ asection *src_sec;
+ bfd_vma src_offset;
+ unsigned src_type; /* Relocation type. */
+
+ bfd *target_abfd;
+ asection *target_sec;
+ bfd_vma target_offset;
+
+ reloc_bfd_fix *next;
+};
+
+
+static reloc_bfd_fix *reloc_bfd_fix_init
+ PARAMS ((asection *, bfd_vma, unsigned, bfd *, asection *, bfd_vma));
+static reloc_bfd_fix *get_bfd_fix
+ PARAMS ((reloc_bfd_fix *, asection *, bfd_vma, unsigned));
+
+
+static reloc_bfd_fix *
+reloc_bfd_fix_init (src_sec, src_offset, src_type,
+ target_abfd, target_sec, target_offset)
+ asection *src_sec;
+ bfd_vma src_offset;
+ unsigned src_type;
+ bfd *target_abfd;
+ asection *target_sec;
+ bfd_vma target_offset;
+{
+ reloc_bfd_fix *fix;
+
+ fix = (reloc_bfd_fix *) bfd_malloc (sizeof (reloc_bfd_fix));
+ fix->src_sec = src_sec;
+ fix->src_offset = src_offset;
+ fix->src_type = src_type;
+ fix->target_abfd = target_abfd;
+ fix->target_sec = target_sec;
+ fix->target_offset = target_offset;
+
+ return fix;
+}
+
+
+static reloc_bfd_fix *
+get_bfd_fix (fix_list, sec, offset, type)
+ reloc_bfd_fix *fix_list;
+ asection *sec;
+ bfd_vma offset;
+ unsigned type;
+{
+ reloc_bfd_fix *r;
+
+ for (r = fix_list; r != NULL; r = r->next)
+ {
+ if (r->src_sec == sec
+ && r->src_offset == offset
+ && r->src_type == type)
+ return r;
+ }
+ return NULL;
+}
+
+
+/* Per-section data for relaxation. */
+
+struct xtensa_relax_info_struct
+{
+ bfd_boolean is_relaxable_literal_section;
+ int visited; /* Number of times visited. */
+
+ source_reloc *src_relocs; /* Array[src_count]. */
+ int src_count;
+ int src_next; /* Next src_relocs entry to assign. */
+
+ removed_literal_list removed_list;
+
+ reloc_bfd_fix *fix_list;
+};
+
+struct elf_xtensa_section_data
+{
+ struct bfd_elf_section_data elf;
+ xtensa_relax_info relax_info;
+};
+
+static void init_xtensa_relax_info
+ PARAMS ((asection *));
+static xtensa_relax_info *get_xtensa_relax_info
+ PARAMS ((asection *));
+static void add_fix
+ PARAMS ((asection *, reloc_bfd_fix *));
+
+
+static bfd_boolean
+elf_xtensa_new_section_hook (abfd, sec)
+ bfd *abfd;
+ asection *sec;
+{
+ struct elf_xtensa_section_data *sdata;
+ bfd_size_type amt = sizeof (*sdata);
+
+ sdata = (struct elf_xtensa_section_data *) bfd_zalloc (abfd, amt);
+ if (sdata == NULL)
+ return FALSE;
+ sec->used_by_bfd = (PTR) sdata;
+
+ return _bfd_elf_new_section_hook (abfd, sec);
+}
+
+
+static void
+init_xtensa_relax_info (sec)
+ asection *sec;
+{
+ xtensa_relax_info *relax_info = get_xtensa_relax_info (sec);
+
+ relax_info->is_relaxable_literal_section = FALSE;
+ relax_info->visited = 0;
+
+ relax_info->src_relocs = NULL;
+ relax_info->src_count = 0;
+ relax_info->src_next = 0;
+
+ relax_info->removed_list.head = NULL;
+ relax_info->removed_list.tail = NULL;
+
+ relax_info->fix_list = NULL;
+}
+
+
+static xtensa_relax_info *
+get_xtensa_relax_info (sec)
+ asection *sec;
+{
+ struct elf_xtensa_section_data *section_data;
+
+ /* No info available if no section or if it is an output section. */
+ if (!sec || sec == sec->output_section)
+ return NULL;
+
+ section_data = (struct elf_xtensa_section_data *) elf_section_data (sec);
+ return &section_data->relax_info;
+}
+
+
+static void
+add_fix (src_sec, fix)
+ asection *src_sec;
+ reloc_bfd_fix *fix;
+{
+ xtensa_relax_info *relax_info;
+
+ relax_info = get_xtensa_relax_info (src_sec);
+ fix->next = relax_info->fix_list;
+ relax_info->fix_list = fix;
+}
+
+
+/* Access to internal relocations, section contents and symbols. */
+
+/* During relaxation, we need to modify relocations, section contents,
+ and symbol definitions, and we need to keep the original values from
+ being reloaded from the input files, i.e., we need to "pin" the
+ modified values in memory. We also want to continue to observe the
+ setting of the "keep-memory" flag. The following functions wrap the
+ standard BFD functions to take care of this for us. */
+
+static Elf_Internal_Rela *
+retrieve_internal_relocs (abfd, sec, keep_memory)
+ bfd *abfd;
+ asection *sec;
+ bfd_boolean keep_memory;
+{
+ Elf_Internal_Rela *internal_relocs;
+
+ if ((sec->flags & SEC_LINKER_CREATED) != 0)
+ return NULL;
+
+ internal_relocs = elf_section_data (sec)->relocs;
+ if (internal_relocs == NULL)
+ internal_relocs = (_bfd_elf32_link_read_relocs
+ (abfd, sec, (PTR) NULL, (Elf_Internal_Rela *) NULL,
+ keep_memory));
+ return internal_relocs;
+}
+
+
+static void
+pin_internal_relocs (sec, internal_relocs)
+ asection *sec;
+ Elf_Internal_Rela *internal_relocs;
+{
+ elf_section_data (sec)->relocs = internal_relocs;
+}
+
+
+static void
+release_internal_relocs (sec, internal_relocs)
+ asection *sec;
+ Elf_Internal_Rela *internal_relocs;
+{
+ if (internal_relocs
+ && elf_section_data (sec)->relocs != internal_relocs)
+ free (internal_relocs);
+}
+
+
+static bfd_byte *
+retrieve_contents (abfd, sec, keep_memory)
+ bfd *abfd;
+ asection *sec;
+ bfd_boolean keep_memory;
+{
+ bfd_byte *contents;
+
+ contents = elf_section_data (sec)->this_hdr.contents;
+
+ if (contents == NULL && sec->_raw_size != 0)
+ {
+ contents = (bfd_byte *) bfd_malloc (sec->_raw_size);
+ if (contents != NULL)
+ {
+ if (! bfd_get_section_contents (abfd, sec, contents,
+ (file_ptr) 0, sec->_raw_size))
+ {
+ free (contents);
+ return NULL;
+ }
+ if (keep_memory)
+ elf_section_data (sec)->this_hdr.contents = contents;
+ }
+ }
+ return contents;
+}
+
+
+static void
+pin_contents (sec, contents)
+ asection *sec;
+ bfd_byte *contents;
+{
+ elf_section_data (sec)->this_hdr.contents = contents;
+}
+
+
+static void
+release_contents (sec, contents)
+ asection *sec;
+ bfd_byte *contents;
+{
+ if (contents &&
+ elf_section_data (sec)->this_hdr.contents != contents)
+ free (contents);
+}
+
+
+static Elf_Internal_Sym *
+retrieve_local_syms (input_bfd)
+ bfd *input_bfd;
+{
+ Elf_Internal_Shdr *symtab_hdr;
+ Elf_Internal_Sym *isymbuf;
+ size_t locsymcount;
+
+ symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+ locsymcount = symtab_hdr->sh_info;
+
+ isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
+ if (isymbuf == NULL && locsymcount != 0)
+ isymbuf = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, locsymcount, 0,
+ NULL, NULL, NULL);
+
+ /* Save the symbols for this input file so they won't be read again. */
+ if (isymbuf && isymbuf != (Elf_Internal_Sym *) symtab_hdr->contents)
+ symtab_hdr->contents = (unsigned char *) isymbuf;
+
+ return isymbuf;
+}
+
+
+/* Code for link-time relaxation. */
+
+/* Local helper functions. */
+static bfd_boolean analyze_relocations
+ PARAMS ((struct bfd_link_info *));
+static bfd_boolean find_relaxable_sections
+ PARAMS ((bfd *, asection *, struct bfd_link_info *, bfd_boolean *));
+static bfd_boolean collect_source_relocs
+ PARAMS ((bfd *, asection *, struct bfd_link_info *));
+static bfd_boolean is_resolvable_asm_expansion
+ PARAMS ((bfd *, asection *, bfd_byte *, Elf_Internal_Rela *,
+ struct bfd_link_info *, bfd_boolean *));
+static bfd_boolean remove_literals
+ PARAMS ((bfd *, asection *, struct bfd_link_info *, value_map_hash_table *));
+static bfd_boolean relax_section
+ PARAMS ((bfd *, asection *, struct bfd_link_info *));
+static bfd_boolean relax_property_section
+ PARAMS ((bfd *, asection *, struct bfd_link_info *));
+static bfd_boolean relax_section_symbols
+ PARAMS ((bfd *, asection *));
+static bfd_boolean relocations_reach
+ PARAMS ((source_reloc *, int, const r_reloc *));
+static void translate_reloc
+ PARAMS ((const r_reloc *, r_reloc *));
+static Elf_Internal_Rela *get_irel_at_offset
+ PARAMS ((asection *, Elf_Internal_Rela *, bfd_vma));
+static Elf_Internal_Rela *find_associated_l32r_irel
+ PARAMS ((asection *, bfd_byte *, Elf_Internal_Rela *,
+ Elf_Internal_Rela *));
+static void shrink_dynamic_reloc_sections
+ PARAMS ((struct bfd_link_info *, bfd *, asection *, Elf_Internal_Rela *));
+
+
+static bfd_boolean
+elf_xtensa_relax_section (abfd, sec, link_info, again)
+ bfd *abfd;
+ asection *sec;
+ struct bfd_link_info *link_info;
+ bfd_boolean *again;
+{
+ static value_map_hash_table *values = NULL;
+ xtensa_relax_info *relax_info;
+
+ if (!values)
+ {
+ /* Do some overall initialization for relaxation. */
+ values = value_map_hash_table_init ();
+ relaxing_section = TRUE;
+ if (!analyze_relocations (link_info))
+ return FALSE;
+ }
+ *again = FALSE;
+
+ /* Don't mess with linker-created sections. */
+ if ((sec->flags & SEC_LINKER_CREATED) != 0)
+ return TRUE;
+
+ relax_info = get_xtensa_relax_info (sec);
+ BFD_ASSERT (relax_info != NULL);
+
+ switch (relax_info->visited)
+ {
+ case 0:
+ /* Note: It would be nice to fold this pass into
+ analyze_relocations, but it is important for this step that the
+ sections be examined in link order. */
+ if (!remove_literals (abfd, sec, link_info, values))
+ return FALSE;
+ *again = TRUE;
+ break;
+
+ case 1:
+ if (!relax_section (abfd, sec, link_info))
+ return FALSE;
+ *again = TRUE;
+ break;
+
+ case 2:
+ if (!relax_section_symbols (abfd, sec))
+ return FALSE;
+ break;
+ }
+
+ relax_info->visited++;
+ return TRUE;
+}
+
+/* Initialization for relaxation. */
+
+/* This function is called once at the start of relaxation. It scans
+ all the input sections and marks the ones that are relaxable (i.e.,
+ literal sections with L32R relocations against them). It then
+ collect source_reloc information for all the relocations against
+ those relaxable sections. */
+
+static bfd_boolean
+analyze_relocations (link_info)
+ struct bfd_link_info *link_info;
+{
+ bfd *abfd;
+ asection *sec;
+ bfd_boolean is_relaxable = FALSE;
+
+ /* Initialize the per-section relaxation info. */
+ for (abfd = link_info->input_bfds; abfd != NULL; abfd = abfd->link_next)
+ for (sec = abfd->sections; sec != NULL; sec = sec->next)
+ {
+ init_xtensa_relax_info (sec);
+ }
+
+ /* Mark relaxable sections (and count relocations against each one). */
+ for (abfd = link_info->input_bfds; abfd != NULL; abfd = abfd->link_next)
+ for (sec = abfd->sections; sec != NULL; sec = sec->next)
+ {
+ if (!find_relaxable_sections (abfd, sec, link_info, &is_relaxable))
+ return FALSE;
+ }
+
+ /* Bail out if there are no relaxable sections. */
+ if (!is_relaxable)
+ return TRUE;
+
+ /* Allocate space for source_relocs. */
+ for (abfd = link_info->input_bfds; abfd != NULL; abfd = abfd->link_next)
+ for (sec = abfd->sections; sec != NULL; sec = sec->next)
+ {
+ xtensa_relax_info *relax_info;
+
+ relax_info = get_xtensa_relax_info (sec);
+ if (relax_info->is_relaxable_literal_section)
+ {
+ relax_info->src_relocs = (source_reloc *)
+ bfd_malloc (relax_info->src_count * sizeof (source_reloc));
+ }
+ }
+
+ /* Collect info on relocations against each relaxable section. */
+ for (abfd = link_info->input_bfds; abfd != NULL; abfd = abfd->link_next)
+ for (sec = abfd->sections; sec != NULL; sec = sec->next)
+ {
+ if (!collect_source_relocs (abfd, sec, link_info))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/* Find all the literal sections that might be relaxed. The motivation
+ for this pass is that collect_source_relocs() needs to record _all_
+ the relocations that target each relaxable section. That is
+ expensive and unnecessary unless the target section is actually going
+ to be relaxed. This pass identifies all such sections by checking if
+ they have L32Rs pointing to them. In the process, the total number
+ of relocations targetting each section is also counted so that we
+ know how much space to allocate for source_relocs against each
+ relaxable literal section. */
+
+static bfd_boolean
+find_relaxable_sections (abfd, sec, link_info, is_relaxable_p)
+ bfd *abfd;
+ asection *sec;
+ struct bfd_link_info *link_info;
+ bfd_boolean *is_relaxable_p;
+{
+ Elf_Internal_Rela *internal_relocs;
+ bfd_byte *contents;
+ bfd_boolean ok = TRUE;
+ unsigned i;
+
+ internal_relocs = retrieve_internal_relocs (abfd, sec,
+ link_info->keep_memory);
+ if (internal_relocs == NULL)
+ return ok;
+
+ contents = retrieve_contents (abfd, sec, link_info->keep_memory);
+ if (contents == NULL && sec->_raw_size != 0)
+ {
+ ok = FALSE;
+ goto error_return;
+ }
+
+ for (i = 0; i < sec->reloc_count; i++)
+ {
+ Elf_Internal_Rela *irel = &internal_relocs[i];
+ r_reloc r_rel;
+ asection *target_sec;
+ xtensa_relax_info *target_relax_info;
+
+ r_reloc_init (&r_rel, abfd, irel);
+
+ target_sec = r_reloc_get_section (&r_rel);
+ target_relax_info = get_xtensa_relax_info (target_sec);
+ if (!target_relax_info)
+ continue;
+
+ /* Count relocations against the target section. */
+ target_relax_info->src_count++;
+
+ if (is_literal_section (target_sec)
+ && is_l32r_relocation (sec, contents, irel)
+ && r_reloc_is_defined (&r_rel))
+ {
+ /* Mark the target section as relaxable. */
+ target_relax_info->is_relaxable_literal_section = TRUE;
+ *is_relaxable_p = TRUE;
+ }
+ }
+
+ error_return:
+ release_contents (sec, contents);
+ release_internal_relocs (sec, internal_relocs);
+ return ok;
+}
+
+
+/* Record _all_ the relocations that point to relaxable literal
+ sections, and get rid of ASM_EXPAND relocs by either converting them
+ to ASM_SIMPLIFY or by removing them. */
+
+static bfd_boolean
+collect_source_relocs (abfd, sec, link_info)
+ bfd *abfd;
+ asection *sec;
+ struct bfd_link_info *link_info;
+{
+ Elf_Internal_Rela *internal_relocs;
+ bfd_byte *contents;
+ bfd_boolean ok = TRUE;
+ unsigned i;
+
+ internal_relocs = retrieve_internal_relocs (abfd, sec,
+ link_info->keep_memory);
+ if (internal_relocs == NULL)
+ return ok;
+
+ contents = retrieve_contents (abfd, sec, link_info->keep_memory);
+ if (contents == NULL && sec->_raw_size != 0)
+ {
+ ok = FALSE;
+ goto error_return;
+ }
+
+ /* Record relocations against relaxable literal sections. */
+ for (i = 0; i < sec->reloc_count; i++)
+ {
+ Elf_Internal_Rela *irel = &internal_relocs[i];
+ r_reloc r_rel;
+ asection *target_sec;
+ xtensa_relax_info *target_relax_info;
+
+ r_reloc_init (&r_rel, abfd, irel);
+
+ target_sec = r_reloc_get_section (&r_rel);
+ target_relax_info = get_xtensa_relax_info (target_sec);
+
+ if (target_relax_info
+ && target_relax_info->is_relaxable_literal_section)
+ {
+ xtensa_opcode opcode;
+ xtensa_operand opnd;
+ source_reloc *s_reloc;
+ int src_next;
+
+ src_next = target_relax_info->src_next++;
+ s_reloc = &target_relax_info->src_relocs[src_next];
+
+ opcode = get_relocation_opcode (sec, contents, irel);
+ if (opcode == XTENSA_UNDEFINED)
+ opnd = NULL;
+ else
+ opnd = xtensa_get_operand (xtensa_default_isa, opcode,
+ get_relocation_opnd (irel));
+
+ init_source_reloc (s_reloc, sec, &r_rel, opnd);
+ }
+ }
+
+ /* Now get rid of ASM_EXPAND relocations. At this point, the
+ src_relocs array for the target literal section may still be
+ incomplete, but it must at least contain the entries for the L32R
+ relocations associated with ASM_EXPANDs because they were just
+ added in the preceding loop over the relocations. */
+
+ for (i = 0; i < sec->reloc_count; i++)
+ {
+ Elf_Internal_Rela *irel = &internal_relocs[i];
+ bfd_boolean is_reachable;
+
+ if (!is_resolvable_asm_expansion (abfd, sec, contents, irel, link_info,
+ &is_reachable))
+ continue;
+
+ if (is_reachable)
+ {
+ Elf_Internal_Rela *l32r_irel;
+ r_reloc r_rel;
+ asection *target_sec;
+ xtensa_relax_info *target_relax_info;
+
+ /* Mark the source_reloc for the L32R so that it will be
+ removed in remove_literals(), along with the associated
+ literal. */
+ l32r_irel = find_associated_l32r_irel (sec, contents,
+ irel, internal_relocs);
+ if (l32r_irel == NULL)
+ continue;
+
+ r_reloc_init (&r_rel, abfd, l32r_irel);
+
+ target_sec = r_reloc_get_section (&r_rel);
+ target_relax_info = get_xtensa_relax_info (target_sec);
+
+ if (target_relax_info
+ && target_relax_info->is_relaxable_literal_section)
+ {
+ source_reloc *s_reloc;
+
+ /* Search the source_relocs for the entry corresponding to
+ the l32r_irel. Note: The src_relocs array is not yet
+ sorted, but it wouldn't matter anyway because we're
+ searching by source offset instead of target offset. */
+ s_reloc = find_source_reloc (target_relax_info->src_relocs,
+ target_relax_info->src_next,
+ sec, l32r_irel);
+ BFD_ASSERT (s_reloc);
+ s_reloc->is_null = TRUE;
+ }
+
+ /* Convert this reloc to ASM_SIMPLIFY. */
+ irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
+ R_XTENSA_ASM_SIMPLIFY);
+ l32r_irel->r_info = ELF32_R_INFO (0, R_XTENSA_NONE);
+
+ pin_internal_relocs (sec, internal_relocs);
+ }
+ else
+ {
+ /* It is resolvable but doesn't reach. We resolve now
+ by eliminating the relocation -- the call will remain
+ expanded into L32R/CALLX. */
+ irel->r_info = ELF32_R_INFO (0, R_XTENSA_NONE);
+ pin_internal_relocs (sec, internal_relocs);
+ }
+ }
+
+ error_return:
+ release_contents (sec, contents);
+ release_internal_relocs (sec, internal_relocs);
+ return ok;
+}
+
+
+/* Return TRUE if the asm expansion can be resolved. Generally it can
+ be resolved on a final link or when a partial link locates it in the
+ same section as the target. Set "is_reachable" flag if the target of
+ the call is within the range of a direct call, given the current VMA
+ for this section and the target section. */
+
+bfd_boolean
+is_resolvable_asm_expansion (abfd, sec, contents, irel, link_info,
+ is_reachable_p)
+ bfd *abfd;
+ asection *sec;
+ bfd_byte *contents;
+ Elf_Internal_Rela *irel;
+ struct bfd_link_info *link_info;
+ bfd_boolean *is_reachable_p;
+{
+ asection *target_sec;
+ bfd_vma target_offset;
+ r_reloc r_rel;
+ xtensa_opcode opcode, direct_call_opcode;
+ bfd_vma self_address;
+ bfd_vma dest_address;
+
+ *is_reachable_p = FALSE;
+
+ if (contents == NULL)
+ return FALSE;
+
+ if (ELF32_R_TYPE (irel->r_info) != R_XTENSA_ASM_EXPAND)
+ return FALSE;
+
+ opcode = get_expanded_call_opcode (contents + irel->r_offset,
+ sec->_raw_size - irel->r_offset);
+
+ direct_call_opcode = swap_callx_for_call_opcode (opcode);
+ if (direct_call_opcode == XTENSA_UNDEFINED)
+ return FALSE;
+
+ /* Check and see that the target resolves. */
+ r_reloc_init (&r_rel, abfd, irel);
+ if (!r_reloc_is_defined (&r_rel))
+ return FALSE;
+
+ target_sec = r_reloc_get_section (&r_rel);
+ target_offset = r_reloc_get_target_offset (&r_rel);
+
+ /* If the target is in a shared library, then it doesn't reach. This
+ isn't supposed to come up because the compiler should never generate
+ non-PIC calls on systems that use shared libraries, but the linker
+ shouldn't crash regardless. */
+ if (!target_sec->output_section)
+ return FALSE;
+
+ /* For relocateable sections, we can only simplify when the output
+ section of the target is the same as the output section of the
+ source. */
+ if (link_info->relocateable
+ && (target_sec->output_section != sec->output_section))
+ return FALSE;
+
+ self_address = (sec->output_section->vma
+ + sec->output_offset + irel->r_offset + 3);
+ dest_address = (target_sec->output_section->vma
+ + target_sec->output_offset + target_offset);
+
+ *is_reachable_p = pcrel_reloc_fits
+ (xtensa_get_operand (xtensa_default_isa, direct_call_opcode, 0),
+ self_address, dest_address);
+
+ if ((self_address >> CALL_SEGMENT_BITS) !=
+ (dest_address >> CALL_SEGMENT_BITS))
+ return FALSE;
+
+ return TRUE;
+}
+
+
+static Elf_Internal_Rela *
+find_associated_l32r_irel (sec, contents, other_irel, internal_relocs)
+ asection *sec;
+ bfd_byte *contents;
+ Elf_Internal_Rela *other_irel;
+ Elf_Internal_Rela *internal_relocs;
+{
+ unsigned i;
+
+ for (i = 0; i < sec->reloc_count; i++)
+ {
+ Elf_Internal_Rela *irel = &internal_relocs[i];
+
+ if (irel == other_irel)
+ continue;
+ if (irel->r_offset != other_irel->r_offset)
+ continue;
+ if (is_l32r_relocation (sec, contents, irel))
+ return irel;
+ }
+
+ return NULL;
+}
+
+/* First relaxation pass. */
+
+/* If the section is relaxable (i.e., a literal section), check each
+ literal to see if it has the same value as another literal that has
+ already been seen, either in the current section or a previous one.
+ If so, add an entry to the per-section list of removed literals. The
+ actual changes are deferred until the next pass. */
+
+static bfd_boolean
+remove_literals (abfd, sec, link_info, values)
+ bfd *abfd;
+ asection *sec;
+ struct bfd_link_info *link_info;
+ value_map_hash_table *values;
+{
+ xtensa_relax_info *relax_info;
+ bfd_byte *contents;
+ Elf_Internal_Rela *internal_relocs;
+ source_reloc *src_relocs;
+ bfd_boolean ok = TRUE;
+ int i;
+
+ /* Do nothing if it is not a relaxable literal section. */
+ relax_info = get_xtensa_relax_info (sec);
+ BFD_ASSERT (relax_info);
+
+ if (!relax_info->is_relaxable_literal_section)
+ return ok;
+
+ internal_relocs = retrieve_internal_relocs (abfd, sec,
+ link_info->keep_memory);
+
+ contents = retrieve_contents (abfd, sec, link_info->keep_memory);
+ if (contents == NULL && sec->_raw_size != 0)
+ {
+ ok = FALSE;
+ goto error_return;
+ }
+
+ /* Sort the source_relocs by target offset. */
+ src_relocs = relax_info->src_relocs;
+ qsort (src_relocs, relax_info->src_count,
+ sizeof (source_reloc), source_reloc_compare);
+
+ for (i = 0; i < relax_info->src_count; i++)
+ {
+ source_reloc *rel;
+ Elf_Internal_Rela *irel = NULL;
+ literal_value val;
+ value_map *val_map;
+
+ rel = &src_relocs[i];
+ irel = get_irel_at_offset (sec, internal_relocs,
+ rel->r_rel.target_offset);
+
+ /* If the target_offset for this relocation is the same as the
+ previous relocation, then we've already considered whether the
+ literal can be coalesced. Skip to the next one.... */
+ if (i != 0 && (src_relocs[i-1].r_rel.target_offset
+ == rel->r_rel.target_offset))
+ continue;
+
+ /* Check if the relocation was from an L32R that is being removed
+ because a CALLX was converted to a direct CALL, and check if
+ there are no other relocations to the literal. */
+ if (rel->is_null
+ && (i == relax_info->src_count - 1
+ || (src_relocs[i+1].r_rel.target_offset
+ != rel->r_rel.target_offset)))
+ {
+ /* Mark the unused literal so that it will be removed. */
+ add_removed_literal (&relax_info->removed_list, &rel->r_rel, NULL);
+
+ /* Zero out the relocation on this literal location. */
+ if (irel)
+ {
+ if (elf_hash_table (link_info)->dynamic_sections_created)
+ shrink_dynamic_reloc_sections (link_info, abfd, sec, irel);
+
+ irel->r_info = ELF32_R_INFO (0, R_XTENSA_NONE);
+ }
+
+ continue;
+ }
+
+ /* Find the literal value. */
+ r_reloc_init (&val.r_rel, abfd, irel);
+ BFD_ASSERT (rel->r_rel.target_offset < sec->_raw_size);
+ val.value = bfd_get_32 (abfd, contents + rel->r_rel.target_offset);
+
+ /* Check if we've seen another literal with the same value. */
+ val_map = get_cached_value (values, &val);
+ if (val_map != NULL)
+ {
+ /* First check that THIS and all the other relocs to this
+ literal will FIT if we move them to the new address. */
+
+ if (relocations_reach (rel, relax_info->src_count - i,
+ &val_map->loc))
+ {
+ /* Mark that the literal will be coalesced. */
+ add_removed_literal (&relax_info->removed_list,
+ &rel->r_rel, &val_map->loc);
+ }
+ else
+ {
+ /* Relocations do not reach -- do not remove this literal. */
+ val_map->loc = rel->r_rel;
+ }
+ }
+ else
+ {
+ /* This is the first time we've seen this literal value. */
+ BFD_ASSERT (sec == r_reloc_get_section (&rel->r_rel));
+ add_value_map (values, &val, &rel->r_rel);
+ }
+ }
+
+error_return:
+ release_contents (sec, contents);
+ release_internal_relocs (sec, internal_relocs);
+ return ok;
+}
+
+
+/* Check if the original relocations (presumably on L32R instructions)
+ identified by reloc[0..N] can be changed to reference the literal
+ identified by r_rel. If r_rel is out of range for any of the
+ original relocations, then we don't want to coalesce the original
+ literal with the one at r_rel. We only check reloc[0..N], where the
+ offsets are all the same as for reloc[0] (i.e., they're all
+ referencing the same literal) and where N is also bounded by the
+ number of remaining entries in the "reloc" array. The "reloc" array
+ is sorted by target offset so we know all the entries for the same
+ literal will be contiguous. */
+
+static bfd_boolean
+relocations_reach (reloc, remaining_relocs, r_rel)
+ source_reloc *reloc;
+ int remaining_relocs;
+ const r_reloc *r_rel;
+{
+ bfd_vma from_offset, source_address, dest_address;
+ asection *sec;
+ int i;
+
+ if (!r_reloc_is_defined (r_rel))
+ return FALSE;
+
+ sec = r_reloc_get_section (r_rel);
+ from_offset = reloc[0].r_rel.target_offset;
+
+ for (i = 0; i < remaining_relocs; i++)
+ {
+ if (reloc[i].r_rel.target_offset != from_offset)
+ break;
+
+ /* Ignore relocations that have been removed. */
+ if (reloc[i].is_null)
+ continue;
+
+ /* The original and new output section for these must be the same
+ in order to coalesce. */
+ if (r_reloc_get_section (&reloc[i].r_rel)->output_section
+ != sec->output_section)
+ return FALSE;
+
+ /* A NULL operand means it is not a PC-relative relocation, so
+ the literal can be moved anywhere. */
+ if (reloc[i].opnd)
+ {
+ /* Otherwise, check to see that it fits. */
+ source_address = (reloc[i].source_sec->output_section->vma
+ + reloc[i].source_sec->output_offset
+ + reloc[i].r_rel.rela.r_offset);
+ dest_address = (sec->output_section->vma
+ + sec->output_offset
+ + r_rel->target_offset);
+
+ if (!pcrel_reloc_fits (reloc[i].opnd, source_address, dest_address))
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+/* WARNING: linear search here. If the relocation are in order by
+ address, we can use a faster binary search. ALSO, we assume that
+ there is only 1 non-NONE relocation per address. */
+
+static Elf_Internal_Rela *
+get_irel_at_offset (sec, internal_relocs, offset)
+ asection *sec;
+ Elf_Internal_Rela *internal_relocs;
+ bfd_vma offset;
+{
+ unsigned i;
+ if (!internal_relocs)
+ return NULL;
+ for (i = 0; i < sec->reloc_count; i++)
+ {
+ Elf_Internal_Rela *irel = &internal_relocs[i];
+ if (irel->r_offset == offset
+ && ELF32_R_TYPE (irel->r_info) != R_XTENSA_NONE)
+ return irel;
+ }
+ return NULL;
+}
+
+
+/* Second relaxation pass. */
+
+/* Modify all of the relocations to point to the right spot, and if this
+ is a relaxable section, delete the unwanted literals and fix the
+ cooked_size. */
+
+bfd_boolean
+relax_section (abfd, sec, link_info)
+ bfd *abfd;
+ asection *sec;
+ struct bfd_link_info *link_info;
+{
+ Elf_Internal_Rela *internal_relocs;
+ xtensa_relax_info *relax_info;
+ bfd_byte *contents;
+ bfd_boolean ok = TRUE;
+ unsigned i;
+
+ relax_info = get_xtensa_relax_info (sec);
+ BFD_ASSERT (relax_info);
+
+ /* Handle property sections (e.g., literal tables) specially. */
+ if (xtensa_is_property_section (sec))
+ {
+ BFD_ASSERT (!relax_info->is_relaxable_literal_section);
+ return relax_property_section (abfd, sec, link_info);
+ }
+
+ internal_relocs = retrieve_internal_relocs (abfd, sec,
+ link_info->keep_memory);
+ contents = retrieve_contents (abfd, sec, link_info->keep_memory);
+ if (contents == NULL && sec->_raw_size != 0)
+ {
+ ok = FALSE;
+ goto error_return;
+ }
+
+ if (internal_relocs)
+ {
+ for (i = 0; i < sec->reloc_count; i++)
+ {
+ Elf_Internal_Rela *irel;
+ xtensa_relax_info *target_relax_info;
+ bfd_vma source_offset;
+ r_reloc r_rel;
+ unsigned r_type;
+ asection *target_sec;
+
+ /* Locally change the source address.
+ Translate the target to the new target address.
+ If it points to this section and has been removed,
+ NULLify it.
+ Write it back. */
+
+ irel = &internal_relocs[i];
+ source_offset = irel->r_offset;
+
+ r_type = ELF32_R_TYPE (irel->r_info);
+ r_reloc_init (&r_rel, abfd, irel);
+
+ if (relax_info->is_relaxable_literal_section)
+ {
+ if (r_type != R_XTENSA_NONE
+ && find_removed_literal (&relax_info->removed_list,
+ irel->r_offset))
+ {
+ /* Remove this relocation. */
+ if (elf_hash_table (link_info)->dynamic_sections_created)
+ shrink_dynamic_reloc_sections (link_info, abfd, sec, irel);
+ irel->r_info = ELF32_R_INFO (0, R_XTENSA_NONE);
+ irel->r_offset = offset_with_removed_literals
+ (&relax_info->removed_list, irel->r_offset);
+ continue;
+ }
+ source_offset =
+ offset_with_removed_literals (&relax_info->removed_list,
+ irel->r_offset);
+ irel->r_offset = source_offset;
+ }
+
+ target_sec = r_reloc_get_section (&r_rel);
+ target_relax_info = get_xtensa_relax_info (target_sec);
+
+ if (target_relax_info
+ && target_relax_info->is_relaxable_literal_section)
+ {
+ r_reloc new_rel;
+ reloc_bfd_fix *fix;
+
+ translate_reloc (&r_rel, &new_rel);
+
+ /* FIXME: If the relocation still references a section in
+ the same input file, the relocation should be modified
+ directly instead of adding a "fix" record. */
+
+ fix = reloc_bfd_fix_init (sec, source_offset, r_type, 0,
+ r_reloc_get_section (&new_rel),
+ new_rel.target_offset);
+ add_fix (sec, fix);
+ }
+
+ pin_internal_relocs (sec, internal_relocs);
+ }
+ }
+
+ if (relax_info->is_relaxable_literal_section)
+ {
+ /* Walk through the contents and delete literals that are not needed
+ anymore. */
+
+ unsigned long size = sec->_cooked_size;
+ unsigned long removed = 0;
+
+ removed_literal *reloc = relax_info->removed_list.head;
+ for (; reloc; reloc = reloc->next)
+ {
+ unsigned long upper = sec->_raw_size;
+ bfd_vma start = reloc->from.target_offset + 4;
+ if (reloc->next)
+ upper = reloc->next->from.target_offset;
+ if (upper - start != 0)
+ {
+ BFD_ASSERT (start <= upper);
+ memmove (contents + start - removed - 4,
+ contents + start,
+ upper - start );
+ pin_contents (sec, contents);
+ }
+ removed += 4;
+ size -= 4;
+ }
+
+ /* Change the section size. */
+ sec->_cooked_size = size;
+ /* Also shrink _raw_size. (The code in relocate_section that
+ checks that relocations are within the section must use
+ _raw_size because of the way the stabs sections are relaxed;
+ shrinking _raw_size means that these checks will not be
+ unnecessarily lax.) */
+ sec->_raw_size = size;
+ }
+
+ error_return:
+ release_internal_relocs (sec, internal_relocs);
+ release_contents (sec, contents);
+ return ok;
+}
+
+
+/* Fix up a relocation to take account of removed literals. */
+
+static void
+translate_reloc (orig_rel, new_rel)
+ const r_reloc *orig_rel;
+ r_reloc *new_rel;
+{
+ asection *sec;
+ xtensa_relax_info *relax_info;
+ removed_literal *removed;
+ unsigned long new_offset;
+
+ *new_rel = *orig_rel;
+
+ if (!r_reloc_is_defined (orig_rel))
+ return;
+ sec = r_reloc_get_section (orig_rel);
+
+ relax_info = get_xtensa_relax_info (sec);
+ BFD_ASSERT (relax_info);
+
+ if (!relax_info->is_relaxable_literal_section)
+ return;
+
+ /* Check if the original relocation is against a literal being removed. */
+ removed = find_removed_literal (&relax_info->removed_list,
+ orig_rel->target_offset);
+ if (removed)
+ {
+ asection *new_sec;
+
+ /* The fact that there is still a relocation to this literal indicates
+ that the literal is being coalesced, not simply removed. */
+ BFD_ASSERT (removed->to.abfd != NULL);
+
+ /* This was moved to some other address (possibly in another section). */
+ *new_rel = removed->to;
+ new_sec = r_reloc_get_section (new_rel);
+ if (new_sec != sec)
+ {
+ sec = new_sec;
+ relax_info = get_xtensa_relax_info (sec);
+ if (!relax_info || !relax_info->is_relaxable_literal_section)
+ return;
+ }
+ }
+
+ /* ...and the target address may have been moved within its section. */
+ new_offset = offset_with_removed_literals (&relax_info->removed_list,
+ new_rel->target_offset);
+
+ /* Modify the offset and addend. */
+ new_rel->target_offset = new_offset;
+ new_rel->rela.r_addend += (new_offset - new_rel->target_offset);
+}
+
+
+/* For dynamic links, there may be a dynamic relocation for each
+ literal. The number of dynamic relocations must be computed in
+ size_dynamic_sections, which occurs before relaxation. When a
+ literal is removed, this function checks if there is a corresponding
+ dynamic relocation and shrinks the size of the appropriate dynamic
+ relocation section accordingly. At this point, the contents of the
+ dynamic relocation sections have not yet been filled in, so there's
+ nothing else that needs to be done. */
+
+static void
+shrink_dynamic_reloc_sections (info, abfd, input_section, rel)
+ struct bfd_link_info *info;
+ bfd *abfd;
+ asection *input_section;
+ Elf_Internal_Rela *rel;
+{
+ Elf_Internal_Shdr *symtab_hdr;
+ struct elf_link_hash_entry **sym_hashes;
+ unsigned long r_symndx;
+ int r_type;
+ struct elf_link_hash_entry *h;
+ bfd_boolean dynamic_symbol;
+
+ symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ sym_hashes = elf_sym_hashes (abfd);
+
+ r_type = ELF32_R_TYPE (rel->r_info);
+ r_symndx = ELF32_R_SYM (rel->r_info);
+
+ if (r_symndx < symtab_hdr->sh_info)
+ h = NULL;
+ else
+ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+
+ dynamic_symbol = xtensa_elf_dynamic_symbol_p (info, h);
+
+ if ((r_type == R_XTENSA_32 || r_type == R_XTENSA_PLT)
+ && (input_section->flags & SEC_ALLOC) != 0
+ && (dynamic_symbol || info->shared))
+ {
+ bfd *dynobj;
+ const char *srel_name;
+ asection *srel;
+ bfd_boolean is_plt = FALSE;
+
+ dynobj = elf_hash_table (info)->dynobj;
+ BFD_ASSERT (dynobj != NULL);
+
+ if (dynamic_symbol && r_type == R_XTENSA_PLT)
+ {
+ srel_name = ".rela.plt";
+ is_plt = TRUE;
+ }
+ else
+ srel_name = ".rela.got";
+
+ /* Reduce size of the .rela.* section by one reloc. */
+ srel = bfd_get_section_by_name (dynobj, srel_name);
+ BFD_ASSERT (srel != NULL);
+ BFD_ASSERT (srel->_cooked_size >= sizeof (Elf32_External_Rela));
+ srel->_cooked_size -= sizeof (Elf32_External_Rela);
+
+ /* Also shrink _raw_size. (This seems wrong but other bfd code seems
+ to assume that linker-created sections will never be relaxed and
+ hence _raw_size must always equal _cooked_size.) */
+ srel->_raw_size = srel->_cooked_size;
+
+ if (is_plt)
+ {
+ asection *splt, *sgotplt, *srelgot;
+ int reloc_index, chunk;
+
+ /* Find the PLT reloc index of the entry being removed. This
+ is computed from the size of ".rela.plt". It is needed to
+ figure out which PLT chunk to resize. Usually "last index
+ = size - 1" since the index starts at zero, but in this
+ context, the size has just been decremented so there's no
+ need to subtract one. */
+ reloc_index = srel->_cooked_size / sizeof (Elf32_External_Rela);
+
+ chunk = reloc_index / PLT_ENTRIES_PER_CHUNK;
+ splt = elf_xtensa_get_plt_section (dynobj, chunk);
+ sgotplt = elf_xtensa_get_gotplt_section (dynobj, chunk);
+ BFD_ASSERT (splt != NULL && sgotplt != NULL);
+
+ /* Check if an entire PLT chunk has just been eliminated. */
+ if (reloc_index % PLT_ENTRIES_PER_CHUNK == 0)
+ {
+ /* The two magic GOT entries for that chunk can go away. */
+ srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+ BFD_ASSERT (srelgot != NULL);
+ srelgot->reloc_count -= 2;
+ srelgot->_cooked_size -= 2 * sizeof (Elf32_External_Rela);
+ /* Shrink _raw_size (see comment above). */
+ srelgot->_raw_size = srelgot->_cooked_size;
+
+ sgotplt->_cooked_size -= 8;
+
+ /* There should be only one entry left (and it will be
+ removed below). */
+ BFD_ASSERT (sgotplt->_cooked_size == 4);
+ BFD_ASSERT (splt->_cooked_size == PLT_ENTRY_SIZE);
+ }
+
+ BFD_ASSERT (sgotplt->_cooked_size >= 4);
+ BFD_ASSERT (splt->_cooked_size >= PLT_ENTRY_SIZE);
+
+ sgotplt->_cooked_size -= 4;
+ splt->_cooked_size -= PLT_ENTRY_SIZE;
+
+ /* Shrink _raw_sizes (see comment above). */
+ sgotplt->_raw_size = sgotplt->_cooked_size;
+ splt->_raw_size = splt->_cooked_size;
+ }
+ }
+}
+
+
+/* This is similar to relax_section except that when a target is moved,
+ we shift addresses up. We also need to modify the size. This
+ algorithm does NOT allow for relocations into the middle of the
+ property sections. */
+
+static bfd_boolean
+relax_property_section (abfd, sec, link_info)
+ bfd *abfd;
+ asection *sec;
+ struct bfd_link_info *link_info;
+{
+ Elf_Internal_Rela *internal_relocs;
+ bfd_byte *contents;
+ unsigned i, nexti;
+ bfd_boolean ok = TRUE;
+
+ internal_relocs = retrieve_internal_relocs (abfd, sec,
+ link_info->keep_memory);
+ contents = retrieve_contents (abfd, sec, link_info->keep_memory);
+ if (contents == NULL && sec->_raw_size != 0)
+ {
+ ok = FALSE;
+ goto error_return;
+ }
+
+ if (internal_relocs)
+ {
+ for (i = 0; i < sec->reloc_count; i++)
+ {
+ Elf_Internal_Rela *irel;
+ xtensa_relax_info *target_relax_info;
+ r_reloc r_rel;
+ unsigned r_type;
+ asection *target_sec;
+
+ /* Locally change the source address.
+ Translate the target to the new target address.
+ If it points to this section and has been removed, MOVE IT.
+ Also, don't forget to modify the associated SIZE at
+ (offset + 4). */
+
+ irel = &internal_relocs[i];
+ r_type = ELF32_R_TYPE (irel->r_info);
+ if (r_type == R_XTENSA_NONE)
+ continue;
+
+ r_reloc_init (&r_rel, abfd, irel);
+
+ target_sec = r_reloc_get_section (&r_rel);
+ target_relax_info = get_xtensa_relax_info (target_sec);
+
+ if (target_relax_info
+ && target_relax_info->is_relaxable_literal_section)
+ {
+ /* Translate the relocation's destination. */
+ bfd_vma new_offset;
+ bfd_vma new_end_offset;
+ bfd_byte *size_p;
+ long old_size, new_size;
+
+ new_offset =
+ offset_with_removed_literals (&target_relax_info->removed_list,
+ r_rel.target_offset);
+
+ /* Assert that we are not out of bounds. */
+ size_p = &contents[irel->r_offset + 4];
+ old_size = bfd_get_32 (abfd, &contents[irel->r_offset + 4]);
+
+ new_end_offset =
+ offset_with_removed_literals (&target_relax_info->removed_list,
+ r_rel.target_offset + old_size);
+
+ new_size = new_end_offset - new_offset;
+ if (new_size != old_size)
+ {
+ bfd_put_32 (abfd, new_size, size_p);
+ pin_contents (sec, contents);
+ }
+
+ if (new_offset != r_rel.target_offset)
+ {
+ bfd_vma diff = new_offset - r_rel.target_offset;
+ irel->r_addend += diff;
+ pin_internal_relocs (sec, internal_relocs);
+ }
+ }
+ }
+ }
+
+ /* Combine adjacent property table entries. This is also done in
+ finish_dynamic_sections() but at that point it's too late to
+ reclaim the space in the output section, so we do this twice. */
+
+ if (internal_relocs)
+ {
+ Elf_Internal_Rela *last_irel = NULL;
+ int removed_bytes = 0;
+ bfd_vma offset, last_irel_offset;
+ bfd_vma section_size;
+
+ /* Walk over memory and irels at the same time.
+ This REQUIRES that the internal_relocs be sorted by offset. */
+ qsort (internal_relocs, sec->reloc_count, sizeof (Elf_Internal_Rela),
+ internal_reloc_compare);
+ nexti = 0; /* Index into internal_relocs. */
+
+ pin_internal_relocs (sec, internal_relocs);
+ pin_contents (sec, contents);
+
+ last_irel_offset = (bfd_vma) -1;
+ section_size = (sec->_cooked_size ? sec->_cooked_size : sec->_raw_size);
+ BFD_ASSERT (section_size % 8 == 0);
+
+ for (offset = 0; offset < section_size; offset += 8)
+ {
+ Elf_Internal_Rela *irel, *next_irel;
+ bfd_vma bytes_to_remove, size, actual_offset;
+ bfd_boolean remove_this_irel;
+
+ irel = NULL;
+ next_irel = NULL;
+
+ /* Find the next two relocations (if there are that many left),
+ skipping over any R_XTENSA_NONE relocs. On entry, "nexti" is
+ the starting reloc index. After these two loops, "i"
+ is the index of the first non-NONE reloc past that starting
+ index, and "nexti" is the index for the next non-NONE reloc
+ after "i". */
+
+ for (i = nexti; i < sec->reloc_count; i++)
+ {
+ if (ELF32_R_TYPE (internal_relocs[i].r_info) != R_XTENSA_NONE)
+ {
+ irel = &internal_relocs[i];
+ break;
+ }
+ internal_relocs[i].r_offset -= removed_bytes;
+ }
+
+ for (nexti = i + 1; nexti < sec->reloc_count; nexti++)
+ {
+ if (ELF32_R_TYPE (internal_relocs[nexti].r_info)
+ != R_XTENSA_NONE)
+ {
+ next_irel = &internal_relocs[nexti];
+ break;
+ }
+ internal_relocs[nexti].r_offset -= removed_bytes;
+ }
+
+ remove_this_irel = FALSE;
+ bytes_to_remove = 0;
+ actual_offset = offset - removed_bytes;
+ size = bfd_get_32 (abfd, &contents[actual_offset + 4]);
+
+ /* Check that the irels are sorted by offset,
+ with only one per address. */
+ BFD_ASSERT (!irel || (int) irel->r_offset > (int) last_irel_offset);
+ BFD_ASSERT (!next_irel || next_irel->r_offset > irel->r_offset);
+
+ /* Make sure there isn't a reloc on the size field. */
+ if (irel && irel->r_offset == offset + 4)
+ {
+ irel->r_offset -= removed_bytes;
+ last_irel_offset = irel->r_offset;
+ }
+ else if (next_irel && next_irel->r_offset == offset + 4)
+ {
+ nexti += 1;
+ irel->r_offset -= removed_bytes;
+ next_irel->r_offset -= removed_bytes;
+ last_irel_offset = next_irel->r_offset;
+ }
+ else if (size == 0)
+ {
+ /* Always remove entries with zero size. */
+ bytes_to_remove = 8;
+ if (irel && irel->r_offset == offset)
+ {
+ remove_this_irel = TRUE;
+
+ irel->r_offset -= removed_bytes;
+ last_irel_offset = irel->r_offset;
+ }
+ }
+ else if (irel && irel->r_offset == offset)
+ {
+ if (ELF32_R_TYPE (irel->r_info) == R_XTENSA_32)
+ {
+ if (last_irel)
+ {
+ bfd_vma old_size =
+ bfd_get_32 (abfd, &contents[last_irel->r_offset + 4]);
+ bfd_vma old_address =
+ (last_irel->r_addend
+ + bfd_get_32 (abfd, &contents[last_irel->r_offset]));
+ bfd_vma new_address =
+ (irel->r_addend
+ + bfd_get_32 (abfd, &contents[actual_offset]));
+
+ if ((ELF32_R_SYM (irel->r_info) ==
+ ELF32_R_SYM (last_irel->r_info))
+ && (old_address + old_size == new_address))
+ {
+ /* fix the old size */
+ bfd_put_32 (abfd, old_size + size,
+ &contents[last_irel->r_offset + 4]);
+ bytes_to_remove = 8;
+ remove_this_irel = TRUE;
+ }
+ else
+ last_irel = irel;
+ }
+ else
+ last_irel = irel;
+ }
+
+ irel->r_offset -= removed_bytes;
+ last_irel_offset = irel->r_offset;
+ }
+
+ if (remove_this_irel)
+ {
+ irel->r_info = ELF32_R_INFO (0, R_XTENSA_NONE);
+ irel->r_offset -= bytes_to_remove;
+ }
+
+ if (bytes_to_remove != 0)
+ {
+ removed_bytes += bytes_to_remove;
+ if (offset + 8 < section_size)
+ memmove (&contents[actual_offset],
+ &contents[actual_offset+8],
+ section_size - offset - 8);
+ }
+ }
+
+ if (removed_bytes)
+ {
+ /* Clear the removed bytes. */
+ memset (&contents[section_size - removed_bytes], 0, removed_bytes);
+
+ sec->_cooked_size = section_size - removed_bytes;
+ /* Also shrink _raw_size. (The code in relocate_section that
+ checks that relocations are within the section must use
+ _raw_size because of the way the stabs sections are
+ relaxed; shrinking _raw_size means that these checks will
+ not be unnecessarily lax.) */
+ sec->_raw_size = sec->_cooked_size;
+ }
+ }
+
+ error_return:
+ release_internal_relocs (sec, internal_relocs);
+ release_contents (sec, contents);
+ return ok;
+}
+
+
+/* Third relaxation pass. */
+
+/* Change symbol values to account for removed literals. */
+
+bfd_boolean
+relax_section_symbols (abfd, sec)
+ bfd *abfd;
+ asection *sec;
+{
+ xtensa_relax_info *relax_info;
+ unsigned int sec_shndx;
+ Elf_Internal_Shdr *symtab_hdr;
+ Elf_Internal_Sym *isymbuf;
+ unsigned i, num_syms, num_locals;
+
+ relax_info = get_xtensa_relax_info (sec);
+ BFD_ASSERT (relax_info);
+
+ if (!relax_info->is_relaxable_literal_section)
+ return TRUE;
+
+ sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
+
+ symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ isymbuf = retrieve_local_syms (abfd);
+
+ num_syms = symtab_hdr->sh_size / sizeof (Elf32_External_Sym);
+ num_locals = symtab_hdr->sh_info;
+
+ /* Adjust the local symbols defined in this section. */
+ for (i = 0; i < num_locals; i++)
+ {
+ Elf_Internal_Sym *isym = &isymbuf[i];
+
+ if (isym->st_shndx == sec_shndx)
+ {
+ bfd_vma new_address = offset_with_removed_literals
+ (&relax_info->removed_list, isym->st_value);
+ if (new_address != isym->st_value)
+ isym->st_value = new_address;
+ }
+ }
+
+ /* Now adjust the global symbols defined in this section. */
+ for (i = 0; i < (num_syms - num_locals); i++)
+ {
+ struct elf_link_hash_entry *sym_hash;
+
+ sym_hash = elf_sym_hashes (abfd)[i];
+
+ if (sym_hash->root.type == bfd_link_hash_warning)
+ sym_hash = (struct elf_link_hash_entry *) sym_hash->root.u.i.link;
+
+ if ((sym_hash->root.type == bfd_link_hash_defined
+ || sym_hash->root.type == bfd_link_hash_defweak)
+ && sym_hash->root.u.def.section == sec)
+ {
+ bfd_vma new_address = offset_with_removed_literals
+ (&relax_info->removed_list, sym_hash->root.u.def.value);
+ if (new_address != sym_hash->root.u.def.value)
+ sym_hash->root.u.def.value = new_address;
+ }
+ }
+
+ return TRUE;
+}
+
+
+/* "Fix" handling functions, called while performing relocations. */
+
+static void
+do_fix_for_relocateable_link (rel, input_bfd, input_section)
+ Elf_Internal_Rela *rel;
+ bfd *input_bfd;
+ asection *input_section;
+{
+ r_reloc r_rel;
+ asection *sec, *old_sec;
+ bfd_vma old_offset;
+ int r_type = ELF32_R_TYPE (rel->r_info);
+ reloc_bfd_fix *fix_list;
+ reloc_bfd_fix *fix;
+
+ if (r_type == R_XTENSA_NONE)
+ return;
+
+ fix_list = (get_xtensa_relax_info (input_section))->fix_list;
+ if (fix_list == NULL)
+ return;
+
+ fix = get_bfd_fix (fix_list, input_section, rel->r_offset, r_type);
+ if (fix == NULL)
+ return;
+
+ r_reloc_init (&r_rel, input_bfd, rel);
+ old_sec = r_reloc_get_section (&r_rel);
+ old_offset = r_reloc_get_target_offset (&r_rel);
+
+ if (old_sec == NULL || !r_reloc_is_defined (&r_rel))
+ {
+ BFD_ASSERT (r_type == R_XTENSA_ASM_EXPAND);
+ /* Leave it be. Resolution will happen in a later stage. */
+ }
+ else
+ {
+ sec = fix->target_sec;
+ rel->r_addend += ((sec->output_offset + fix->target_offset)
+ - (old_sec->output_offset + old_offset));
+ }
+}
+
+
+static void
+do_fix_for_final_link (rel, input_section, relocationp)
+ Elf_Internal_Rela *rel;
+ asection *input_section;
+ bfd_vma *relocationp;
+{
+ asection *sec;
+ int r_type = ELF32_R_TYPE (rel->r_info);
+ reloc_bfd_fix *fix_list;
+ reloc_bfd_fix *fix;
+
+ if (r_type == R_XTENSA_NONE)
+ return;
+
+ fix_list = (get_xtensa_relax_info (input_section))->fix_list;
+ if (fix_list == NULL)
+ return;
+
+ fix = get_bfd_fix (fix_list, input_section, rel->r_offset, r_type);
+ if (fix == NULL)
+ return;
+
+ sec = fix->target_sec;
+ *relocationp = (sec->output_section->vma
+ + sec->output_offset
+ + fix->target_offset - rel->r_addend);
+}
+
+
+/* Miscellaneous utility functions.... */
+
+static asection *
+elf_xtensa_get_plt_section (dynobj, chunk)
+ bfd *dynobj;
+ int chunk;
+{
+ char plt_name[10];
+
+ if (chunk == 0)
+ return bfd_get_section_by_name (dynobj, ".plt");
+
+ sprintf (plt_name, ".plt.%u", chunk);
+ return bfd_get_section_by_name (dynobj, plt_name);
+}
+
+
+static asection *
+elf_xtensa_get_gotplt_section (dynobj, chunk)
+ bfd *dynobj;
+ int chunk;
+{
+ char got_name[14];
+
+ if (chunk == 0)
+ return bfd_get_section_by_name (dynobj, ".got.plt");
+
+ sprintf (got_name, ".got.plt.%u", chunk);
+ return bfd_get_section_by_name (dynobj, got_name);
+}
+
+
+/* Get the input section for a given symbol index.
+ If the symbol is:
+ . a section symbol, return the section;
+ . a common symbol, return the common section;
+ . an undefined symbol, return the undefined section;
+ . an indirect symbol, follow the links;
+ . an absolute value, return the absolute section. */
+
+static asection *
+get_elf_r_symndx_section (abfd, r_symndx)
+ bfd *abfd;
+ unsigned long r_symndx;
+{
+ Elf_Internal_Shdr *symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ asection *target_sec = NULL;
+ if (r_symndx < symtab_hdr->sh_info)
+ {
+ Elf_Internal_Sym *isymbuf;
+ unsigned int section_index;
+
+ isymbuf = retrieve_local_syms (abfd);
+ section_index = isymbuf[r_symndx].st_shndx;
+
+ if (section_index == SHN_UNDEF)
+ target_sec = bfd_und_section_ptr;
+ else if (section_index > 0 && section_index < SHN_LORESERVE)
+ target_sec = bfd_section_from_elf_index (abfd, section_index);
+ else if (section_index == SHN_ABS)
+ target_sec = bfd_abs_section_ptr;
+ else if (section_index == SHN_COMMON)
+ target_sec = bfd_com_section_ptr;
+ else
+ /* Who knows? */
+ target_sec = NULL;
+ }
+ else
+ {
+ unsigned long indx = r_symndx - symtab_hdr->sh_info;
+ struct elf_link_hash_entry *h = elf_sym_hashes (abfd)[indx];
+
+ while (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+ switch (h->root.type)
+ {
+ case bfd_link_hash_defined:
+ case bfd_link_hash_defweak:
+ target_sec = h->root.u.def.section;
+ break;
+ case bfd_link_hash_common:
+ target_sec = bfd_com_section_ptr;
+ break;
+ case bfd_link_hash_undefined:
+ case bfd_link_hash_undefweak:
+ target_sec = bfd_und_section_ptr;
+ break;
+ default: /* New indirect warning. */
+ target_sec = bfd_und_section_ptr;
+ break;
+ }
+ }
+ return target_sec;
+}
+
+
+static struct elf_link_hash_entry *
+get_elf_r_symndx_hash_entry (abfd, r_symndx)
+ bfd *abfd;
+ unsigned long r_symndx;
+{
+ unsigned long indx;
+ struct elf_link_hash_entry *h;
+ Elf_Internal_Shdr *symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+
+ if (r_symndx < symtab_hdr->sh_info)
+ return NULL;
+
+ indx = r_symndx - symtab_hdr->sh_info;
+ h = elf_sym_hashes (abfd)[indx];
+ while (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ return h;
+}
+
+
+/* Get the section-relative offset for a symbol number. */
+
+static bfd_vma
+get_elf_r_symndx_offset (abfd, r_symndx)
+ bfd *abfd;
+ unsigned long r_symndx;
+{
+ Elf_Internal_Shdr *symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ bfd_vma offset = 0;
+
+ if (r_symndx < symtab_hdr->sh_info)
+ {
+ Elf_Internal_Sym *isymbuf;
+ isymbuf = retrieve_local_syms (abfd);
+ offset = isymbuf[r_symndx].st_value;
+ }
+ else
+ {
+ unsigned long indx = r_symndx - symtab_hdr->sh_info;
+ struct elf_link_hash_entry *h =
+ elf_sym_hashes (abfd)[indx];
+
+ while (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ if (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ offset = h->root.u.def.value;
+ }
+ return offset;
+}
+
+
+static bfd_boolean
+pcrel_reloc_fits (opnd, self_address, dest_address)
+ xtensa_operand opnd;
+ bfd_vma self_address;
+ bfd_vma dest_address;
+{
+ uint32 new_address =
+ xtensa_operand_do_reloc (opnd, dest_address, self_address);
+ return (xtensa_operand_encode (opnd, &new_address)
+ == xtensa_encode_result_ok);
+}
+
+
+static bfd_boolean
+xtensa_is_property_section (sec)
+ asection *sec;
+{
+ static int len = sizeof (".gnu.linkonce.t.") - 1;
+
+ return (strcmp (".xt.insn", sec->name) == 0
+ || strcmp (".xt.lit", sec->name) == 0
+ || strncmp (".gnu.linkonce.x.", sec->name, len) == 0
+ || strncmp (".gnu.linkonce.p.", sec->name, len) == 0);
+}
+
+
+static bfd_boolean
+is_literal_section (sec)
+ asection *sec;
+{
+ /* FIXME: the current definition of this leaves a lot to be desired.... */
+ if (sec == NULL || sec->name == NULL)
+ return FALSE;
+ return (strstr (sec->name, "literal") != NULL);
+}
+
+
+static int
+internal_reloc_compare (ap, bp)
+ const PTR ap;
+ const PTR bp;
+{
+ const Elf_Internal_Rela *a = (const Elf_Internal_Rela *) ap;
+ const Elf_Internal_Rela *b = (const Elf_Internal_Rela *) bp;
+
+ return (a->r_offset - b->r_offset);
+}
+
+
+static bfd_boolean
+get_is_linkonce_section (abfd, sec)
+ bfd *abfd ATTRIBUTE_UNUSED;
+ asection *sec;
+{
+ flagword flags, link_once_flags;
+ bfd_boolean is_linkonce = FALSE;;
+
+ flags = bfd_get_section_flags (abfd, sec);
+ link_once_flags = (flags & SEC_LINK_ONCE);
+ if (link_once_flags != 0)
+ is_linkonce = TRUE;
+
+ /* In order for this to be useful to the assembler
+ before the linkonce flag is set we need to
+ check for the GNU extension name. */
+ if (!is_linkonce &&
+ strncmp (sec->name, ".gnu.linkonce", sizeof ".gnu.linkonce" - 1) == 0)
+ is_linkonce = TRUE;
+
+ return is_linkonce;
+}
+
+
+char *
+xtensa_get_property_section_name (abfd, sec, base_name)
+ bfd *abfd;
+ asection *sec;
+ const char * base_name;
+{
+ char *table_sec_name = NULL;
+ bfd_boolean is_linkonce;
+
+ is_linkonce = get_is_linkonce_section (abfd, sec);
+
+ if (!is_linkonce)
+ {
+ table_sec_name = strdup (base_name);
+ }
+ else
+ {
+ static size_t prefix_len = sizeof (".gnu.linkonce.t.") - 1;
+ size_t len = strlen (sec->name) + 1;
+ char repl_char = '\0';
+ const char *segname = sec->name;
+
+ if (strncmp (segname, ".gnu.linkonce.t.", prefix_len) == 0)
+ {
+ if (strcmp (base_name, ".xt.insn") == 0)
+ repl_char = 'x';
+ else if (strcmp (base_name, ".xt.lit") == 0)
+ repl_char = 'p';
+ }
+
+ if (repl_char != '\0')
+ {
+ char *name = (char *) bfd_malloc (len);
+ memcpy (name, sec->name, len);
+ name[prefix_len - 2] = repl_char;
+ table_sec_name = name;
+ }
+ else
+ {
+ size_t base_len = strlen (base_name) + 1;
+ char *name = (char *) bfd_malloc (len + base_len);
+ memcpy (name, sec->name, len - 1);
+ memcpy (name + len - 1, base_name, base_len);
+ table_sec_name = name;
+ }
+ }
+
+ return table_sec_name;
+}
+
+
+/* Other functions called directly by the linker. */
+
+bfd_boolean
+xtensa_callback_required_dependence (abfd, sec, link_info, callback, closure)
+ bfd *abfd;
+ asection *sec;
+ struct bfd_link_info *link_info;
+ deps_callback_t callback;
+ PTR closure;
+{
+ Elf_Internal_Rela *internal_relocs;
+ bfd_byte *contents;
+ unsigned i;
+ bfd_boolean ok = TRUE;
+
+ /* ".plt*" sections have no explicit relocations but they contain L32R
+ instructions that reference the corresponding ".got.plt*" sections. */
+ if ((sec->flags & SEC_LINKER_CREATED) != 0
+ && strncmp (sec->name, ".plt", 4) == 0)
+ {
+ asection *sgotplt;
+
+ /* Find the corresponding ".got.plt*" section. */
+ if (sec->name[4] == '\0')
+ sgotplt = bfd_get_section_by_name (sec->owner, ".got.plt");
+ else
+ {
+ char got_name[14];
+ int chunk = 0;
+
+ BFD_ASSERT (sec->name[4] == '.');
+ chunk = strtol (&sec->name[5], NULL, 10);
+
+ sprintf (got_name, ".got.plt.%u", chunk);
+ sgotplt = bfd_get_section_by_name (sec->owner, got_name);
+ }
+ BFD_ASSERT (sgotplt);
+
+ /* Assume worst-case offsets: L32R at the very end of the ".plt"
+ section referencing a literal at the very beginning of
+ ".got.plt". This is very close to the real dependence, anyway. */
+ (*callback) (sec, sec->_raw_size, sgotplt, 0, closure);
+ }
+
+ internal_relocs = retrieve_internal_relocs (abfd, sec,
+ link_info->keep_memory);
+ if (internal_relocs == NULL
+ || sec->reloc_count == 0)
+ return ok;
+
+ /* Cache the contents for the duration of this scan. */
+ contents = retrieve_contents (abfd, sec, link_info->keep_memory);
+ if (contents == NULL && sec->_raw_size != 0)
+ {
+ ok = FALSE;
+ goto error_return;
+ }
+
+ if (xtensa_default_isa == NULL)
+ xtensa_isa_init ();
+
+ for (i = 0; i < sec->reloc_count; i++)
+ {
+ Elf_Internal_Rela *irel = &internal_relocs[i];
+ if (is_l32r_relocation (sec, contents, irel))
+ {
+ r_reloc l32r_rel;
+ asection *target_sec;
+ bfd_vma target_offset;
+
+ r_reloc_init (&l32r_rel, abfd, irel);
+ target_sec = NULL;
+ target_offset = 0;
+ /* L32Rs must be local to the input file. */
+ if (r_reloc_is_defined (&l32r_rel))
+ {
+ target_sec = r_reloc_get_section (&l32r_rel);
+ target_offset = r_reloc_get_target_offset (&l32r_rel);
+ }
+ (*callback) (sec, irel->r_offset, target_sec, target_offset,
+ closure);
+ }
+ }
+
+ error_return:
+ release_internal_relocs (sec, internal_relocs);
+ release_contents (sec, contents);
+ return ok;
+}
+
+
+#ifndef ELF_ARCH
+#define TARGET_LITTLE_SYM bfd_elf32_xtensa_le_vec
+#define TARGET_LITTLE_NAME "elf32-xtensa-le"
+#define TARGET_BIG_SYM bfd_elf32_xtensa_be_vec
+#define TARGET_BIG_NAME "elf32-xtensa-be"
+#define ELF_ARCH bfd_arch_xtensa
+
+/* The new EM_XTENSA value will be recognized beginning in the Xtensa T1040
+ release. However, we still have to generate files with the EM_XTENSA_OLD
+ value so that pre-T1040 tools can read the files. As soon as we stop
+ caring about pre-T1040 tools, the following two values should be
+ swapped. At the same time, any other code that uses EM_XTENSA_OLD
+ (e.g., prep_headers() in elf.c) should be changed to use EM_XTENSA. */
+#define ELF_MACHINE_CODE EM_XTENSA_OLD
+#define ELF_MACHINE_ALT1 EM_XTENSA
+
+#if XCHAL_HAVE_MMU
+#define ELF_MAXPAGESIZE (1 << XCHAL_MMU_MIN_PTE_PAGE_SIZE)
+#else /* !XCHAL_HAVE_MMU */
+#define ELF_MAXPAGESIZE 1
+#endif /* !XCHAL_HAVE_MMU */
+#endif /* ELF_ARCH */
+
+#define elf_backend_can_gc_sections 1
+#define elf_backend_can_refcount 1
+#define elf_backend_plt_readonly 1
+#define elf_backend_got_header_size 4
+#define elf_backend_want_dynbss 0
+#define elf_backend_want_got_plt 1
+
+#define elf_info_to_howto elf_xtensa_info_to_howto_rela
+
+#define bfd_elf32_bfd_final_link bfd_elf32_bfd_final_link
+#define bfd_elf32_bfd_merge_private_bfd_data elf_xtensa_merge_private_bfd_data
+#define bfd_elf32_new_section_hook elf_xtensa_new_section_hook
+#define bfd_elf32_bfd_print_private_bfd_data elf_xtensa_print_private_bfd_data
+#define bfd_elf32_bfd_relax_section elf_xtensa_relax_section
+#define bfd_elf32_bfd_reloc_type_lookup elf_xtensa_reloc_type_lookup
+#define bfd_elf32_bfd_set_private_flags elf_xtensa_set_private_flags
+
+#define elf_backend_adjust_dynamic_symbol elf_xtensa_adjust_dynamic_symbol
+#define elf_backend_check_relocs elf_xtensa_check_relocs
+#define elf_backend_copy_indirect_symbol elf_xtensa_copy_indirect_symbol
+#define elf_backend_create_dynamic_sections elf_xtensa_create_dynamic_sections
+#define elf_backend_discard_info elf_xtensa_discard_info
+#define elf_backend_ignore_discarded_relocs elf_xtensa_ignore_discarded_relocs
+#define elf_backend_final_write_processing elf_xtensa_final_write_processing
+#define elf_backend_finish_dynamic_sections elf_xtensa_finish_dynamic_sections
+#define elf_backend_finish_dynamic_symbol elf_xtensa_finish_dynamic_symbol
+#define elf_backend_gc_mark_hook elf_xtensa_gc_mark_hook
+#define elf_backend_gc_sweep_hook elf_xtensa_gc_sweep_hook
+#define elf_backend_grok_prstatus elf_xtensa_grok_prstatus
+#define elf_backend_grok_psinfo elf_xtensa_grok_psinfo
+#define elf_backend_hide_symbol elf_xtensa_hide_symbol
+#define elf_backend_modify_segment_map elf_xtensa_modify_segment_map
+#define elf_backend_object_p elf_xtensa_object_p
+#define elf_backend_reloc_type_class elf_xtensa_reloc_type_class
+#define elf_backend_relocate_section elf_xtensa_relocate_section
+#define elf_backend_size_dynamic_sections elf_xtensa_size_dynamic_sections
+
+#include "elf32-target.h"
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index df2ba3e3f9..9bbdebd218 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -1475,6 +1475,16 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
"BFD_RELOC_IQ2000_OFFSET_16",
"BFD_RELOC_IQ2000_OFFSET_21",
"BFD_RELOC_IQ2000_UHI16",
+ "BFD_RELOC_XTENSA_RTLD",
+ "BFD_RELOC_XTENSA_GLOB_DAT",
+ "BFD_RELOC_XTENSA_JMP_SLOT",
+ "BFD_RELOC_XTENSA_RELATIVE",
+ "BFD_RELOC_XTENSA_PLT",
+ "BFD_RELOC_XTENSA_OP0",
+ "BFD_RELOC_XTENSA_OP1",
+ "BFD_RELOC_XTENSA_OP2",
+ "BFD_RELOC_XTENSA_ASM_EXPAND",
+ "BFD_RELOC_XTENSA_ASM_SIMPLIFY",
"@@overflow: BFD_RELOC_UNUSED@@",
};
#endif
diff --git a/bfd/reloc.c b/bfd/reloc.c
index f4a3321802..aa2321fef7 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -3850,6 +3850,49 @@ ENUMX
ENUMDOC
IQ2000 Relocations.
+ENUM
+ BFD_RELOC_XTENSA_RTLD
+ENUMDOC
+ Special Xtensa relocation used only by PLT entries in ELF shared
+ objects to indicate that the runtime linker should set the value
+ to one of its own internal functions or data structures.
+ENUM
+ BFD_RELOC_XTENSA_GLOB_DAT
+ENUMX
+ BFD_RELOC_XTENSA_JMP_SLOT
+ENUMX
+ BFD_RELOC_XTENSA_RELATIVE
+ENUMDOC
+ Xtensa relocations for ELF shared objects.
+ENUM
+ BFD_RELOC_XTENSA_PLT
+ENUMDOC
+ Xtensa relocation used in ELF object files for symbols that may require
+ PLT entries. Otherwise, this is just a generic 32-bit relocation.
+ENUM
+ BFD_RELOC_XTENSA_OP0
+ENUMX
+ BFD_RELOC_XTENSA_OP1
+ENUMX
+ BFD_RELOC_XTENSA_OP2
+ENUMDOC
+ Generic Xtensa relocations. Only the operand number is encoded
+ in the relocation. The details are determined by extracting the
+ instruction opcode.
+ENUM
+ BFD_RELOC_XTENSA_ASM_EXPAND
+ENUMDOC
+ Xtensa relocation to mark that the assembler expanded the
+ instructions from an original target. The expansion size is
+ encoded in the reloc size.
+ENUM
+ BFD_RELOC_XTENSA_ASM_SIMPLIFY
+ENUMDOC
+ Xtensa relocation to mark that the linker should simplify
+ assembler-expanded instructions. This is commonly used
+ internally by the linker after analysis of a
+ BFD_RELOC_XTENSA_ASM_EXPAND.
+
ENDSENUM
BFD_RELOC_UNUSED
CODE_FRAGMENT
diff --git a/bfd/targets.c b/bfd/targets.c
index 2211e124a7..5ccae2a992 100644
--- a/bfd/targets.c
+++ b/bfd/targets.c
@@ -579,6 +579,8 @@ extern const bfd_target bfd_elf32_us_cris_vec;
extern const bfd_target bfd_elf32_v850_vec;
extern const bfd_target bfd_elf32_vax_vec;
extern const bfd_target bfd_elf32_xstormy16_vec;
+extern const bfd_target bfd_elf32_xtensa_be_vec;
+extern const bfd_target bfd_elf32_xtensa_le_vec;
extern const bfd_target bfd_elf64_alpha_freebsd_vec;
extern const bfd_target bfd_elf64_alpha_vec;
extern const bfd_target bfd_elf64_big_generic_vec;
@@ -871,6 +873,8 @@ static const bfd_target * const _bfd_target_vector[] = {
&bfd_elf32_v850_vec,
&bfd_elf32_vax_vec,
&bfd_elf32_xstormy16_vec,
+ &bfd_elf32_xtensa_be_vec,
+ &bfd_elf32_xtensa_le_vec,
#ifdef BFD64
&bfd_elf64_alpha_freebsd_vec,
&bfd_elf64_alpha_vec,
diff --git a/bfd/xtensa-isa.c b/bfd/xtensa-isa.c
new file mode 100644
index 0000000000..ffbef53dfd
--- /dev/null
+++ b/bfd/xtensa-isa.c
@@ -0,0 +1,593 @@
+/* Configurable Xtensa ISA support.
+ Copyright 2003 Free Software Foundation, Inc.
+
+ 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 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <string.h>
+
+#include "xtensa-isa.h"
+#include "xtensa-isa-internal.h"
+
+xtensa_isa xtensa_default_isa = NULL;
+
+static int
+opname_lookup_compare (const void *v1, const void *v2)
+{
+ opname_lookup_entry *e1 = (opname_lookup_entry *)v1;
+ opname_lookup_entry *e2 = (opname_lookup_entry *)v2;
+
+ return strcmp (e1->key, e2->key);
+}
+
+
+xtensa_isa
+xtensa_isa_init (void)
+{
+ xtensa_isa isa;
+ int mod;
+
+ isa = xtensa_load_isa (0);
+ if (isa == 0)
+ {
+ fprintf (stderr, "Failed to initialize Xtensa base ISA module\n");
+ return NULL;
+ }
+
+ for (mod = 1; xtensa_isa_modules[mod].get_num_opcodes_fn; mod++)
+ {
+ if (!xtensa_extend_isa (isa, mod))
+ {
+ fprintf (stderr, "Failed to initialize Xtensa TIE ISA module\n");
+ return NULL;
+ }
+ }
+
+ return isa;
+}
+
+/* ISA information. */
+
+static int
+xtensa_check_isa_config (xtensa_isa_internal *isa,
+ struct config_struct *config_table)
+{
+ int i, j;
+
+ if (!config_table)
+ {
+ fprintf (stderr, "Error: Empty configuration table in ISA DLL\n");
+ return 0;
+ }
+
+ /* For the first module, save a pointer to the table and record the
+ specified endianness and availability of the density option. */
+
+ if (isa->num_modules == 0)
+ {
+ int found_memory_order = 0;
+
+ isa->config = config_table;
+ isa->has_density = 1; /* Default to have density option. */
+
+ for (i = 0; config_table[i].param_name; i++)
+ {
+ if (!strcmp (config_table[i].param_name, "IsaMemoryOrder"))
+ {
+ isa->is_big_endian =
+ (strcmp (config_table[i].param_value, "BigEndian") == 0);
+ found_memory_order = 1;
+ }
+ if (!strcmp (config_table[i].param_name, "IsaUseDensityInstruction"))
+ {
+ isa->has_density = atoi (config_table[i].param_value);
+ }
+ }
+ if (!found_memory_order)
+ {
+ fprintf (stderr, "Error: \"IsaMemoryOrder\" missing from "
+ "configuration table in ISA DLL\n");
+ return 0;
+ }
+
+ return 1;
+ }
+
+ /* For subsequent modules, check that the parameters match. Note: This
+ code is sufficient to handle the current model where there are never
+ more than 2 modules; we might at some point want to handle cases where
+ module N > 0 specifies some parameters not included in the base table,
+ and we would then add those to isa->config so that subsequent modules
+ would check against them. */
+
+ for (i = 0; config_table[i].param_name; i++)
+ {
+ for (j = 0; isa->config[j].param_name; j++)
+ {
+ if (!strcmp (config_table[i].param_name, isa->config[j].param_name))
+ {
+ int mismatch;
+ if (!strcmp (config_table[i].param_name, "IsaCoprocessorCount"))
+ {
+ /* Only require the coprocessor count to be <= the base. */
+ int tiecnt = atoi (config_table[i].param_value);
+ int basecnt = atoi (isa->config[j].param_value);
+ mismatch = (tiecnt > basecnt);
+ }
+ else
+ mismatch = strcmp (config_table[i].param_value,
+ isa->config[j].param_value);
+ if (mismatch)
+ {
+#define MISMATCH_MESSAGE \
+"Error: Configuration mismatch in the \"%s\" parameter:\n\
+the configuration used when the TIE file was compiled had a value of\n\
+\"%s\", while the current configuration has a value of\n\
+\"%s\". Please rerun the TIE compiler with a matching\n\
+configuration.\n"
+ fprintf (stderr, MISMATCH_MESSAGE,
+ config_table[i].param_name,
+ config_table[i].param_value,
+ isa->config[j].param_value);
+ return 0;
+ }
+ break;
+ }
+ }
+ }
+
+ return 1;
+}
+
+
+static int
+xtensa_add_isa (xtensa_isa_internal *isa, libisa_module_specifier libisa)
+{
+ const int (*get_num_opcodes_fn) (void);
+ struct config_struct *(*get_config_table_fn) (void);
+ xtensa_opcode_internal **(*get_opcodes_fn) (void);
+ int (*decode_insn_fn) (const xtensa_insnbuf);
+ xtensa_opcode_internal **opcodes;
+ int opc, insn_size, prev_num_opcodes, new_num_opcodes, this_module;
+
+ get_num_opcodes_fn = xtensa_isa_modules[libisa].get_num_opcodes_fn;
+ get_opcodes_fn = xtensa_isa_modules[libisa].get_opcodes_fn;
+ decode_insn_fn = xtensa_isa_modules[libisa].decode_insn_fn;
+ get_config_table_fn = xtensa_isa_modules[libisa].get_config_table_fn;
+
+ if (!get_num_opcodes_fn || !get_opcodes_fn || !decode_insn_fn
+ || (!get_config_table_fn && isa->num_modules == 0))
+ return 0;
+
+ if (get_config_table_fn
+ && !xtensa_check_isa_config (isa, get_config_table_fn ()))
+ return 0;
+
+ prev_num_opcodes = isa->num_opcodes;
+ new_num_opcodes = (*get_num_opcodes_fn) ();
+
+ isa->num_opcodes += new_num_opcodes;
+ isa->opcode_table = (xtensa_opcode_internal **)
+ realloc (isa->opcode_table, isa->num_opcodes *
+ sizeof (xtensa_opcode_internal *));
+ isa->opname_lookup_table = (opname_lookup_entry *)
+ realloc (isa->opname_lookup_table, isa->num_opcodes *
+ sizeof (opname_lookup_entry));
+
+ opcodes = (*get_opcodes_fn) ();
+
+ insn_size = isa->insn_size;
+ for (opc = 0; opc < new_num_opcodes; opc++)
+ {
+ xtensa_opcode_internal *intopc = opcodes[opc];
+ int newopc = prev_num_opcodes + opc;
+ isa->opcode_table[newopc] = intopc;
+ isa->opname_lookup_table[newopc].key = intopc->name;
+ isa->opname_lookup_table[newopc].opcode = newopc;
+ if (intopc->length > insn_size)
+ insn_size = intopc->length;
+ }
+
+ isa->insn_size = insn_size;
+ isa->insnbuf_size = ((isa->insn_size + sizeof (xtensa_insnbuf_word) - 1) /
+ sizeof (xtensa_insnbuf_word));
+
+ qsort (isa->opname_lookup_table, isa->num_opcodes,
+ sizeof (opname_lookup_entry), opname_lookup_compare);
+
+ /* Check for duplicate opcode names. */
+ for (opc = 1; opc < isa->num_opcodes; opc++)
+ {
+ if (!opname_lookup_compare (&isa->opname_lookup_table[opc-1],
+ &isa->opname_lookup_table[opc]))
+ {
+ fprintf (stderr, "Error: Duplicate TIE opcode \"%s\"\n",
+ isa->opname_lookup_table[opc].key);
+ return 0;
+ }
+ }
+
+ this_module = isa->num_modules;
+ isa->num_modules += 1;
+
+ isa->module_opcode_base = (int *) realloc (isa->module_opcode_base,
+ isa->num_modules * sizeof (int));
+ isa->module_decode_fn = (xtensa_insn_decode_fn *)
+ realloc (isa->module_decode_fn, isa->num_modules *
+ sizeof (xtensa_insn_decode_fn));
+
+ isa->module_opcode_base[this_module] = prev_num_opcodes;
+ isa->module_decode_fn[this_module] = decode_insn_fn;
+
+ xtensa_default_isa = isa;
+
+ return 1; /* Library was successfully added. */
+}
+
+
+xtensa_isa
+xtensa_load_isa (libisa_module_specifier libisa)
+{
+ xtensa_isa_internal *isa;
+
+ isa = (xtensa_isa_internal *) malloc (sizeof (xtensa_isa_internal));
+ memset (isa, 0, sizeof (xtensa_isa_internal));
+ if (!xtensa_add_isa (isa, libisa))
+ {
+ xtensa_isa_free (isa);
+ return NULL;
+ }
+ return (xtensa_isa) isa;
+}
+
+
+int
+xtensa_extend_isa (xtensa_isa isa, libisa_module_specifier libisa)
+{
+ xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+ return xtensa_add_isa (intisa, libisa);
+}
+
+
+void
+xtensa_isa_free (xtensa_isa isa)
+{
+ xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+ if (intisa->opcode_table)
+ free (intisa->opcode_table);
+ if (intisa->opname_lookup_table)
+ free (intisa->opname_lookup_table);
+ if (intisa->module_opcode_base)
+ free (intisa->module_opcode_base);
+ if (intisa->module_decode_fn)
+ free (intisa->module_decode_fn);
+ free (intisa);
+}
+
+
+int
+xtensa_insn_maxlength (xtensa_isa isa)
+{
+ xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+ return intisa->insn_size;
+}
+
+
+int
+xtensa_insnbuf_size (xtensa_isa isa)
+{
+ xtensa_isa_internal *intisa = (xtensa_isa_internal *)isa;
+ return intisa->insnbuf_size;
+}
+
+
+int
+xtensa_num_opcodes (xtensa_isa isa)
+{
+ xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+ return intisa->num_opcodes;
+}
+
+
+xtensa_opcode
+xtensa_opcode_lookup (xtensa_isa isa, const char *opname)
+{
+ xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+ opname_lookup_entry entry, *result;
+
+ entry.key = opname;
+ result = bsearch (&entry, intisa->opname_lookup_table, intisa->num_opcodes,
+ sizeof (opname_lookup_entry), opname_lookup_compare);
+ if (!result) return XTENSA_UNDEFINED;
+ return result->opcode;
+}
+
+
+xtensa_opcode
+xtensa_decode_insn (xtensa_isa isa, const xtensa_insnbuf insn)
+{
+ xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+ int n, opc;
+ for (n = 0; n < intisa->num_modules; n++) {
+ opc = (intisa->module_decode_fn[n]) (insn);
+ if (opc != XTENSA_UNDEFINED)
+ return intisa->module_opcode_base[n] + opc;
+ }
+ return XTENSA_UNDEFINED;
+}
+
+
+/* Opcode information. */
+
+void
+xtensa_encode_insn (xtensa_isa isa, xtensa_opcode opc, xtensa_insnbuf insn)
+{
+ xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+ xtensa_insnbuf template = intisa->opcode_table[opc]->template();
+ int len = intisa->opcode_table[opc]->length;
+ int n;
+
+ /* Convert length to 32-bit words. */
+ len = (len + 3) / 4;
+
+ /* Copy the template. */
+ for (n = 0; n < len; n++)
+ insn[n] = template[n];
+
+ /* Fill any unused buffer space with zeros. */
+ for ( ; n < intisa->insnbuf_size; n++)
+ insn[n] = 0;
+}
+
+
+const char *
+xtensa_opcode_name (xtensa_isa isa, xtensa_opcode opc)
+{
+ xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+ return intisa->opcode_table[opc]->name;
+}
+
+
+int
+xtensa_insn_length (xtensa_isa isa, xtensa_opcode opc)
+{
+ xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+ return intisa->opcode_table[opc]->length;
+}
+
+
+int
+xtensa_insn_length_from_first_byte (xtensa_isa isa, char first_byte)
+{
+ xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+ int is_density = (first_byte & (intisa->is_big_endian ? 0x80 : 0x08)) != 0;
+ return (intisa->has_density && is_density ? 2 : 3);
+}
+
+
+int
+xtensa_num_operands (xtensa_isa isa, xtensa_opcode opc)
+{
+ xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+ return intisa->opcode_table[opc]->iclass->num_operands;
+}
+
+
+xtensa_operand
+xtensa_get_operand (xtensa_isa isa, xtensa_opcode opc, int opnd)
+{
+ xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+ xtensa_iclass_internal *iclass = intisa->opcode_table[opc]->iclass;
+ if (opnd >= iclass->num_operands)
+ return NULL;
+ return (xtensa_operand) iclass->operands[opnd];
+}
+
+
+/* Operand information. */
+
+char *
+xtensa_operand_kind (xtensa_operand opnd)
+{
+ xtensa_operand_internal *intop = (xtensa_operand_internal *) opnd;
+ return intop->operand_kind;
+}
+
+
+char
+xtensa_operand_inout (xtensa_operand opnd)
+{
+ xtensa_operand_internal *intop = (xtensa_operand_internal *) opnd;
+ return intop->inout;
+}
+
+
+uint32
+xtensa_operand_get_field (xtensa_operand opnd, const xtensa_insnbuf insn)
+{
+ xtensa_operand_internal *intop = (xtensa_operand_internal *) opnd;
+ return (*intop->get_field) (insn);
+}
+
+
+void
+xtensa_operand_set_field (xtensa_operand opnd, xtensa_insnbuf insn, uint32 val)
+{
+ xtensa_operand_internal *intop = (xtensa_operand_internal *) opnd;
+ return (*intop->set_field) (insn, val);
+}
+
+
+xtensa_encode_result
+xtensa_operand_encode (xtensa_operand opnd, uint32 *valp)
+{
+ xtensa_operand_internal *intop = (xtensa_operand_internal *) opnd;
+ return (*intop->encode) (valp);
+}
+
+
+uint32
+xtensa_operand_decode (xtensa_operand opnd, uint32 val)
+{
+ xtensa_operand_internal *intop = (xtensa_operand_internal *) opnd;
+ return (*intop->decode) (val);
+}
+
+
+int
+xtensa_operand_isPCRelative (xtensa_operand opnd)
+{
+ xtensa_operand_internal *intop = (xtensa_operand_internal *) opnd;
+ return intop->isPCRelative;
+}
+
+
+uint32
+xtensa_operand_do_reloc (xtensa_operand opnd, uint32 addr, uint32 pc)
+{
+ xtensa_operand_internal *intop = (xtensa_operand_internal *) opnd;
+ if (!intop->isPCRelative)
+ return addr;
+ return (*intop->do_reloc) (addr, pc);
+}
+
+
+uint32
+xtensa_operand_undo_reloc (xtensa_operand opnd, uint32 offset, uint32 pc)
+{
+ xtensa_operand_internal *intop = (xtensa_operand_internal *) opnd;
+ if (!intop->isPCRelative)
+ return offset;
+ return (*intop->undo_reloc) (offset, pc);
+}
+
+
+/* Instruction buffers. */
+
+xtensa_insnbuf
+xtensa_insnbuf_alloc (xtensa_isa isa)
+{
+ return (xtensa_insnbuf) malloc (xtensa_insnbuf_size (isa) *
+ sizeof (xtensa_insnbuf_word));
+}
+
+
+void
+xtensa_insnbuf_free (xtensa_insnbuf buf)
+{
+ free( buf );
+}
+
+
+/* Given <byte_index>, the index of a byte in a xtensa_insnbuf, our
+ internal representation of a xtensa instruction word, return the index of
+ its word and the bit index of its low order byte in the xtensa_insnbuf. */
+
+static inline int
+byte_to_word_index (int byte_index)
+{
+ return byte_index / sizeof (xtensa_insnbuf_word);
+}
+
+
+static inline int
+byte_to_bit_index (int byte_index)
+{
+ return (byte_index & 0x3) * 8;
+}
+
+
+/* Copy an instruction in the 32 bit words pointed at by <insn> to characters
+ pointed at by <cp>. This is more complicated than you might think because
+ we want 16 bit instructions in bytes 2,3 for big endian. This function
+ allows us to specify which byte in <insn> to start with and which way to
+ increment, allowing trivial implementation for both big and little endian.
+ And it seems to make pretty good code for both. */
+
+void
+xtensa_insnbuf_to_chars (xtensa_isa isa, const xtensa_insnbuf insn, char *cp)
+{
+ xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+ int insn_size = xtensa_insn_maxlength (intisa);
+ int fence_post, start, increment, i, byte_count;
+ xtensa_opcode opc;
+
+ if (intisa->is_big_endian)
+ {
+ start = insn_size - 1;
+ increment = -1;
+ }
+ else
+ {
+ start = 0;
+ increment = 1;
+ }
+
+ /* Find the opcode; do nothing if the buffer does not contain a valid
+ instruction since we need to know how many bytes to copy. */
+ opc = xtensa_decode_insn (isa, insn);
+ if (opc == XTENSA_UNDEFINED)
+ return;
+
+ byte_count = xtensa_insn_length (isa, opc);
+ fence_post = start + (byte_count * increment);
+
+ for (i = start; i != fence_post; i += increment, ++cp)
+ {
+ int word_inx = byte_to_word_index (i);
+ int bit_inx = byte_to_bit_index (i);
+
+ *cp = (insn[word_inx] >> bit_inx) & 0xff;
+ }
+}
+
+/* Inward conversion from byte stream to xtensa_insnbuf. See
+ xtensa_insnbuf_to_chars for a discussion of why this is
+ complicated by endianness. */
+
+void
+xtensa_insnbuf_from_chars (xtensa_isa isa, xtensa_insnbuf insn, const char* cp)
+{
+ xtensa_isa_internal *intisa = (xtensa_isa_internal *) isa;
+ int insn_size = xtensa_insn_maxlength (intisa);
+ int fence_post, start, increment, i;
+
+ if (intisa->is_big_endian)
+ {
+ start = insn_size - 1;
+ increment = -1;
+ }
+ else
+ {
+ start = 0;
+ increment = 1;
+ }
+
+ fence_post = start + (insn_size * increment);
+ memset (insn, 0, xtensa_insnbuf_size (isa) * sizeof (xtensa_insnbuf_word));
+
+ for ( i = start; i != fence_post; i += increment, ++cp )
+ {
+ int word_inx = byte_to_word_index (i);
+ int bit_inx = byte_to_bit_index (i);
+
+ insn[word_inx] |= (*cp & 0xff) << bit_inx;
+ }
+}
+
diff --git a/bfd/xtensa-modules.c b/bfd/xtensa-modules.c
new file mode 100644
index 0000000000..662f72860e
--- /dev/null
+++ b/bfd/xtensa-modules.c
@@ -0,0 +1,6090 @@
+/* Xtensa configuration-specific ISA information.
+ Copyright 2003 Free Software Foundation, Inc.
+
+ 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 2 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Automatically generated by gen-opcode-code - DO NOT EDIT! */
+
+#include <xtensa-isa.h>
+#include "xtensa-isa-internal.h"
+#include "ansidecl.h"
+
+#define BPW 32
+#define WINDEX(_n) ((_n) / BPW)
+#define BINDEX(_n) ((_n) %% BPW)
+
+static uint32 tie_do_reloc_l (uint32, uint32) ATTRIBUTE_UNUSED;
+static uint32 tie_undo_reloc_l (uint32, uint32) ATTRIBUTE_UNUSED;
+
+static uint32
+tie_do_reloc_l (uint32 addr, uint32 pc)
+{
+ return (addr - pc);
+}
+
+static uint32
+tie_undo_reloc_l (uint32 offset, uint32 pc)
+{
+ return (pc + offset);
+}
+
+xtensa_opcode_internal** get_opcodes (void);
+const int get_num_opcodes (void);
+int decode_insn (const xtensa_insnbuf);
+int interface_version (void);
+
+uint32 get_bbi_field (const xtensa_insnbuf);
+void set_bbi_field (xtensa_insnbuf, uint32);
+uint32 get_bbi4_field (const xtensa_insnbuf);
+void set_bbi4_field (xtensa_insnbuf, uint32);
+uint32 get_i_field (const xtensa_insnbuf);
+void set_i_field (xtensa_insnbuf, uint32);
+uint32 get_imm12_field (const xtensa_insnbuf);
+void set_imm12_field (xtensa_insnbuf, uint32);
+uint32 get_imm12b_field (const xtensa_insnbuf);
+void set_imm12b_field (xtensa_insnbuf, uint32);
+uint32 get_imm16_field (const xtensa_insnbuf);
+void set_imm16_field (xtensa_insnbuf, uint32);
+uint32 get_imm4_field (const xtensa_insnbuf);
+void set_imm4_field (xtensa_insnbuf, uint32);
+uint32 get_imm6_field (const xtensa_insnbuf);
+void set_imm6_field (xtensa_insnbuf, uint32);
+uint32 get_imm6hi_field (const xtensa_insnbuf);
+void set_imm6hi_field (xtensa_insnbuf, uint32);
+uint32 get_imm6lo_field (const xtensa_insnbuf);
+void set_imm6lo_field (xtensa_insnbuf, uint32);
+uint32 get_imm7_field (const xtensa_insnbuf);
+void set_imm7_field (xtensa_insnbuf, uint32);
+uint32 get_imm7hi_field (const xtensa_insnbuf);
+void set_imm7hi_field (xtensa_insnbuf, uint32);
+uint32 get_imm7lo_field (const xtensa_insnbuf);
+void set_imm7lo_field (xtensa_insnbuf, uint32);
+uint32 get_imm8_field (const xtensa_insnbuf);
+void set_imm8_field (xtensa_insnbuf, uint32);
+uint32 get_m_field (const xtensa_insnbuf);
+void set_m_field (xtensa_insnbuf, uint32);
+uint32 get_mn_field (const xtensa_insnbuf);
+void set_mn_field (xtensa_insnbuf, uint32);
+uint32 get_n_field (const xtensa_insnbuf);
+void set_n_field (xtensa_insnbuf, uint32);
+uint32 get_none_field (const xtensa_insnbuf);
+void set_none_field (xtensa_insnbuf, uint32);
+uint32 get_offset_field (const xtensa_insnbuf);
+void set_offset_field (xtensa_insnbuf, uint32);
+uint32 get_op0_field (const xtensa_insnbuf);
+void set_op0_field (xtensa_insnbuf, uint32);
+uint32 get_op1_field (const xtensa_insnbuf);
+void set_op1_field (xtensa_insnbuf, uint32);
+uint32 get_op2_field (const xtensa_insnbuf);
+void set_op2_field (xtensa_insnbuf, uint32);
+uint32 get_r_field (const xtensa_insnbuf);
+void set_r_field (xtensa_insnbuf, uint32);
+uint32 get_s_field (const xtensa_insnbuf);
+void set_s_field (xtensa_insnbuf, uint32);
+uint32 get_sa4_field (const xtensa_insnbuf);
+void set_sa4_field (xtensa_insnbuf, uint32);
+uint32 get_sae_field (const xtensa_insnbuf);
+void set_sae_field (xtensa_insnbuf, uint32);
+uint32 get_sae4_field (const xtensa_insnbuf);
+void set_sae4_field (xtensa_insnbuf, uint32);
+uint32 get_sal_field (const xtensa_insnbuf);
+void set_sal_field (xtensa_insnbuf, uint32);
+uint32 get_sar_field (const xtensa_insnbuf);
+void set_sar_field (xtensa_insnbuf, uint32);
+uint32 get_sas_field (const xtensa_insnbuf);
+void set_sas_field (xtensa_insnbuf, uint32);
+uint32 get_sas4_field (const xtensa_insnbuf);
+void set_sas4_field (xtensa_insnbuf, uint32);
+uint32 get_sr_field (const xtensa_insnbuf);
+void set_sr_field (xtensa_insnbuf, uint32);
+uint32 get_t_field (const xtensa_insnbuf);
+void set_t_field (xtensa_insnbuf, uint32);
+uint32 get_thi3_field (const xtensa_insnbuf);
+void set_thi3_field (xtensa_insnbuf, uint32);
+uint32 get_z_field (const xtensa_insnbuf);
+void set_z_field (xtensa_insnbuf, uint32);
+
+
+uint32
+get_bbi_field (const xtensa_insnbuf insn)
+{
+ return ((insn[0] & 0xf0000) >> 16) |
+ ((insn[0] & 0x100) >> 4);
+}
+
+void
+set_bbi_field (xtensa_insnbuf insn, uint32 val)
+{
+ insn[0] = (insn[0] & 0xfff0ffff) | ((val << 16) & 0xf0000);
+ insn[0] = (insn[0] & 0xfffffeff) | ((val << 4) & 0x100);
+}
+
+uint32
+get_bbi4_field (const xtensa_insnbuf insn)
+{
+ return ((insn[0] & 0x100) >> 8);
+}
+
+void
+set_bbi4_field (xtensa_insnbuf insn, uint32 val)
+{
+ insn[0] = (insn[0] & 0xfffffeff) | ((val << 8) & 0x100);
+}
+
+uint32
+get_i_field (const xtensa_insnbuf insn)
+{
+ return ((insn[0] & 0x80000) >> 19);
+}
+
+void
+set_i_field (xtensa_insnbuf insn, uint32 val)
+{
+ insn[0] = (insn[0] & 0xfff7ffff) | ((val << 19) & 0x80000);
+}
+
+uint32
+get_imm12_field (const xtensa_insnbuf insn)
+{
+ return ((insn[0] & 0xfff));
+}
+
+void
+set_imm12_field (xtensa_insnbuf insn, uint32 val)
+{
+ insn[0] = (insn[0] & 0xfffff000) | (val & 0xfff);
+}
+
+uint32
+get_imm12b_field (const xtensa_insnbuf insn)
+{
+ return ((insn[0] & 0xff)) |
+ ((insn[0] & 0xf000) >> 4);
+}
+
+void
+set_imm12b_field (xtensa_insnbuf insn, uint32 val)
+{
+ insn[0] = (insn[0] & 0xffffff00) | (val & 0xff);
+ insn[0] = (insn[0] & 0xffff0fff) | ((val << 4) & 0xf000);
+}
+
+uint32
+get_imm16_field (const xtensa_insnbuf insn)
+{
+ return ((insn[0] & 0xffff));
+}
+
+void
+set_imm16_field (xtensa_insnbuf insn, uint32 val)
+{
+ insn[0] = (insn[0] & 0xffff0000) | (val & 0xffff);
+}
+
+uint32
+get_imm4_field (const xtensa_insnbuf insn)
+{
+ return ((insn[0] & 0xf00) >> 8);
+}
+
+void
+set_imm4_field (xtensa_insnbuf insn, uint32 val)
+{
+ insn[0] = (insn[0] & 0xfffff0ff) | ((val << 8) & 0xf00);
+}
+
+uint32
+get_imm6_field (const xtensa_insnbuf insn)
+{
+ return ((insn[0] & 0xf00) >> 8) |
+ ((insn[0] & 0x30000) >> 12);
+}
+
+void
+set_imm6_field (xtensa_insnbuf insn, uint32 val)
+{
+ insn[0] = (insn[0] & 0xfffff0ff) | ((val << 8) & 0xf00);
+ insn[0] = (insn[0] & 0xfffcffff) | ((val << 12) & 0x30000);
+}
+
+uint32
+get_imm6hi_field (const xtensa_insnbuf insn)
+{
+ return ((insn[0] & 0x30000) >> 16);
+}
+
+void
+set_imm6hi_field (xtensa_insnbuf insn, uint32 val)
+{
+ insn[0] = (insn[0] & 0xfffcffff) | ((val << 16) & 0x30000);
+}
+
+uint32
+get_imm6lo_field (const xtensa_insnbuf insn)
+{
+ return ((insn[0] & 0xf00) >> 8);
+}
+
+void
+set_imm6lo_field (xtensa_insnbuf insn, uint32 val)
+{
+ insn[0] = (insn[0] & 0xfffff0ff) | ((val << 8) & 0xf00);
+}
+
+uint32
+get_imm7_field (const xtensa_insnbuf insn)
+{
+ return ((insn[0] & 0xf00) >> 8) |
+ ((insn[0] & 0x70000) >> 12);
+}
+
+void
+set_imm7_field (xtensa_insnbuf insn, uint32 val)
+{
+ insn[0] = (insn[0] & 0xfffff0ff) | ((val << 8) & 0xf00);
+ insn[0] = (insn[0] & 0xfff8ffff) | ((val << 12) & 0x70000);
+}
+
+uint32
+get_imm7hi_field (const xtensa_insnbuf insn)
+{
+ return ((insn[0] & 0x70000) >> 16);
+}
+
+void
+set_imm7hi_field (xtensa_insnbuf insn, uint32 val)
+{
+ insn[0] = (insn[0] & 0xfff8ffff) | ((val << 16) & 0x70000);
+}
+
+uint32
+get_imm7lo_field (const xtensa_insnbuf insn)
+{
+ return ((insn[0] & 0xf00) >> 8);
+}
+
+void
+set_imm7lo_field (xtensa_insnbuf insn, uint32 val)
+{
+ insn[0] = (insn[0] & 0xfffff0ff) | ((val << 8) & 0xf00);
+}
+
+uint32
+get_imm8_field (const xtensa_insnbuf insn)
+{
+ return ((insn[0] & 0xff));
+}
+
+void
+set_imm8_field (xtensa_insnbuf insn, uint32 val)
+{
+ insn[0] = (insn[0] & 0xffffff00) | (val & 0xff);
+}
+
+uint32
+get_m_field (const xtensa_insnbuf insn)
+{
+ return ((insn[0] & 0x30000) >> 16);
+}
+
+void
+set_m_field (xtensa_insnbuf insn, uint32 val)
+{
+ insn[0] = (insn[0] & 0xfffcffff) | ((val << 16) & 0x30000);
+}
+
+uint32
+get_mn_field (const xtensa_insnbuf insn)
+{
+ return ((insn[0] & 0x30000) >> 16) |
+ ((insn[0] & 0xc0000) >> 16);
+}
+
+void
+set_mn_field (xtensa_insnbuf insn, uint32 val)
+{
+ insn[0] = (insn[0] & 0xfffcffff) | ((val << 16) & 0x30000);
+ insn[0] = (insn[0] & 0xfff3ffff) | ((val << 16) & 0xc0000);
+}
+
+uint32
+get_n_field (const xtensa_insnbuf insn)
+{
+ return ((insn[0] & 0xc0000) >> 18);
+}
+
+void
+set_n_field (xtensa_insnbuf insn, uint32 val)
+{
+ insn[0] = (insn[0] & 0xfff3ffff) | ((val << 18) & 0xc0000);
+}
+
+uint32
+get_none_field (const xtensa_insnbuf insn)
+{
+ return ((insn[0] & 0x0));
+}
+
+void
+set_none_field (xtensa_insnbuf insn, uint32 val)
+{
+ insn[0] = (insn[0] & 0xffffffff) | (val & 0x0);
+}
+
+uint32
+get_offset_field (const xtensa_insnbuf insn)
+{
+ return ((insn[0] & 0x3ffff));
+}
+
+void
+set_offset_field (xtensa_insnbuf insn, uint32 val)
+{
+ insn[0] = (insn[0] & 0xfffc0000) | (val & 0x3ffff);
+}
+
+uint32
+get_op0_field (const xtensa_insnbuf insn)
+{
+ return ((insn[0] & 0xf00000) >> 20);
+}
+
+void
+set_op0_field (xtensa_insnbuf insn, uint32 val)
+{
+ insn[0] = (insn[0] & 0xff0fffff) | ((val << 20) & 0xf00000);
+}
+
+uint32
+get_op1_field (const xtensa_insnbuf insn)
+{
+ return ((insn[0] & 0xf0) >> 4);
+}
+
+void
+set_op1_field (xtensa_insnbuf insn, uint32 val)
+{
+ insn[0] = (insn[0] & 0xffffff0f) | ((val << 4) & 0xf0);
+}
+
+uint32
+get_op2_field (const xtensa_insnbuf insn)
+{
+ return ((insn[0] & 0xf));
+}
+
+void
+set_op2_field (xtensa_insnbuf insn, uint32 val)
+{
+ insn[0] = (insn[0] & 0xfffffff0) | (val & 0xf);
+}
+
+uint32
+get_r_field (const xtensa_insnbuf insn)
+{
+ return ((insn[0] & 0xf00) >> 8);
+}
+
+void
+set_r_field (xtensa_insnbuf insn, uint32 val)
+{
+ insn[0] = (insn[0] & 0xfffff0ff) | ((val << 8) & 0xf00);
+}
+
+uint32
+get_s_field (const xtensa_insnbuf insn)
+{
+ return ((insn[0] & 0xf000) >> 12);
+}
+
+void
+set_s_field (xtensa_insnbuf insn, uint32 val)
+{
+ insn[0] = (insn[0] & 0xffff0fff) | ((val << 12) & 0xf000);
+}
+
+uint32
+get_sa4_field (const xtensa_insnbuf insn)
+{
+ return ((insn[0] & 0x1));
+}
+
+void
+set_sa4_field (xtensa_insnbuf insn, uint32 val)
+{
+ insn[0] = (insn[0] & 0xfffffffe) | (val & 0x1);
+}
+
+uint32
+get_sae_field (const xtensa_insnbuf insn)
+{
+ return ((insn[0] & 0xf000) >> 12) |
+ ((insn[0] & 0x10));
+}
+
+void
+set_sae_field (xtensa_insnbuf insn, uint32 val)
+{
+ insn[0] = (insn[0] & 0xffff0fff) | ((val << 12) & 0xf000);
+ insn[0] = (insn[0] & 0xffffffef) | (val & 0x10);
+}
+
+uint32
+get_sae4_field (const xtensa_insnbuf insn)
+{
+ return ((insn[0] & 0x10) >> 4);
+}
+
+void
+set_sae4_field (xtensa_insnbuf insn, uint32 val)
+{
+ insn[0] = (insn[0] & 0xffffffef) | ((val << 4) & 0x10);
+}
+
+uint32
+get_sal_field (const xtensa_insnbuf insn)
+{
+ return ((insn[0] & 0xf0000) >> 16) |
+ ((insn[0] & 0x1) << 4);
+}
+
+void
+set_sal_field (xtensa_insnbuf insn, uint32 val)
+{
+ insn[0] = (insn[0] & 0xfff0ffff) | ((val << 16) & 0xf0000);
+ insn[0] = (insn[0] & 0xfffffffe) | ((val >> 4) & 0x1);
+}
+
+uint32
+get_sar_field (const xtensa_insnbuf insn)
+{
+ return ((insn[0] & 0xf000) >> 12) |
+ ((insn[0] & 0x1) << 4);
+}
+
+void
+set_sar_field (xtensa_insnbuf insn, uint32 val)
+{
+ insn[0] = (insn[0] & 0xffff0fff) | ((val << 12) & 0xf000);
+ insn[0] = (insn[0] & 0xfffffffe) | ((val >> 4) & 0x1);
+}
+
+uint32
+get_sas_field (const xtensa_insnbuf insn)
+{
+ return ((insn[0] & 0xf000) >> 12) |
+ ((insn[0] & 0x10000) >> 12);
+}
+
+void
+set_sas_field (xtensa_insnbuf insn, uint32 val)
+{
+ insn[0] = (insn[0] & 0xffff0fff) | ((val << 12) & 0xf000);
+ insn[0] = (insn[0] & 0xfffeffff) | ((val << 12) & 0x10000);
+}
+
+uint32
+get_sas4_field (const xtensa_insnbuf insn)
+{
+ return ((insn[0] & 0x10000) >> 16);
+}
+
+void
+set_sas4_field (xtensa_insnbuf insn, uint32 val)
+{
+ insn[0] = (insn[0] & 0xfffeffff) | ((val << 16) & 0x10000);
+}
+
+uint32
+get_sr_field (const xtensa_insnbuf insn)
+{
+ return ((insn[0] & 0xf00) >> 8) |
+ ((insn[0] & 0xf000) >> 8);
+}
+
+void
+set_sr_field (xtensa_insnbuf insn, uint32 val)
+{
+ insn[0] = (insn[0] & 0xfffff0ff) | ((val << 8) & 0xf00);
+ insn[0] = (insn[0] & 0xffff0fff) | ((val << 8) & 0xf000);
+}
+
+uint32
+get_t_field (const xtensa_insnbuf insn)
+{
+ return ((insn[0] & 0xf0000) >> 16);
+}
+
+void
+set_t_field (xtensa_insnbuf insn, uint32 val)
+{
+ insn[0] = (insn[0] & 0xfff0ffff) | ((val << 16) & 0xf0000);
+}
+
+uint32
+get_thi3_field (const xtensa_insnbuf insn)
+{
+ return ((insn[0] & 0xe0000) >> 17);
+}
+
+void
+set_thi3_field (xtensa_insnbuf insn, uint32 val)
+{
+ insn[0] = (insn[0] & 0xfff1ffff) | ((val << 17) & 0xe0000);
+}
+
+uint32
+get_z_field (const xtensa_insnbuf insn)
+{
+ return ((insn[0] & 0x40000) >> 18);
+}
+
+void
+set_z_field (xtensa_insnbuf insn, uint32 val)
+{
+ insn[0] = (insn[0] & 0xfffbffff) | ((val << 18) & 0x40000);
+}
+
+uint32 decode_b4constu (uint32);
+xtensa_encode_result encode_b4constu (uint32 *);
+uint32 decode_simm8x256 (uint32);
+xtensa_encode_result encode_simm8x256 (uint32 *);
+uint32 decode_soffset (uint32);
+xtensa_encode_result encode_soffset (uint32 *);
+uint32 decode_imm4 (uint32);
+xtensa_encode_result encode_imm4 (uint32 *);
+uint32 decode_op0 (uint32);
+xtensa_encode_result encode_op0 (uint32 *);
+uint32 decode_op1 (uint32);
+xtensa_encode_result encode_op1 (uint32 *);
+uint32 decode_imm6 (uint32);
+xtensa_encode_result encode_imm6 (uint32 *);
+uint32 decode_op2 (uint32);
+xtensa_encode_result encode_op2 (uint32 *);
+uint32 decode_imm7 (uint32);
+xtensa_encode_result encode_imm7 (uint32 *);
+uint32 decode_simm4 (uint32);
+xtensa_encode_result encode_simm4 (uint32 *);
+uint32 decode_ai4const (uint32);
+xtensa_encode_result encode_ai4const (uint32 *);
+uint32 decode_imm8 (uint32);
+xtensa_encode_result encode_imm8 (uint32 *);
+uint32 decode_sae (uint32);
+xtensa_encode_result encode_sae (uint32 *);
+uint32 decode_imm7lo (uint32);
+xtensa_encode_result encode_imm7lo (uint32 *);
+uint32 decode_simm7 (uint32);
+xtensa_encode_result encode_simm7 (uint32 *);
+uint32 decode_simm8 (uint32);
+xtensa_encode_result encode_simm8 (uint32 *);
+uint32 decode_uimm12x8 (uint32);
+xtensa_encode_result encode_uimm12x8 (uint32 *);
+uint32 decode_sal (uint32);
+xtensa_encode_result encode_sal (uint32 *);
+uint32 decode_uimm6 (uint32);
+xtensa_encode_result encode_uimm6 (uint32 *);
+uint32 decode_sas4 (uint32);
+xtensa_encode_result encode_sas4 (uint32 *);
+uint32 decode_uimm8 (uint32);
+xtensa_encode_result encode_uimm8 (uint32 *);
+uint32 decode_uimm16x4 (uint32);
+xtensa_encode_result encode_uimm16x4 (uint32 *);
+uint32 decode_sar (uint32);
+xtensa_encode_result encode_sar (uint32 *);
+uint32 decode_sa4 (uint32);
+xtensa_encode_result encode_sa4 (uint32 *);
+uint32 decode_sas (uint32);
+xtensa_encode_result encode_sas (uint32 *);
+uint32 decode_imm6hi (uint32);
+xtensa_encode_result encode_imm6hi (uint32 *);
+uint32 decode_bbi (uint32);
+xtensa_encode_result encode_bbi (uint32 *);
+uint32 decode_uimm8x2 (uint32);
+xtensa_encode_result encode_uimm8x2 (uint32 *);
+uint32 decode_uimm8x4 (uint32);
+xtensa_encode_result encode_uimm8x4 (uint32 *);
+uint32 decode_msalp32 (uint32);
+xtensa_encode_result encode_msalp32 (uint32 *);
+uint32 decode_bbi4 (uint32);
+xtensa_encode_result encode_bbi4 (uint32 *);
+uint32 decode_op2p1 (uint32);
+xtensa_encode_result encode_op2p1 (uint32 *);
+uint32 decode_soffsetx4 (uint32);
+xtensa_encode_result encode_soffsetx4 (uint32 *);
+uint32 decode_imm6lo (uint32);
+xtensa_encode_result encode_imm6lo (uint32 *);
+uint32 decode_imm12 (uint32);
+xtensa_encode_result encode_imm12 (uint32 *);
+uint32 decode_b4const (uint32);
+xtensa_encode_result encode_b4const (uint32 *);
+uint32 decode_i (uint32);
+xtensa_encode_result encode_i (uint32 *);
+uint32 decode_imm16 (uint32);
+xtensa_encode_result encode_imm16 (uint32 *);
+uint32 decode_mn (uint32);
+xtensa_encode_result encode_mn (uint32 *);
+uint32 decode_m (uint32);
+xtensa_encode_result encode_m (uint32 *);
+uint32 decode_n (uint32);
+xtensa_encode_result encode_n (uint32 *);
+uint32 decode_none (uint32);
+xtensa_encode_result encode_none (uint32 *);
+uint32 decode_imm12b (uint32);
+xtensa_encode_result encode_imm12b (uint32 *);
+uint32 decode_r (uint32);
+xtensa_encode_result encode_r (uint32 *);
+uint32 decode_s (uint32);
+xtensa_encode_result encode_s (uint32 *);
+uint32 decode_t (uint32);
+xtensa_encode_result encode_t (uint32 *);
+uint32 decode_thi3 (uint32);
+xtensa_encode_result encode_thi3 (uint32 *);
+uint32 decode_sae4 (uint32);
+xtensa_encode_result encode_sae4 (uint32 *);
+uint32 decode_offset (uint32);
+xtensa_encode_result encode_offset (uint32 *);
+uint32 decode_imm7hi (uint32);
+xtensa_encode_result encode_imm7hi (uint32 *);
+uint32 decode_uimm4x16 (uint32);
+xtensa_encode_result encode_uimm4x16 (uint32 *);
+uint32 decode_simm12b (uint32);
+xtensa_encode_result encode_simm12b (uint32 *);
+uint32 decode_lsi4x4 (uint32);
+xtensa_encode_result encode_lsi4x4 (uint32 *);
+uint32 decode_z (uint32);
+xtensa_encode_result encode_z (uint32 *);
+uint32 decode_simm12 (uint32);
+xtensa_encode_result encode_simm12 (uint32 *);
+uint32 decode_sr (uint32);
+xtensa_encode_result encode_sr (uint32 *);
+uint32 decode_nimm4x2 (uint32);
+xtensa_encode_result encode_nimm4x2 (uint32 *);
+
+
+static const uint32 b4constu_table[] = {
+ 32768,
+ 65536,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 10,
+ 12,
+ 16,
+ 32,
+ 64,
+ 128,
+ 256
+};
+
+uint32
+decode_b4constu (uint32 val)
+{
+ val = b4constu_table[val];
+ return val;
+}
+
+xtensa_encode_result
+encode_b4constu (uint32 *valp)
+{
+ uint32 val = *valp;
+ unsigned i;
+ for (i = 0; i < (1 << 4); i += 1)
+ if (b4constu_table[i] == val) goto found;
+ return xtensa_encode_result_not_in_table;
+ found:
+ val = i;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_simm8x256 (uint32 val)
+{
+ val = (val ^ 0x80) - 0x80;
+ val <<= 8;
+ return val;
+}
+
+xtensa_encode_result
+encode_simm8x256 (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val & ((1 << 8) - 1)) != 0)
+ return xtensa_encode_result_align;
+ val = (signed int) val >> 8;
+ if (((val + (1 << 7)) >> 8) != 0)
+ {
+ if ((signed int) val > 0)
+ return xtensa_encode_result_too_high;
+ else
+ return xtensa_encode_result_too_low;
+ }
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_soffset (uint32 val)
+{
+ val = (val ^ 0x20000) - 0x20000;
+ return val;
+}
+
+xtensa_encode_result
+encode_soffset (uint32 *valp)
+{
+ uint32 val = *valp;
+ if (((val + (1 << 17)) >> 18) != 0)
+ {
+ if ((signed int) val > 0)
+ return xtensa_encode_result_too_high;
+ else
+ return xtensa_encode_result_too_low;
+ }
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_imm4 (uint32 val)
+{
+ return val;
+}
+
+xtensa_encode_result
+encode_imm4 (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val >> 4) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_op0 (uint32 val)
+{
+ return val;
+}
+
+xtensa_encode_result
+encode_op0 (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val >> 4) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_op1 (uint32 val)
+{
+ return val;
+}
+
+xtensa_encode_result
+encode_op1 (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val >> 4) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_imm6 (uint32 val)
+{
+ return val;
+}
+
+xtensa_encode_result
+encode_imm6 (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val >> 6) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_op2 (uint32 val)
+{
+ return val;
+}
+
+xtensa_encode_result
+encode_op2 (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val >> 4) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_imm7 (uint32 val)
+{
+ return val;
+}
+
+xtensa_encode_result
+encode_imm7 (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val >> 7) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_simm4 (uint32 val)
+{
+ val = (val ^ 0x8) - 0x8;
+ return val;
+}
+
+xtensa_encode_result
+encode_simm4 (uint32 *valp)
+{
+ uint32 val = *valp;
+ if (((val + (1 << 3)) >> 4) != 0)
+ {
+ if ((signed int) val > 0)
+ return xtensa_encode_result_too_high;
+ else
+ return xtensa_encode_result_too_low;
+ }
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+static const uint32 ai4const_table[] = {
+ -1,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15
+};
+
+uint32
+decode_ai4const (uint32 val)
+{
+ val = ai4const_table[val];
+ return val;
+}
+
+xtensa_encode_result
+encode_ai4const (uint32 *valp)
+{
+ uint32 val = *valp;
+ unsigned i;
+ for (i = 0; i < (1 << 4); i += 1)
+ if (ai4const_table[i] == val) goto found;
+ return xtensa_encode_result_not_in_table;
+ found:
+ val = i;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_imm8 (uint32 val)
+{
+ return val;
+}
+
+xtensa_encode_result
+encode_imm8 (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val >> 8) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_sae (uint32 val)
+{
+ return val;
+}
+
+xtensa_encode_result
+encode_sae (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val >> 5) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_imm7lo (uint32 val)
+{
+ return val;
+}
+
+xtensa_encode_result
+encode_imm7lo (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val >> 4) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_simm7 (uint32 val)
+{
+ if (val > 95)
+ val |= -32;
+ return val;
+}
+
+xtensa_encode_result
+encode_simm7 (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((signed int) val < -32)
+ return xtensa_encode_result_too_low;
+ if ((signed int) val > 95)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_simm8 (uint32 val)
+{
+ val = (val ^ 0x80) - 0x80;
+ return val;
+}
+
+xtensa_encode_result
+encode_simm8 (uint32 *valp)
+{
+ uint32 val = *valp;
+ if (((val + (1 << 7)) >> 8) != 0)
+ {
+ if ((signed int) val > 0)
+ return xtensa_encode_result_too_high;
+ else
+ return xtensa_encode_result_too_low;
+ }
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_uimm12x8 (uint32 val)
+{
+ val <<= 3;
+ return val;
+}
+
+xtensa_encode_result
+encode_uimm12x8 (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val & ((1 << 3) - 1)) != 0)
+ return xtensa_encode_result_align;
+ val = (signed int) val >> 3;
+ if ((val >> 12) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_sal (uint32 val)
+{
+ return val;
+}
+
+xtensa_encode_result
+encode_sal (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val >> 5) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_uimm6 (uint32 val)
+{
+ return val;
+}
+
+xtensa_encode_result
+encode_uimm6 (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val >> 6) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_sas4 (uint32 val)
+{
+ return val;
+}
+
+xtensa_encode_result
+encode_sas4 (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val >> 1) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_uimm8 (uint32 val)
+{
+ return val;
+}
+
+xtensa_encode_result
+encode_uimm8 (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val >> 8) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_uimm16x4 (uint32 val)
+{
+ val |= -1 << 16;
+ val <<= 2;
+ return val;
+}
+
+xtensa_encode_result
+encode_uimm16x4 (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val & ((1 << 2) - 1)) != 0)
+ return xtensa_encode_result_align;
+ val = (signed int) val >> 2;
+ if ((signed int) val >> 16 != -1)
+ {
+ if ((signed int) val >= 0)
+ return xtensa_encode_result_too_high;
+ else
+ return xtensa_encode_result_too_low;
+ }
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_sar (uint32 val)
+{
+ return val;
+}
+
+xtensa_encode_result
+encode_sar (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val >> 5) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_sa4 (uint32 val)
+{
+ return val;
+}
+
+xtensa_encode_result
+encode_sa4 (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val >> 1) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_sas (uint32 val)
+{
+ return val;
+}
+
+xtensa_encode_result
+encode_sas (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val >> 5) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_imm6hi (uint32 val)
+{
+ return val;
+}
+
+xtensa_encode_result
+encode_imm6hi (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val >> 2) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_bbi (uint32 val)
+{
+ return val;
+}
+
+xtensa_encode_result
+encode_bbi (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val >> 5) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_uimm8x2 (uint32 val)
+{
+ val <<= 1;
+ return val;
+}
+
+xtensa_encode_result
+encode_uimm8x2 (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val & ((1 << 1) - 1)) != 0)
+ return xtensa_encode_result_align;
+ val = (signed int) val >> 1;
+ if ((val >> 8) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_uimm8x4 (uint32 val)
+{
+ val <<= 2;
+ return val;
+}
+
+xtensa_encode_result
+encode_uimm8x4 (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val & ((1 << 2) - 1)) != 0)
+ return xtensa_encode_result_align;
+ val = (signed int) val >> 2;
+ if ((val >> 8) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+static const uint32 mip32const_table[] = {
+ 32,
+ 31,
+ 30,
+ 29,
+ 28,
+ 27,
+ 26,
+ 25,
+ 24,
+ 23,
+ 22,
+ 21,
+ 20,
+ 19,
+ 18,
+ 17,
+ 16,
+ 15,
+ 14,
+ 13,
+ 12,
+ 11,
+ 10,
+ 9,
+ 8,
+ 7,
+ 6,
+ 5,
+ 4,
+ 3,
+ 2,
+ 1
+};
+
+uint32
+decode_msalp32 (uint32 val)
+{
+ val = mip32const_table[val];
+ return val;
+}
+
+xtensa_encode_result
+encode_msalp32 (uint32 *valp)
+{
+ uint32 val = *valp;
+ unsigned i;
+ for (i = 0; i < (1 << 5); i += 1)
+ if (mip32const_table[i] == val) goto found;
+ return xtensa_encode_result_not_in_table;
+ found:
+ val = i;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_bbi4 (uint32 val)
+{
+ return val;
+}
+
+xtensa_encode_result
+encode_bbi4 (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val >> 1) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+static const uint32 i4p1const_table[] = {
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 16
+};
+
+uint32
+decode_op2p1 (uint32 val)
+{
+ val = i4p1const_table[val];
+ return val;
+}
+
+xtensa_encode_result
+encode_op2p1 (uint32 *valp)
+{
+ uint32 val = *valp;
+ unsigned i;
+ for (i = 0; i < (1 << 4); i += 1)
+ if (i4p1const_table[i] == val) goto found;
+ return xtensa_encode_result_not_in_table;
+ found:
+ val = i;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_soffsetx4 (uint32 val)
+{
+ val = (val ^ 0x20000) - 0x20000;
+ val <<= 2;
+ return val;
+}
+
+xtensa_encode_result
+encode_soffsetx4 (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val & ((1 << 2) - 1)) != 0)
+ return xtensa_encode_result_align;
+ val = (signed int) val >> 2;
+ if (((val + (1 << 17)) >> 18) != 0)
+ {
+ if ((signed int) val > 0)
+ return xtensa_encode_result_too_high;
+ else
+ return xtensa_encode_result_too_low;
+ }
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_imm6lo (uint32 val)
+{
+ return val;
+}
+
+xtensa_encode_result
+encode_imm6lo (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val >> 4) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_imm12 (uint32 val)
+{
+ return val;
+}
+
+xtensa_encode_result
+encode_imm12 (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val >> 12) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+static const uint32 b4const_table[] = {
+ -1,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 10,
+ 12,
+ 16,
+ 32,
+ 64,
+ 128,
+ 256
+};
+
+uint32
+decode_b4const (uint32 val)
+{
+ val = b4const_table[val];
+ return val;
+}
+
+xtensa_encode_result
+encode_b4const (uint32 *valp)
+{
+ uint32 val = *valp;
+ unsigned i;
+ for (i = 0; i < (1 << 4); i += 1)
+ if (b4const_table[i] == val) goto found;
+ return xtensa_encode_result_not_in_table;
+ found:
+ val = i;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_i (uint32 val)
+{
+ return val;
+}
+
+xtensa_encode_result
+encode_i (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val >> 1) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_imm16 (uint32 val)
+{
+ return val;
+}
+
+xtensa_encode_result
+encode_imm16 (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val >> 16) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_mn (uint32 val)
+{
+ return val;
+}
+
+xtensa_encode_result
+encode_mn (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val >> 4) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_m (uint32 val)
+{
+ return val;
+}
+
+xtensa_encode_result
+encode_m (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val >> 2) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_n (uint32 val)
+{
+ return val;
+}
+
+xtensa_encode_result
+encode_n (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val >> 2) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_none (uint32 val)
+{
+ return val;
+}
+
+xtensa_encode_result
+encode_none (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val >> 0) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_imm12b (uint32 val)
+{
+ return val;
+}
+
+xtensa_encode_result
+encode_imm12b (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val >> 12) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_r (uint32 val)
+{
+ return val;
+}
+
+xtensa_encode_result
+encode_r (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val >> 4) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_s (uint32 val)
+{
+ return val;
+}
+
+xtensa_encode_result
+encode_s (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val >> 4) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_t (uint32 val)
+{
+ return val;
+}
+
+xtensa_encode_result
+encode_t (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val >> 4) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_thi3 (uint32 val)
+{
+ return val;
+}
+
+xtensa_encode_result
+encode_thi3 (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val >> 3) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_sae4 (uint32 val)
+{
+ return val;
+}
+
+xtensa_encode_result
+encode_sae4 (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val >> 1) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_offset (uint32 val)
+{
+ return val;
+}
+
+xtensa_encode_result
+encode_offset (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val >> 18) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_imm7hi (uint32 val)
+{
+ return val;
+}
+
+xtensa_encode_result
+encode_imm7hi (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val >> 3) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_uimm4x16 (uint32 val)
+{
+ val <<= 4;
+ return val;
+}
+
+xtensa_encode_result
+encode_uimm4x16 (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val & ((1 << 4) - 1)) != 0)
+ return xtensa_encode_result_align;
+ val = (signed int) val >> 4;
+ if ((val >> 4) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_simm12b (uint32 val)
+{
+ val = (val ^ 0x800) - 0x800;
+ return val;
+}
+
+xtensa_encode_result
+encode_simm12b (uint32 *valp)
+{
+ uint32 val = *valp;
+ if (((val + (1 << 11)) >> 12) != 0)
+ {
+ if ((signed int) val > 0)
+ return xtensa_encode_result_too_high;
+ else
+ return xtensa_encode_result_too_low;
+ }
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_lsi4x4 (uint32 val)
+{
+ val <<= 2;
+ return val;
+}
+
+xtensa_encode_result
+encode_lsi4x4 (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val & ((1 << 2) - 1)) != 0)
+ return xtensa_encode_result_align;
+ val = (signed int) val >> 2;
+ if ((val >> 4) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_z (uint32 val)
+{
+ return val;
+}
+
+xtensa_encode_result
+encode_z (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val >> 1) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_simm12 (uint32 val)
+{
+ val = (val ^ 0x800) - 0x800;
+ return val;
+}
+
+xtensa_encode_result
+encode_simm12 (uint32 *valp)
+{
+ uint32 val = *valp;
+ if (((val + (1 << 11)) >> 12) != 0)
+ {
+ if ((signed int) val > 0)
+ return xtensa_encode_result_too_high;
+ else
+ return xtensa_encode_result_too_low;
+ }
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_sr (uint32 val)
+{
+ return val;
+}
+
+xtensa_encode_result
+encode_sr (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val >> 8) != 0)
+ return xtensa_encode_result_too_high;
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+uint32
+decode_nimm4x2 (uint32 val)
+{
+ val |= -1 << 4;
+ val <<= 2;
+ return val;
+}
+
+xtensa_encode_result
+encode_nimm4x2 (uint32 *valp)
+{
+ uint32 val = *valp;
+ if ((val & ((1 << 2) - 1)) != 0)
+ return xtensa_encode_result_align;
+ val = (signed int) val >> 2;
+ if ((signed int) val >> 4 != -1)
+ {
+ if ((signed int) val >= 0)
+ return xtensa_encode_result_too_high;
+ else
+ return xtensa_encode_result_too_low;
+ }
+ *valp = val;
+ return xtensa_encode_result_ok;
+}
+
+
+
+uint32 do_reloc_l (uint32, uint32);
+uint32 undo_reloc_l (uint32, uint32);
+uint32 do_reloc_L (uint32, uint32);
+uint32 undo_reloc_L (uint32, uint32);
+uint32 do_reloc_r (uint32, uint32);
+uint32 undo_reloc_r (uint32, uint32);
+
+
+uint32
+do_reloc_l (uint32 addr, uint32 pc)
+{
+ return addr - pc - 4;
+}
+
+uint32
+undo_reloc_l (uint32 offset, uint32 pc)
+{
+ return pc + offset + 4;
+}
+
+uint32
+do_reloc_L (uint32 addr, uint32 pc)
+{
+ return addr - (pc & -4) - 4;
+}
+
+uint32
+undo_reloc_L (uint32 offset, uint32 pc)
+{
+ return (pc & -4) + offset + 4;
+}
+
+uint32
+do_reloc_r (uint32 addr, uint32 pc)
+{
+ return addr - ((pc+3) & -4);
+}
+
+uint32
+undo_reloc_r (uint32 offset, uint32 pc)
+{
+ return ((pc+3) & -4) + offset;
+}
+
+static xtensa_operand_internal iib4const_operand = {
+ "i",
+ '<',
+ 0,
+ get_r_field,
+ set_r_field,
+ encode_b4const,
+ decode_b4const,
+ 0,
+ 0
+};
+
+static xtensa_operand_internal iiuimm8_operand = {
+ "i",
+ '<',
+ 0,
+ get_imm8_field,
+ set_imm8_field,
+ encode_uimm8,
+ decode_uimm8,
+ 0,
+ 0
+};
+
+static xtensa_operand_internal lisoffsetx4_operand = {
+ "L",
+ '<',
+ 1,
+ get_offset_field,
+ set_offset_field,
+ encode_soffsetx4,
+ decode_soffsetx4,
+ do_reloc_L,
+ undo_reloc_L,
+};
+
+static xtensa_operand_internal iisimm8x256_operand = {
+ "i",
+ '<',
+ 0,
+ get_imm8_field,
+ set_imm8_field,
+ encode_simm8x256,
+ decode_simm8x256,
+ 0,
+ 0
+};
+
+static xtensa_operand_internal lisimm12_operand = {
+ "l",
+ '<',
+ 1,
+ get_imm12_field,
+ set_imm12_field,
+ encode_simm12,
+ decode_simm12,
+ do_reloc_l,
+ undo_reloc_l,
+};
+
+static xtensa_operand_internal iiop2p1_operand = {
+ "i",
+ '<',
+ 0,
+ get_op2_field,
+ set_op2_field,
+ encode_op2p1,
+ decode_op2p1,
+ 0,
+ 0
+};
+
+static xtensa_operand_internal iisae_operand = {
+ "i",
+ '<',
+ 0,
+ get_sae_field,
+ set_sae_field,
+ encode_sae,
+ decode_sae,
+ 0,
+ 0
+};
+
+static xtensa_operand_internal iis_operand = {
+ "i",
+ '<',
+ 0,
+ get_s_field,
+ set_s_field,
+ encode_s,
+ decode_s,
+ 0,
+ 0
+};
+
+static xtensa_operand_internal iit_operand = {
+ "i",
+ '<',
+ 0,
+ get_t_field,
+ set_t_field,
+ encode_t,
+ decode_t,
+ 0,
+ 0
+};
+
+static xtensa_operand_internal iisimm12b_operand = {
+ "i",
+ '<',
+ 0,
+ get_imm12b_field,
+ set_imm12b_field,
+ encode_simm12b,
+ decode_simm12b,
+ 0,
+ 0
+};
+
+static xtensa_operand_internal iinimm4x2_operand = {
+ "i",
+ '<',
+ 0,
+ get_imm4_field,
+ set_imm4_field,
+ encode_nimm4x2,
+ decode_nimm4x2,
+ 0,
+ 0
+};
+
+static xtensa_operand_internal iiuimm4x16_operand = {
+ "i",
+ '<',
+ 0,
+ get_op2_field,
+ set_op2_field,
+ encode_uimm4x16,
+ decode_uimm4x16,
+ 0,
+ 0
+};
+
+static xtensa_operand_internal abs_operand = {
+ "a",
+ '=',
+ 0,
+ get_s_field,
+ set_s_field,
+ encode_s,
+ decode_s,
+ 0,
+ 0
+};
+
+static xtensa_operand_internal iisar_operand = {
+ "i",
+ '<',
+ 0,
+ get_sar_field,
+ set_sar_field,
+ encode_sar,
+ decode_sar,
+ 0,
+ 0
+};
+
+static xtensa_operand_internal abt_operand = {
+ "a",
+ '=',
+ 0,
+ get_t_field,
+ set_t_field,
+ encode_t,
+ decode_t,
+ 0,
+ 0
+};
+
+static xtensa_operand_internal iisas_operand = {
+ "i",
+ '<',
+ 0,
+ get_sas_field,
+ set_sas_field,
+ encode_sas,
+ decode_sas,
+ 0,
+ 0
+};
+
+static xtensa_operand_internal amr_operand = {
+ "a",
+ '=',
+ 0,
+ get_r_field,
+ set_r_field,
+ encode_r,
+ decode_r,
+ 0,
+ 0
+};
+
+static xtensa_operand_internal iib4constu_operand = {
+ "i",
+ '<',
+ 0,
+ get_r_field,
+ set_r_field,
+ encode_b4constu,
+ decode_b4constu,
+ 0,
+ 0
+};
+
+static xtensa_operand_internal iisr_operand = {
+ "i",
+ '<',
+ 0,
+ get_sr_field,
+ set_sr_field,
+ encode_sr,
+ decode_sr,
+ 0,
+ 0
+};
+
+static xtensa_operand_internal iibbi_operand = {
+ "i",
+ '<',
+ 0,
+ get_bbi_field,
+ set_bbi_field,
+ encode_bbi,
+ decode_bbi,
+ 0,
+ 0
+};
+
+static xtensa_operand_internal iiai4const_operand = {
+ "i",
+ '<',
+ 0,
+ get_t_field,
+ set_t_field,
+ encode_ai4const,
+ decode_ai4const,
+ 0,
+ 0
+};
+
+static xtensa_operand_internal iiuimm12x8_operand = {
+ "i",
+ '<',
+ 0,
+ get_imm12_field,
+ set_imm12_field,
+ encode_uimm12x8,
+ decode_uimm12x8,
+ 0,
+ 0
+};
+
+static xtensa_operand_internal riuimm16x4_operand = {
+ "r",
+ '<',
+ 1,
+ get_imm16_field,
+ set_imm16_field,
+ encode_uimm16x4,
+ decode_uimm16x4,
+ do_reloc_r,
+ undo_reloc_r,
+};
+
+static xtensa_operand_internal lisimm8_operand = {
+ "l",
+ '<',
+ 1,
+ get_imm8_field,
+ set_imm8_field,
+ encode_simm8,
+ decode_simm8,
+ do_reloc_l,
+ undo_reloc_l,
+};
+
+static xtensa_operand_internal iilsi4x4_operand = {
+ "i",
+ '<',
+ 0,
+ get_r_field,
+ set_r_field,
+ encode_lsi4x4,
+ decode_lsi4x4,
+ 0,
+ 0
+};
+
+static xtensa_operand_internal iiuimm8x2_operand = {
+ "i",
+ '<',
+ 0,
+ get_imm8_field,
+ set_imm8_field,
+ encode_uimm8x2,
+ decode_uimm8x2,
+ 0,
+ 0
+};
+
+static xtensa_operand_internal iisimm4_operand = {
+ "i",
+ '<',
+ 0,
+ get_mn_field,
+ set_mn_field,
+ encode_simm4,
+ decode_simm4,
+ 0,
+ 0
+};
+
+static xtensa_operand_internal iimsalp32_operand = {
+ "i",
+ '<',
+ 0,
+ get_sal_field,
+ set_sal_field,
+ encode_msalp32,
+ decode_msalp32,
+ 0,
+ 0
+};
+
+static xtensa_operand_internal liuimm6_operand = {
+ "l",
+ '<',
+ 1,
+ get_imm6_field,
+ set_imm6_field,
+ encode_uimm6,
+ decode_uimm6,
+ do_reloc_l,
+ undo_reloc_l,
+};
+
+static xtensa_operand_internal iiuimm8x4_operand = {
+ "i",
+ '<',
+ 0,
+ get_imm8_field,
+ set_imm8_field,
+ encode_uimm8x4,
+ decode_uimm8x4,
+ 0,
+ 0
+};
+
+static xtensa_operand_internal lisoffset_operand = {
+ "l",
+ '<',
+ 1,
+ get_offset_field,
+ set_offset_field,
+ encode_soffset,
+ decode_soffset,
+ do_reloc_l,
+ undo_reloc_l,
+};
+
+static xtensa_operand_internal iisimm7_operand = {
+ "i",
+ '<',
+ 0,
+ get_imm7_field,
+ set_imm7_field,
+ encode_simm7,
+ decode_simm7,
+ 0,
+ 0
+};
+
+static xtensa_operand_internal ais_operand = {
+ "a",
+ '<',
+ 0,
+ get_s_field,
+ set_s_field,
+ encode_s,
+ decode_s,
+ 0,
+ 0
+};
+
+static xtensa_operand_internal liuimm8_operand = {
+ "l",
+ '<',
+ 1,
+ get_imm8_field,
+ set_imm8_field,
+ encode_uimm8,
+ decode_uimm8,
+ do_reloc_l,
+ undo_reloc_l,
+};
+
+static xtensa_operand_internal ait_operand = {
+ "a",
+ '<',
+ 0,
+ get_t_field,
+ set_t_field,
+ encode_t,
+ decode_t,
+ 0,
+ 0
+};
+
+static xtensa_operand_internal iisimm8_operand = {
+ "i",
+ '<',
+ 0,
+ get_imm8_field,
+ set_imm8_field,
+ encode_simm8,
+ decode_simm8,
+ 0,
+ 0
+};
+
+static xtensa_operand_internal aor_operand = {
+ "a",
+ '>',
+ 0,
+ get_r_field,
+ set_r_field,
+ encode_r,
+ decode_r,
+ 0,
+ 0
+};
+
+static xtensa_operand_internal aos_operand = {
+ "a",
+ '>',
+ 0,
+ get_s_field,
+ set_s_field,
+ encode_s,
+ decode_s,
+ 0,
+ 0
+};
+
+static xtensa_operand_internal aot_operand = {
+ "a",
+ '>',
+ 0,
+ get_t_field,
+ set_t_field,
+ encode_t,
+ decode_t,
+ 0,
+ 0
+};
+
+static xtensa_iclass_internal nopn_iclass = {
+ 0,
+ 0
+};
+
+static xtensa_operand_internal *movi_operand_list[] = {
+ &aot_operand,
+ &iisimm12b_operand
+};
+
+static xtensa_iclass_internal movi_iclass = {
+ 2,
+ &movi_operand_list[0]
+};
+
+static xtensa_operand_internal *bsi8u_operand_list[] = {
+ &ais_operand,
+ &iib4constu_operand,
+ &lisimm8_operand
+};
+
+static xtensa_iclass_internal bsi8u_iclass = {
+ 3,
+ &bsi8u_operand_list[0]
+};
+
+static xtensa_operand_internal *itlb_operand_list[] = {
+ &ais_operand
+};
+
+static xtensa_iclass_internal itlb_iclass = {
+ 1,
+ &itlb_operand_list[0]
+};
+
+static xtensa_operand_internal *shiftst_operand_list[] = {
+ &aor_operand,
+ &ais_operand,
+ &ait_operand
+};
+
+static xtensa_iclass_internal shiftst_iclass = {
+ 3,
+ &shiftst_operand_list[0]
+};
+
+static xtensa_operand_internal *l32r_operand_list[] = {
+ &aot_operand,
+ &riuimm16x4_operand
+};
+
+static xtensa_iclass_internal l32r_iclass = {
+ 2,
+ &l32r_operand_list[0]
+};
+
+static xtensa_iclass_internal rfe_iclass = {
+ 0,
+ 0
+};
+
+static xtensa_operand_internal *wait_operand_list[] = {
+ &iis_operand
+};
+
+static xtensa_iclass_internal wait_iclass = {
+ 1,
+ &wait_operand_list[0]
+};
+
+static xtensa_operand_internal *rfi_operand_list[] = {
+ &iis_operand
+};
+
+static xtensa_iclass_internal rfi_iclass = {
+ 1,
+ &rfi_operand_list[0]
+};
+
+static xtensa_operand_internal *movz_operand_list[] = {
+ &amr_operand,
+ &ais_operand,
+ &ait_operand
+};
+
+static xtensa_iclass_internal movz_iclass = {
+ 3,
+ &movz_operand_list[0]
+};
+
+static xtensa_operand_internal *callx_operand_list[] = {
+ &ais_operand
+};
+
+static xtensa_iclass_internal callx_iclass = {
+ 1,
+ &callx_operand_list[0]
+};
+
+static xtensa_operand_internal *mov_n_operand_list[] = {
+ &aot_operand,
+ &ais_operand
+};
+
+static xtensa_iclass_internal mov_n_iclass = {
+ 2,
+ &mov_n_operand_list[0]
+};
+
+static xtensa_operand_internal *loadi4_operand_list[] = {
+ &aot_operand,
+ &ais_operand,
+ &iilsi4x4_operand
+};
+
+static xtensa_iclass_internal loadi4_iclass = {
+ 3,
+ &loadi4_operand_list[0]
+};
+
+static xtensa_operand_internal *exti_operand_list[] = {
+ &aor_operand,
+ &ait_operand,
+ &iisae_operand,
+ &iiop2p1_operand
+};
+
+static xtensa_iclass_internal exti_iclass = {
+ 4,
+ &exti_operand_list[0]
+};
+
+static xtensa_operand_internal *break_operand_list[] = {
+ &iis_operand,
+ &iit_operand
+};
+
+static xtensa_iclass_internal break_iclass = {
+ 2,
+ &break_operand_list[0]
+};
+
+static xtensa_operand_internal *slli_operand_list[] = {
+ &aor_operand,
+ &ais_operand,
+ &iimsalp32_operand
+};
+
+static xtensa_iclass_internal slli_iclass = {
+ 3,
+ &slli_operand_list[0]
+};
+
+static xtensa_operand_internal *s16i_operand_list[] = {
+ &ait_operand,
+ &ais_operand,
+ &iiuimm8x2_operand
+};
+
+static xtensa_iclass_internal s16i_iclass = {
+ 3,
+ &s16i_operand_list[0]
+};
+
+static xtensa_operand_internal *call_operand_list[] = {
+ &lisoffsetx4_operand
+};
+
+static xtensa_iclass_internal call_iclass = {
+ 1,
+ &call_operand_list[0]
+};
+
+static xtensa_operand_internal *shifts_operand_list[] = {
+ &aor_operand,
+ &ais_operand
+};
+
+static xtensa_iclass_internal shifts_iclass = {
+ 2,
+ &shifts_operand_list[0]
+};
+
+static xtensa_operand_internal *shiftt_operand_list[] = {
+ &aor_operand,
+ &ait_operand
+};
+
+static xtensa_iclass_internal shiftt_iclass = {
+ 2,
+ &shiftt_operand_list[0]
+};
+
+static xtensa_operand_internal *rotw_operand_list[] = {
+ &iisimm4_operand
+};
+
+static xtensa_iclass_internal rotw_iclass = {
+ 1,
+ &rotw_operand_list[0]
+};
+
+static xtensa_operand_internal *addsub_operand_list[] = {
+ &aor_operand,
+ &ais_operand,
+ &ait_operand
+};
+
+static xtensa_iclass_internal addsub_iclass = {
+ 3,
+ &addsub_operand_list[0]
+};
+
+static xtensa_operand_internal *l8i_operand_list[] = {
+ &aot_operand,
+ &ais_operand,
+ &iiuimm8_operand
+};
+
+static xtensa_iclass_internal l8i_iclass = {
+ 3,
+ &l8i_operand_list[0]
+};
+
+static xtensa_operand_internal *sari_operand_list[] = {
+ &iisas_operand
+};
+
+static xtensa_iclass_internal sari_iclass = {
+ 1,
+ &sari_operand_list[0]
+};
+
+static xtensa_operand_internal *xsr_operand_list[] = {
+ &abt_operand,
+ &iisr_operand
+};
+
+static xtensa_iclass_internal xsr_iclass = {
+ 2,
+ &xsr_operand_list[0]
+};
+
+static xtensa_operand_internal *rsil_operand_list[] = {
+ &aot_operand,
+ &iis_operand
+};
+
+static xtensa_iclass_internal rsil_iclass = {
+ 2,
+ &rsil_operand_list[0]
+};
+
+static xtensa_operand_internal *bst8_operand_list[] = {
+ &ais_operand,
+ &ait_operand,
+ &lisimm8_operand
+};
+
+static xtensa_iclass_internal bst8_iclass = {
+ 3,
+ &bst8_operand_list[0]
+};
+
+static xtensa_operand_internal *addi_operand_list[] = {
+ &aot_operand,
+ &ais_operand,
+ &iisimm8_operand
+};
+
+static xtensa_iclass_internal addi_iclass = {
+ 3,
+ &addi_operand_list[0]
+};
+
+static xtensa_operand_internal *callx12_operand_list[] = {
+ &ais_operand
+};
+
+static xtensa_iclass_internal callx12_iclass = {
+ 1,
+ &callx12_operand_list[0]
+};
+
+static xtensa_operand_internal *bsi8_operand_list[] = {
+ &ais_operand,
+ &iib4const_operand,
+ &lisimm8_operand
+};
+
+static xtensa_iclass_internal bsi8_iclass = {
+ 3,
+ &bsi8_operand_list[0]
+};
+
+static xtensa_operand_internal *jumpx_operand_list[] = {
+ &ais_operand
+};
+
+static xtensa_iclass_internal jumpx_iclass = {
+ 1,
+ &jumpx_operand_list[0]
+};
+
+static xtensa_iclass_internal retn_iclass = {
+ 0,
+ 0
+};
+
+static xtensa_operand_internal *nsa_operand_list[] = {
+ &aot_operand,
+ &ais_operand
+};
+
+static xtensa_iclass_internal nsa_iclass = {
+ 2,
+ &nsa_operand_list[0]
+};
+
+static xtensa_operand_internal *storei4_operand_list[] = {
+ &ait_operand,
+ &ais_operand,
+ &iilsi4x4_operand
+};
+
+static xtensa_iclass_internal storei4_iclass = {
+ 3,
+ &storei4_operand_list[0]
+};
+
+static xtensa_operand_internal *wtlb_operand_list[] = {
+ &ait_operand,
+ &ais_operand
+};
+
+static xtensa_iclass_internal wtlb_iclass = {
+ 2,
+ &wtlb_operand_list[0]
+};
+
+static xtensa_operand_internal *dce_operand_list[] = {
+ &ais_operand,
+ &iiuimm4x16_operand
+};
+
+static xtensa_iclass_internal dce_iclass = {
+ 2,
+ &dce_operand_list[0]
+};
+
+static xtensa_operand_internal *l16i_operand_list[] = {
+ &aot_operand,
+ &ais_operand,
+ &iiuimm8x2_operand
+};
+
+static xtensa_iclass_internal l16i_iclass = {
+ 3,
+ &l16i_operand_list[0]
+};
+
+static xtensa_operand_internal *callx4_operand_list[] = {
+ &ais_operand
+};
+
+static xtensa_iclass_internal callx4_iclass = {
+ 1,
+ &callx4_operand_list[0]
+};
+
+static xtensa_operand_internal *callx8_operand_list[] = {
+ &ais_operand
+};
+
+static xtensa_iclass_internal callx8_iclass = {
+ 1,
+ &callx8_operand_list[0]
+};
+
+static xtensa_operand_internal *movsp_operand_list[] = {
+ &aot_operand,
+ &ais_operand
+};
+
+static xtensa_iclass_internal movsp_iclass = {
+ 2,
+ &movsp_operand_list[0]
+};
+
+static xtensa_operand_internal *wsr_operand_list[] = {
+ &ait_operand,
+ &iisr_operand
+};
+
+static xtensa_iclass_internal wsr_iclass = {
+ 2,
+ &wsr_operand_list[0]
+};
+
+static xtensa_operand_internal *call12_operand_list[] = {
+ &lisoffsetx4_operand
+};
+
+static xtensa_iclass_internal call12_iclass = {
+ 1,
+ &call12_operand_list[0]
+};
+
+static xtensa_operand_internal *call4_operand_list[] = {
+ &lisoffsetx4_operand
+};
+
+static xtensa_iclass_internal call4_iclass = {
+ 1,
+ &call4_operand_list[0]
+};
+
+static xtensa_operand_internal *addmi_operand_list[] = {
+ &aot_operand,
+ &ais_operand,
+ &iisimm8x256_operand
+};
+
+static xtensa_iclass_internal addmi_iclass = {
+ 3,
+ &addmi_operand_list[0]
+};
+
+static xtensa_operand_internal *bit_operand_list[] = {
+ &aor_operand,
+ &ais_operand,
+ &ait_operand
+};
+
+static xtensa_iclass_internal bit_iclass = {
+ 3,
+ &bit_operand_list[0]
+};
+
+static xtensa_operand_internal *call8_operand_list[] = {
+ &lisoffsetx4_operand
+};
+
+static xtensa_iclass_internal call8_iclass = {
+ 1,
+ &call8_operand_list[0]
+};
+
+static xtensa_iclass_internal itlba_iclass = {
+ 0,
+ 0
+};
+
+static xtensa_operand_internal *break_n_operand_list[] = {
+ &iis_operand
+};
+
+static xtensa_iclass_internal break_n_iclass = {
+ 1,
+ &break_n_operand_list[0]
+};
+
+static xtensa_operand_internal *sar_operand_list[] = {
+ &ais_operand
+};
+
+static xtensa_iclass_internal sar_iclass = {
+ 1,
+ &sar_operand_list[0]
+};
+
+static xtensa_operand_internal *s32e_operand_list[] = {
+ &ait_operand,
+ &ais_operand,
+ &iinimm4x2_operand
+};
+
+static xtensa_iclass_internal s32e_iclass = {
+ 3,
+ &s32e_operand_list[0]
+};
+
+static xtensa_operand_internal *bz6_operand_list[] = {
+ &ais_operand,
+ &liuimm6_operand
+};
+
+static xtensa_iclass_internal bz6_iclass = {
+ 2,
+ &bz6_operand_list[0]
+};
+
+static xtensa_operand_internal *loop_operand_list[] = {
+ &ais_operand,
+ &liuimm8_operand
+};
+
+static xtensa_iclass_internal loop_iclass = {
+ 2,
+ &loop_operand_list[0]
+};
+
+static xtensa_operand_internal *rsr_operand_list[] = {
+ &aot_operand,
+ &iisr_operand
+};
+
+static xtensa_iclass_internal rsr_iclass = {
+ 2,
+ &rsr_operand_list[0]
+};
+
+static xtensa_operand_internal *icache_operand_list[] = {
+ &ais_operand,
+ &iiuimm8x4_operand
+};
+
+static xtensa_iclass_internal icache_iclass = {
+ 2,
+ &icache_operand_list[0]
+};
+
+static xtensa_operand_internal *s8i_operand_list[] = {
+ &ait_operand,
+ &ais_operand,
+ &iiuimm8_operand
+};
+
+static xtensa_iclass_internal s8i_iclass = {
+ 3,
+ &s8i_operand_list[0]
+};
+
+static xtensa_iclass_internal return_iclass = {
+ 0,
+ 0
+};
+
+static xtensa_operand_internal *dcache_operand_list[] = {
+ &ais_operand,
+ &iiuimm8x4_operand
+};
+
+static xtensa_iclass_internal dcache_iclass = {
+ 2,
+ &dcache_operand_list[0]
+};
+
+static xtensa_operand_internal *s32i_operand_list[] = {
+ &ait_operand,
+ &ais_operand,
+ &iiuimm8x4_operand
+};
+
+static xtensa_iclass_internal s32i_iclass = {
+ 3,
+ &s32i_operand_list[0]
+};
+
+static xtensa_operand_internal *jump_operand_list[] = {
+ &lisoffset_operand
+};
+
+static xtensa_iclass_internal jump_iclass = {
+ 1,
+ &jump_operand_list[0]
+};
+
+static xtensa_operand_internal *addi_n_operand_list[] = {
+ &aor_operand,
+ &ais_operand,
+ &iiai4const_operand
+};
+
+static xtensa_iclass_internal addi_n_iclass = {
+ 3,
+ &addi_n_operand_list[0]
+};
+
+static xtensa_iclass_internal sync_iclass = {
+ 0,
+ 0
+};
+
+static xtensa_operand_internal *neg_operand_list[] = {
+ &aor_operand,
+ &ait_operand
+};
+
+static xtensa_iclass_internal neg_iclass = {
+ 2,
+ &neg_operand_list[0]
+};
+
+static xtensa_iclass_internal syscall_iclass = {
+ 0,
+ 0
+};
+
+static xtensa_operand_internal *bsz12_operand_list[] = {
+ &ais_operand,
+ &lisimm12_operand
+};
+
+static xtensa_iclass_internal bsz12_iclass = {
+ 2,
+ &bsz12_operand_list[0]
+};
+
+static xtensa_iclass_internal excw_iclass = {
+ 0,
+ 0
+};
+
+static xtensa_operand_internal *movi_n_operand_list[] = {
+ &aos_operand,
+ &iisimm7_operand
+};
+
+static xtensa_iclass_internal movi_n_iclass = {
+ 2,
+ &movi_n_operand_list[0]
+};
+
+static xtensa_operand_internal *rtlb_operand_list[] = {
+ &aot_operand,
+ &ais_operand
+};
+
+static xtensa_iclass_internal rtlb_iclass = {
+ 2,
+ &rtlb_operand_list[0]
+};
+
+static xtensa_operand_internal *actl_operand_list[] = {
+ &aot_operand,
+ &ais_operand
+};
+
+static xtensa_iclass_internal actl_iclass = {
+ 2,
+ &actl_operand_list[0]
+};
+
+static xtensa_operand_internal *srli_operand_list[] = {
+ &aor_operand,
+ &ait_operand,
+ &iis_operand
+};
+
+static xtensa_iclass_internal srli_iclass = {
+ 3,
+ &srli_operand_list[0]
+};
+
+static xtensa_operand_internal *bsi8b_operand_list[] = {
+ &ais_operand,
+ &iibbi_operand,
+ &lisimm8_operand
+};
+
+static xtensa_iclass_internal bsi8b_iclass = {
+ 3,
+ &bsi8b_operand_list[0]
+};
+
+static xtensa_operand_internal *acts_operand_list[] = {
+ &ait_operand,
+ &ais_operand
+};
+
+static xtensa_iclass_internal acts_iclass = {
+ 2,
+ &acts_operand_list[0]
+};
+
+static xtensa_operand_internal *add_n_operand_list[] = {
+ &aor_operand,
+ &ais_operand,
+ &ait_operand
+};
+
+static xtensa_iclass_internal add_n_iclass = {
+ 3,
+ &add_n_operand_list[0]
+};
+
+static xtensa_operand_internal *srai_operand_list[] = {
+ &aor_operand,
+ &ait_operand,
+ &iisar_operand
+};
+
+static xtensa_iclass_internal srai_iclass = {
+ 3,
+ &srai_operand_list[0]
+};
+
+static xtensa_operand_internal *entry_operand_list[] = {
+ &abs_operand,
+ &iiuimm12x8_operand
+};
+
+static xtensa_iclass_internal entry_iclass = {
+ 2,
+ &entry_operand_list[0]
+};
+
+static xtensa_operand_internal *l32e_operand_list[] = {
+ &aot_operand,
+ &ais_operand,
+ &iinimm4x2_operand
+};
+
+static xtensa_iclass_internal l32e_iclass = {
+ 3,
+ &l32e_operand_list[0]
+};
+
+static xtensa_operand_internal *dpf_operand_list[] = {
+ &ais_operand,
+ &iiuimm8x4_operand
+};
+
+static xtensa_iclass_internal dpf_iclass = {
+ 2,
+ &dpf_operand_list[0]
+};
+
+static xtensa_operand_internal *l32i_operand_list[] = {
+ &aot_operand,
+ &ais_operand,
+ &iiuimm8x4_operand
+};
+
+static xtensa_iclass_internal l32i_iclass = {
+ 3,
+ &l32i_operand_list[0]
+};
+
+static xtensa_insnbuf abs_template (void);
+static xtensa_insnbuf add_template (void);
+static xtensa_insnbuf add_n_template (void);
+static xtensa_insnbuf addi_template (void);
+static xtensa_insnbuf addi_n_template (void);
+static xtensa_insnbuf addmi_template (void);
+static xtensa_insnbuf addx2_template (void);
+static xtensa_insnbuf addx4_template (void);
+static xtensa_insnbuf addx8_template (void);
+static xtensa_insnbuf and_template (void);
+static xtensa_insnbuf ball_template (void);
+static xtensa_insnbuf bany_template (void);
+static xtensa_insnbuf bbc_template (void);
+static xtensa_insnbuf bbci_template (void);
+static xtensa_insnbuf bbs_template (void);
+static xtensa_insnbuf bbsi_template (void);
+static xtensa_insnbuf beq_template (void);
+static xtensa_insnbuf beqi_template (void);
+static xtensa_insnbuf beqz_template (void);
+static xtensa_insnbuf beqz_n_template (void);
+static xtensa_insnbuf bge_template (void);
+static xtensa_insnbuf bgei_template (void);
+static xtensa_insnbuf bgeu_template (void);
+static xtensa_insnbuf bgeui_template (void);
+static xtensa_insnbuf bgez_template (void);
+static xtensa_insnbuf blt_template (void);
+static xtensa_insnbuf blti_template (void);
+static xtensa_insnbuf bltu_template (void);
+static xtensa_insnbuf bltui_template (void);
+static xtensa_insnbuf bltz_template (void);
+static xtensa_insnbuf bnall_template (void);
+static xtensa_insnbuf bne_template (void);
+static xtensa_insnbuf bnei_template (void);
+static xtensa_insnbuf bnez_template (void);
+static xtensa_insnbuf bnez_n_template (void);
+static xtensa_insnbuf bnone_template (void);
+static xtensa_insnbuf break_template (void);
+static xtensa_insnbuf break_n_template (void);
+static xtensa_insnbuf call0_template (void);
+static xtensa_insnbuf call12_template (void);
+static xtensa_insnbuf call4_template (void);
+static xtensa_insnbuf call8_template (void);
+static xtensa_insnbuf callx0_template (void);
+static xtensa_insnbuf callx12_template (void);
+static xtensa_insnbuf callx4_template (void);
+static xtensa_insnbuf callx8_template (void);
+static xtensa_insnbuf dhi_template (void);
+static xtensa_insnbuf dhwb_template (void);
+static xtensa_insnbuf dhwbi_template (void);
+static xtensa_insnbuf dii_template (void);
+static xtensa_insnbuf diwb_template (void);
+static xtensa_insnbuf diwbi_template (void);
+static xtensa_insnbuf dpfr_template (void);
+static xtensa_insnbuf dpfro_template (void);
+static xtensa_insnbuf dpfw_template (void);
+static xtensa_insnbuf dpfwo_template (void);
+static xtensa_insnbuf dsync_template (void);
+static xtensa_insnbuf entry_template (void);
+static xtensa_insnbuf esync_template (void);
+static xtensa_insnbuf excw_template (void);
+static xtensa_insnbuf extui_template (void);
+static xtensa_insnbuf idtlb_template (void);
+static xtensa_insnbuf idtlba_template (void);
+static xtensa_insnbuf ihi_template (void);
+static xtensa_insnbuf iii_template (void);
+static xtensa_insnbuf iitlb_template (void);
+static xtensa_insnbuf iitlba_template (void);
+static xtensa_insnbuf ipf_template (void);
+static xtensa_insnbuf isync_template (void);
+static xtensa_insnbuf j_template (void);
+static xtensa_insnbuf jx_template (void);
+static xtensa_insnbuf l16si_template (void);
+static xtensa_insnbuf l16ui_template (void);
+static xtensa_insnbuf l32e_template (void);
+static xtensa_insnbuf l32i_template (void);
+static xtensa_insnbuf l32i_n_template (void);
+static xtensa_insnbuf l32r_template (void);
+static xtensa_insnbuf l8ui_template (void);
+static xtensa_insnbuf ldct_template (void);
+static xtensa_insnbuf lict_template (void);
+static xtensa_insnbuf licw_template (void);
+static xtensa_insnbuf loop_template (void);
+static xtensa_insnbuf loopgtz_template (void);
+static xtensa_insnbuf loopnez_template (void);
+static xtensa_insnbuf memw_template (void);
+static xtensa_insnbuf mov_n_template (void);
+static xtensa_insnbuf moveqz_template (void);
+static xtensa_insnbuf movgez_template (void);
+static xtensa_insnbuf movi_template (void);
+static xtensa_insnbuf movi_n_template (void);
+static xtensa_insnbuf movltz_template (void);
+static xtensa_insnbuf movnez_template (void);
+static xtensa_insnbuf movsp_template (void);
+static xtensa_insnbuf neg_template (void);
+static xtensa_insnbuf nop_n_template (void);
+static xtensa_insnbuf nsa_template (void);
+static xtensa_insnbuf nsau_template (void);
+static xtensa_insnbuf or_template (void);
+static xtensa_insnbuf pdtlb_template (void);
+static xtensa_insnbuf pitlb_template (void);
+static xtensa_insnbuf rdtlb0_template (void);
+static xtensa_insnbuf rdtlb1_template (void);
+static xtensa_insnbuf ret_template (void);
+static xtensa_insnbuf ret_n_template (void);
+static xtensa_insnbuf retw_template (void);
+static xtensa_insnbuf retw_n_template (void);
+static xtensa_insnbuf rfde_template (void);
+static xtensa_insnbuf rfe_template (void);
+static xtensa_insnbuf rfi_template (void);
+static xtensa_insnbuf rfwo_template (void);
+static xtensa_insnbuf rfwu_template (void);
+static xtensa_insnbuf ritlb0_template (void);
+static xtensa_insnbuf ritlb1_template (void);
+static xtensa_insnbuf rotw_template (void);
+static xtensa_insnbuf rsil_template (void);
+static xtensa_insnbuf rsr_template (void);
+static xtensa_insnbuf rsync_template (void);
+static xtensa_insnbuf s16i_template (void);
+static xtensa_insnbuf s32e_template (void);
+static xtensa_insnbuf s32i_template (void);
+static xtensa_insnbuf s32i_n_template (void);
+static xtensa_insnbuf s8i_template (void);
+static xtensa_insnbuf sdct_template (void);
+static xtensa_insnbuf sict_template (void);
+static xtensa_insnbuf sicw_template (void);
+static xtensa_insnbuf simcall_template (void);
+static xtensa_insnbuf sll_template (void);
+static xtensa_insnbuf slli_template (void);
+static xtensa_insnbuf sra_template (void);
+static xtensa_insnbuf srai_template (void);
+static xtensa_insnbuf src_template (void);
+static xtensa_insnbuf srl_template (void);
+static xtensa_insnbuf srli_template (void);
+static xtensa_insnbuf ssa8b_template (void);
+static xtensa_insnbuf ssa8l_template (void);
+static xtensa_insnbuf ssai_template (void);
+static xtensa_insnbuf ssl_template (void);
+static xtensa_insnbuf ssr_template (void);
+static xtensa_insnbuf sub_template (void);
+static xtensa_insnbuf subx2_template (void);
+static xtensa_insnbuf subx4_template (void);
+static xtensa_insnbuf subx8_template (void);
+static xtensa_insnbuf syscall_template (void);
+static xtensa_insnbuf waiti_template (void);
+static xtensa_insnbuf wdtlb_template (void);
+static xtensa_insnbuf witlb_template (void);
+static xtensa_insnbuf wsr_template (void);
+static xtensa_insnbuf xor_template (void);
+static xtensa_insnbuf xsr_template (void);
+
+static xtensa_insnbuf
+abs_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00001006 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+add_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000008 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+add_n_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00a00000 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+addi_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00200c00 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+addi_n_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00b00000 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+addmi_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00200d00 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+addx2_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000009 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+addx4_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x0000000a };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+addx8_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x0000000b };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+and_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000001 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+ball_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00700400 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+bany_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00700800 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+bbc_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00700500 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+bbci_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00700600 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+bbs_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00700d00 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+bbsi_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00700e00 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+beq_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00700100 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+beqi_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00680000 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+beqz_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00640000 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+beqz_n_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00c80000 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+bge_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00700a00 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+bgei_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x006b0000 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+bgeu_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00700b00 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+bgeui_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x006f0000 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+bgez_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00670000 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+blt_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00700200 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+blti_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x006a0000 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+bltu_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00700300 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+bltui_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x006e0000 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+bltz_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00660000 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+bnall_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00700c00 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+bne_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00700900 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+bnei_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00690000 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+bnez_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00650000 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+bnez_n_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00cc0000 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+bnone_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00700000 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+break_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000400 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+break_n_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00d20f00 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+call0_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00500000 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+call12_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x005c0000 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+call4_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00540000 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+call8_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00580000 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+callx0_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00030000 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+callx12_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x000f0000 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+callx4_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00070000 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+callx8_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x000b0000 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+dhi_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00260700 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+dhwb_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00240700 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+dhwbi_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00250700 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+dii_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00270700 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+diwb_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00280740 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+diwbi_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00280750 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+dpfr_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00200700 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+dpfro_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00220700 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+dpfw_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00210700 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+dpfwo_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00230700 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+dsync_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00030200 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+entry_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x006c0000 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+esync_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00020200 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+excw_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00080200 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+extui_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000040 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+idtlb_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000c05 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+idtlba_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000805 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+ihi_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x002e0700 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+iii_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x002f0700 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+iitlb_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000405 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+iitlba_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000005 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+ipf_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x002c0700 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+isync_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000200 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+j_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00600000 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+jx_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x000a0000 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+l16si_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00200900 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+l16ui_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00200100 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+l32e_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000090 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+l32i_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00200200 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+l32i_n_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00800000 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+l32r_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00100000 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+l8ui_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00200000 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+ldct_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x0000081f };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+lict_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x0000001f };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+licw_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x0000021f };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+loop_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x006d0800 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+loopgtz_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x006d0a00 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+loopnez_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x006d0900 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+memw_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x000c0200 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+mov_n_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00d00000 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+moveqz_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000038 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+movgez_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x0000003b };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+movi_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00200a00 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+movi_n_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00c00000 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+movltz_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x0000003a };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+movnez_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000039 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+movsp_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000100 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+neg_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000006 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+nop_n_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00d30f00 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+nsa_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000e04 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+nsau_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000f04 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+or_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000002 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+pdtlb_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000d05 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+pitlb_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000505 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+rdtlb0_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000b05 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+rdtlb1_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000f05 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+ret_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00020000 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+ret_n_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00d00f00 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+retw_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00060000 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+retw_n_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00d10f00 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+rfde_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00002300 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+rfe_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000300 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+rfi_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00010300 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+rfwo_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00004300 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+rfwu_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00005300 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+ritlb0_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000305 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+ritlb1_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000705 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+rotw_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000804 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+rsil_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000600 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+rsr_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000030 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+rsync_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00010200 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+s16i_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00200500 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+s32e_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000094 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+s32i_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00200600 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+s32i_n_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00900000 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+s8i_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00200400 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+sdct_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x0000091f };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+sict_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x0000011f };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+sicw_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x0000031f };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+simcall_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00001500 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+sll_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x0000001a };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+slli_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000010 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+sra_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x0000001b };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+srai_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000012 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+src_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000018 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+srl_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000019 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+srli_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000014 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+ssa8b_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000304 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+ssa8l_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000204 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+ssai_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000404 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+ssl_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000104 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+ssr_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000004 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+sub_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x0000000c };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+subx2_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x0000000d };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+subx4_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x0000000e };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+subx8_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x0000000f };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+syscall_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000500 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+waiti_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000700 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+wdtlb_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000e05 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+witlb_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000605 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+wsr_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000031 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+xor_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000003 };
+ return &template[0];
+}
+
+static xtensa_insnbuf
+xsr_template (void)
+{
+ static xtensa_insnbuf_word template[] = { 0x00000016 };
+ return &template[0];
+}
+
+static xtensa_opcode_internal abs_opcode = {
+ "abs",
+ 3,
+ abs_template,
+ &neg_iclass
+};
+
+static xtensa_opcode_internal add_opcode = {
+ "add",
+ 3,
+ add_template,
+ &addsub_iclass
+};
+
+static xtensa_opcode_internal add_n_opcode = {
+ "add.n",
+ 2,
+ add_n_template,
+ &add_n_iclass
+};
+
+static xtensa_opcode_internal addi_opcode = {
+ "addi",
+ 3,
+ addi_template,
+ &addi_iclass
+};
+
+static xtensa_opcode_internal addi_n_opcode = {
+ "addi.n",
+ 2,
+ addi_n_template,
+ &addi_n_iclass
+};
+
+static xtensa_opcode_internal addmi_opcode = {
+ "addmi",
+ 3,
+ addmi_template,
+ &addmi_iclass
+};
+
+static xtensa_opcode_internal addx2_opcode = {
+ "addx2",
+ 3,
+ addx2_template,
+ &addsub_iclass
+};
+
+static xtensa_opcode_internal addx4_opcode = {
+ "addx4",
+ 3,
+ addx4_template,
+ &addsub_iclass
+};
+
+static xtensa_opcode_internal addx8_opcode = {
+ "addx8",
+ 3,
+ addx8_template,
+ &addsub_iclass
+};
+
+static xtensa_opcode_internal and_opcode = {
+ "and",
+ 3,
+ and_template,
+ &bit_iclass
+};
+
+static xtensa_opcode_internal ball_opcode = {
+ "ball",
+ 3,
+ ball_template,
+ &bst8_iclass
+};
+
+static xtensa_opcode_internal bany_opcode = {
+ "bany",
+ 3,
+ bany_template,
+ &bst8_iclass
+};
+
+static xtensa_opcode_internal bbc_opcode = {
+ "bbc",
+ 3,
+ bbc_template,
+ &bst8_iclass
+};
+
+static xtensa_opcode_internal bbci_opcode = {
+ "bbci",
+ 3,
+ bbci_template,
+ &bsi8b_iclass
+};
+
+static xtensa_opcode_internal bbs_opcode = {
+ "bbs",
+ 3,
+ bbs_template,
+ &bst8_iclass
+};
+
+static xtensa_opcode_internal bbsi_opcode = {
+ "bbsi",
+ 3,
+ bbsi_template,
+ &bsi8b_iclass
+};
+
+static xtensa_opcode_internal beq_opcode = {
+ "beq",
+ 3,
+ beq_template,
+ &bst8_iclass
+};
+
+static xtensa_opcode_internal beqi_opcode = {
+ "beqi",
+ 3,
+ beqi_template,
+ &bsi8_iclass
+};
+
+static xtensa_opcode_internal beqz_opcode = {
+ "beqz",
+ 3,
+ beqz_template,
+ &bsz12_iclass
+};
+
+static xtensa_opcode_internal beqz_n_opcode = {
+ "beqz.n",
+ 2,
+ beqz_n_template,
+ &bz6_iclass
+};
+
+static xtensa_opcode_internal bge_opcode = {
+ "bge",
+ 3,
+ bge_template,
+ &bst8_iclass
+};
+
+static xtensa_opcode_internal bgei_opcode = {
+ "bgei",
+ 3,
+ bgei_template,
+ &bsi8_iclass
+};
+
+static xtensa_opcode_internal bgeu_opcode = {
+ "bgeu",
+ 3,
+ bgeu_template,
+ &bst8_iclass
+};
+
+static xtensa_opcode_internal bgeui_opcode = {
+ "bgeui",
+ 3,
+ bgeui_template,
+ &bsi8u_iclass
+};
+
+static xtensa_opcode_internal bgez_opcode = {
+ "bgez",
+ 3,
+ bgez_template,
+ &bsz12_iclass
+};
+
+static xtensa_opcode_internal blt_opcode = {
+ "blt",
+ 3,
+ blt_template,
+ &bst8_iclass
+};
+
+static xtensa_opcode_internal blti_opcode = {
+ "blti",
+ 3,
+ blti_template,
+ &bsi8_iclass
+};
+
+static xtensa_opcode_internal bltu_opcode = {
+ "bltu",
+ 3,
+ bltu_template,
+ &bst8_iclass
+};
+
+static xtensa_opcode_internal bltui_opcode = {
+ "bltui",
+ 3,
+ bltui_template,
+ &bsi8u_iclass
+};
+
+static xtensa_opcode_internal bltz_opcode = {
+ "bltz",
+ 3,
+ bltz_template,
+ &bsz12_iclass
+};
+
+static xtensa_opcode_internal bnall_opcode = {
+ "bnall",
+ 3,
+ bnall_template,
+ &bst8_iclass
+};
+
+static xtensa_opcode_internal bne_opcode = {
+ "bne",
+ 3,
+ bne_template,
+ &bst8_iclass
+};
+
+static xtensa_opcode_internal bnei_opcode = {
+ "bnei",
+ 3,
+ bnei_template,
+ &bsi8_iclass
+};
+
+static xtensa_opcode_internal bnez_opcode = {
+ "bnez",
+ 3,
+ bnez_template,
+ &bsz12_iclass
+};
+
+static xtensa_opcode_internal bnez_n_opcode = {
+ "bnez.n",
+ 2,
+ bnez_n_template,
+ &bz6_iclass
+};
+
+static xtensa_opcode_internal bnone_opcode = {
+ "bnone",
+ 3,
+ bnone_template,
+ &bst8_iclass
+};
+
+static xtensa_opcode_internal break_opcode = {
+ "break",
+ 3,
+ break_template,
+ &break_iclass
+};
+
+static xtensa_opcode_internal break_n_opcode = {
+ "break.n",
+ 2,
+ break_n_template,
+ &break_n_iclass
+};
+
+static xtensa_opcode_internal call0_opcode = {
+ "call0",
+ 3,
+ call0_template,
+ &call_iclass
+};
+
+static xtensa_opcode_internal call12_opcode = {
+ "call12",
+ 3,
+ call12_template,
+ &call12_iclass
+};
+
+static xtensa_opcode_internal call4_opcode = {
+ "call4",
+ 3,
+ call4_template,
+ &call4_iclass
+};
+
+static xtensa_opcode_internal call8_opcode = {
+ "call8",
+ 3,
+ call8_template,
+ &call8_iclass
+};
+
+static xtensa_opcode_internal callx0_opcode = {
+ "callx0",
+ 3,
+ callx0_template,
+ &callx_iclass
+};
+
+static xtensa_opcode_internal callx12_opcode = {
+ "callx12",
+ 3,
+ callx12_template,
+ &callx12_iclass
+};
+
+static xtensa_opcode_internal callx4_opcode = {
+ "callx4",
+ 3,
+ callx4_template,
+ &callx4_iclass
+};
+
+static xtensa_opcode_internal callx8_opcode = {
+ "callx8",
+ 3,
+ callx8_template,
+ &callx8_iclass
+};
+
+static xtensa_opcode_internal dhi_opcode = {
+ "dhi",
+ 3,
+ dhi_template,
+ &dcache_iclass
+};
+
+static xtensa_opcode_internal dhwb_opcode = {
+ "dhwb",
+ 3,
+ dhwb_template,
+ &dcache_iclass
+};
+
+static xtensa_opcode_internal dhwbi_opcode = {
+ "dhwbi",
+ 3,
+ dhwbi_template,
+ &dcache_iclass
+};
+
+static xtensa_opcode_internal dii_opcode = {
+ "dii",
+ 3,
+ dii_template,
+ &dcache_iclass
+};
+
+static xtensa_opcode_internal diwb_opcode = {
+ "diwb",
+ 3,
+ diwb_template,
+ &dce_iclass
+};
+
+static xtensa_opcode_internal diwbi_opcode = {
+ "diwbi",
+ 3,
+ diwbi_template,
+ &dce_iclass
+};
+
+static xtensa_opcode_internal dpfr_opcode = {
+ "dpfr",
+ 3,
+ dpfr_template,
+ &dpf_iclass
+};
+
+static xtensa_opcode_internal dpfro_opcode = {
+ "dpfro",
+ 3,
+ dpfro_template,
+ &dpf_iclass
+};
+
+static xtensa_opcode_internal dpfw_opcode = {
+ "dpfw",
+ 3,
+ dpfw_template,
+ &dpf_iclass
+};
+
+static xtensa_opcode_internal dpfwo_opcode = {
+ "dpfwo",
+ 3,
+ dpfwo_template,
+ &dpf_iclass
+};
+
+static xtensa_opcode_internal dsync_opcode = {
+ "dsync",
+ 3,
+ dsync_template,
+ &sync_iclass
+};
+
+static xtensa_opcode_internal entry_opcode = {
+ "entry",
+ 3,
+ entry_template,
+ &entry_iclass
+};
+
+static xtensa_opcode_internal esync_opcode = {
+ "esync",
+ 3,
+ esync_template,
+ &sync_iclass
+};
+
+static xtensa_opcode_internal excw_opcode = {
+ "excw",
+ 3,
+ excw_template,
+ &excw_iclass
+};
+
+static xtensa_opcode_internal extui_opcode = {
+ "extui",
+ 3,
+ extui_template,
+ &exti_iclass
+};
+
+static xtensa_opcode_internal idtlb_opcode = {
+ "idtlb",
+ 3,
+ idtlb_template,
+ &itlb_iclass
+};
+
+static xtensa_opcode_internal idtlba_opcode = {
+ "idtlba",
+ 3,
+ idtlba_template,
+ &itlba_iclass
+};
+
+static xtensa_opcode_internal ihi_opcode = {
+ "ihi",
+ 3,
+ ihi_template,
+ &icache_iclass
+};
+
+static xtensa_opcode_internal iii_opcode = {
+ "iii",
+ 3,
+ iii_template,
+ &icache_iclass
+};
+
+static xtensa_opcode_internal iitlb_opcode = {
+ "iitlb",
+ 3,
+ iitlb_template,
+ &itlb_iclass
+};
+
+static xtensa_opcode_internal iitlba_opcode = {
+ "iitlba",
+ 3,
+ iitlba_template,
+ &itlba_iclass
+};
+
+static xtensa_opcode_internal ipf_opcode = {
+ "ipf",
+ 3,
+ ipf_template,
+ &icache_iclass
+};
+
+static xtensa_opcode_internal isync_opcode = {
+ "isync",
+ 3,
+ isync_template,
+ &sync_iclass
+};
+
+static xtensa_opcode_internal j_opcode = {
+ "j",
+ 3,
+ j_template,
+ &jump_iclass
+};
+
+static xtensa_opcode_internal jx_opcode = {
+ "jx",
+ 3,
+ jx_template,
+ &jumpx_iclass
+};
+
+static xtensa_opcode_internal l16si_opcode = {
+ "l16si",
+ 3,
+ l16si_template,
+ &l16i_iclass
+};
+
+static xtensa_opcode_internal l16ui_opcode = {
+ "l16ui",
+ 3,
+ l16ui_template,
+ &l16i_iclass
+};
+
+static xtensa_opcode_internal l32e_opcode = {
+ "l32e",
+ 3,
+ l32e_template,
+ &l32e_iclass
+};
+
+static xtensa_opcode_internal l32i_opcode = {
+ "l32i",
+ 3,
+ l32i_template,
+ &l32i_iclass
+};
+
+static xtensa_opcode_internal l32i_n_opcode = {
+ "l32i.n",
+ 2,
+ l32i_n_template,
+ &loadi4_iclass
+};
+
+static xtensa_opcode_internal l32r_opcode = {
+ "l32r",
+ 3,
+ l32r_template,
+ &l32r_iclass
+};
+
+static xtensa_opcode_internal l8ui_opcode = {
+ "l8ui",
+ 3,
+ l8ui_template,
+ &l8i_iclass
+};
+
+static xtensa_opcode_internal ldct_opcode = {
+ "ldct",
+ 3,
+ ldct_template,
+ &actl_iclass
+};
+
+static xtensa_opcode_internal lict_opcode = {
+ "lict",
+ 3,
+ lict_template,
+ &actl_iclass
+};
+
+static xtensa_opcode_internal licw_opcode = {
+ "licw",
+ 3,
+ licw_template,
+ &actl_iclass
+};
+
+static xtensa_opcode_internal loop_opcode = {
+ "loop",
+ 3,
+ loop_template,
+ &loop_iclass
+};
+
+static xtensa_opcode_internal loopgtz_opcode = {
+ "loopgtz",
+ 3,
+ loopgtz_template,
+ &loop_iclass
+};
+
+static xtensa_opcode_internal loopnez_opcode = {
+ "loopnez",
+ 3,
+ loopnez_template,
+ &loop_iclass
+};
+
+static xtensa_opcode_internal memw_opcode = {
+ "memw",
+ 3,
+ memw_template,
+ &sync_iclass
+};
+
+static xtensa_opcode_internal mov_n_opcode = {
+ "mov.n",
+ 2,
+ mov_n_template,
+ &mov_n_iclass
+};
+
+static xtensa_opcode_internal moveqz_opcode = {
+ "moveqz",
+ 3,
+ moveqz_template,
+ &movz_iclass
+};
+
+static xtensa_opcode_internal movgez_opcode = {
+ "movgez",
+ 3,
+ movgez_template,
+ &movz_iclass
+};
+
+static xtensa_opcode_internal movi_opcode = {
+ "movi",
+ 3,
+ movi_template,
+ &movi_iclass
+};
+
+static xtensa_opcode_internal movi_n_opcode = {
+ "movi.n",
+ 2,
+ movi_n_template,
+ &movi_n_iclass
+};
+
+static xtensa_opcode_internal movltz_opcode = {
+ "movltz",
+ 3,
+ movltz_template,
+ &movz_iclass
+};
+
+static xtensa_opcode_internal movnez_opcode = {
+ "movnez",
+ 3,
+ movnez_template,
+ &movz_iclass
+};
+
+static xtensa_opcode_internal movsp_opcode = {
+ "movsp",
+ 3,
+ movsp_template,
+ &movsp_iclass
+};
+
+static xtensa_opcode_internal neg_opcode = {
+ "neg",
+ 3,
+ neg_template,
+ &neg_iclass
+};
+
+static xtensa_opcode_internal nop_n_opcode = {
+ "nop.n",
+ 2,
+ nop_n_template,
+ &nopn_iclass
+};
+
+static xtensa_opcode_internal nsa_opcode = {
+ "nsa",
+ 3,
+ nsa_template,
+ &nsa_iclass
+};
+
+static xtensa_opcode_internal nsau_opcode = {
+ "nsau",
+ 3,
+ nsau_template,
+ &nsa_iclass
+};
+
+static xtensa_opcode_internal or_opcode = {
+ "or",
+ 3,
+ or_template,
+ &bit_iclass
+};
+
+static xtensa_opcode_internal pdtlb_opcode = {
+ "pdtlb",
+ 3,
+ pdtlb_template,
+ &rtlb_iclass
+};
+
+static xtensa_opcode_internal pitlb_opcode = {
+ "pitlb",
+ 3,
+ pitlb_template,
+ &rtlb_iclass
+};
+
+static xtensa_opcode_internal rdtlb0_opcode = {
+ "rdtlb0",
+ 3,
+ rdtlb0_template,
+ &rtlb_iclass
+};
+
+static xtensa_opcode_internal rdtlb1_opcode = {
+ "rdtlb1",
+ 3,
+ rdtlb1_template,
+ &rtlb_iclass
+};
+
+static xtensa_opcode_internal ret_opcode = {
+ "ret",
+ 3,
+ ret_template,
+ &return_iclass
+};
+
+static xtensa_opcode_internal ret_n_opcode = {
+ "ret.n",
+ 2,
+ ret_n_template,
+ &retn_iclass
+};
+
+static xtensa_opcode_internal retw_opcode = {
+ "retw",
+ 3,
+ retw_template,
+ &return_iclass
+};
+
+static xtensa_opcode_internal retw_n_opcode = {
+ "retw.n",
+ 2,
+ retw_n_template,
+ &retn_iclass
+};
+
+static xtensa_opcode_internal rfde_opcode = {
+ "rfde",
+ 3,
+ rfde_template,
+ &rfe_iclass
+};
+
+static xtensa_opcode_internal rfe_opcode = {
+ "rfe",
+ 3,
+ rfe_template,
+ &rfe_iclass
+};
+
+static xtensa_opcode_internal rfi_opcode = {
+ "rfi",
+ 3,
+ rfi_template,
+ &rfi_iclass
+};
+
+static xtensa_opcode_internal rfwo_opcode = {
+ "rfwo",
+ 3,
+ rfwo_template,
+ &rfe_iclass
+};
+
+static xtensa_opcode_internal rfwu_opcode = {
+ "rfwu",
+ 3,
+ rfwu_template,
+ &rfe_iclass
+};
+
+static xtensa_opcode_internal ritlb0_opcode = {
+ "ritlb0",
+ 3,
+ ritlb0_template,
+ &rtlb_iclass
+};
+
+static xtensa_opcode_internal ritlb1_opcode = {
+ "ritlb1",
+ 3,
+ ritlb1_template,
+ &rtlb_iclass
+};
+
+static xtensa_opcode_internal rotw_opcode = {
+ "rotw",
+ 3,
+ rotw_template,
+ &rotw_iclass
+};
+
+static xtensa_opcode_internal rsil_opcode = {
+ "rsil",
+ 3,
+ rsil_template,
+ &rsil_iclass
+};
+
+static xtensa_opcode_internal rsr_opcode = {
+ "rsr",
+ 3,
+ rsr_template,
+ &rsr_iclass
+};
+
+static xtensa_opcode_internal rsync_opcode = {
+ "rsync",
+ 3,
+ rsync_template,
+ &sync_iclass
+};
+
+static xtensa_opcode_internal s16i_opcode = {
+ "s16i",
+ 3,
+ s16i_template,
+ &s16i_iclass
+};
+
+static xtensa_opcode_internal s32e_opcode = {
+ "s32e",
+ 3,
+ s32e_template,
+ &s32e_iclass
+};
+
+static xtensa_opcode_internal s32i_opcode = {
+ "s32i",
+ 3,
+ s32i_template,
+ &s32i_iclass
+};
+
+static xtensa_opcode_internal s32i_n_opcode = {
+ "s32i.n",
+ 2,
+ s32i_n_template,
+ &storei4_iclass
+};
+
+static xtensa_opcode_internal s8i_opcode = {
+ "s8i",
+ 3,
+ s8i_template,
+ &s8i_iclass
+};
+
+static xtensa_opcode_internal sdct_opcode = {
+ "sdct",
+ 3,
+ sdct_template,
+ &acts_iclass
+};
+
+static xtensa_opcode_internal sict_opcode = {
+ "sict",
+ 3,
+ sict_template,
+ &acts_iclass
+};
+
+static xtensa_opcode_internal sicw_opcode = {
+ "sicw",
+ 3,
+ sicw_template,
+ &acts_iclass
+};
+
+static xtensa_opcode_internal simcall_opcode = {
+ "simcall",
+ 3,
+ simcall_template,
+ &syscall_iclass
+};
+
+static xtensa_opcode_internal sll_opcode = {
+ "sll",
+ 3,
+ sll_template,
+ &shifts_iclass
+};
+
+static xtensa_opcode_internal slli_opcode = {
+ "slli",
+ 3,
+ slli_template,
+ &slli_iclass
+};
+
+static xtensa_opcode_internal sra_opcode = {
+ "sra",
+ 3,
+ sra_template,
+ &shiftt_iclass
+};
+
+static xtensa_opcode_internal srai_opcode = {
+ "srai",
+ 3,
+ srai_template,
+ &srai_iclass
+};
+
+static xtensa_opcode_internal src_opcode = {
+ "src",
+ 3,
+ src_template,
+ &shiftst_iclass
+};
+
+static xtensa_opcode_internal srl_opcode = {
+ "srl",
+ 3,
+ srl_template,
+ &shiftt_iclass
+};
+
+static xtensa_opcode_internal srli_opcode = {
+ "srli",
+ 3,
+ srli_template,
+ &srli_iclass
+};
+
+static xtensa_opcode_internal ssa8b_opcode = {
+ "ssa8b",
+ 3,
+ ssa8b_template,
+ &sar_iclass
+};
+
+static xtensa_opcode_internal ssa8l_opcode = {
+ "ssa8l",
+ 3,
+ ssa8l_template,
+ &sar_iclass
+};
+
+static xtensa_opcode_internal ssai_opcode = {
+ "ssai",
+ 3,
+ ssai_template,
+ &sari_iclass
+};
+
+static xtensa_opcode_internal ssl_opcode = {
+ "ssl",
+ 3,
+ ssl_template,
+ &sar_iclass
+};
+
+static xtensa_opcode_internal ssr_opcode = {
+ "ssr",
+ 3,
+ ssr_template,
+ &sar_iclass
+};
+
+static xtensa_opcode_internal sub_opcode = {
+ "sub",
+ 3,
+ sub_template,
+ &addsub_iclass
+};
+
+static xtensa_opcode_internal subx2_opcode = {
+ "subx2",
+ 3,
+ subx2_template,
+ &addsub_iclass
+};
+
+static xtensa_opcode_internal subx4_opcode = {
+ "subx4",
+ 3,
+ subx4_template,
+ &addsub_iclass
+};
+
+static xtensa_opcode_internal subx8_opcode = {
+ "subx8",
+ 3,
+ subx8_template,
+ &addsub_iclass
+};
+
+static xtensa_opcode_internal syscall_opcode = {
+ "syscall",
+ 3,
+ syscall_template,
+ &syscall_iclass
+};
+
+static xtensa_opcode_internal waiti_opcode = {
+ "waiti",
+ 3,
+ waiti_template,
+ &wait_iclass
+};
+
+static xtensa_opcode_internal wdtlb_opcode = {
+ "wdtlb",
+ 3,
+ wdtlb_template,
+ &wtlb_iclass
+};
+
+static xtensa_opcode_internal witlb_opcode = {
+ "witlb",
+ 3,
+ witlb_template,
+ &wtlb_iclass
+};
+
+static xtensa_opcode_internal wsr_opcode = {
+ "wsr",
+ 3,
+ wsr_template,
+ &wsr_iclass
+};
+
+static xtensa_opcode_internal xor_opcode = {
+ "xor",
+ 3,
+ xor_template,
+ &bit_iclass
+};
+
+static xtensa_opcode_internal xsr_opcode = {
+ "xsr",
+ 3,
+ xsr_template,
+ &xsr_iclass
+};
+
+static xtensa_opcode_internal * opcodes[149] = {
+ &abs_opcode,
+ &add_opcode,
+ &add_n_opcode,
+ &addi_opcode,
+ &addi_n_opcode,
+ &addmi_opcode,
+ &addx2_opcode,
+ &addx4_opcode,
+ &addx8_opcode,
+ &and_opcode,
+ &ball_opcode,
+ &bany_opcode,
+ &bbc_opcode,
+ &bbci_opcode,
+ &bbs_opcode,
+ &bbsi_opcode,
+ &beq_opcode,
+ &beqi_opcode,
+ &beqz_opcode,
+ &beqz_n_opcode,
+ &bge_opcode,
+ &bgei_opcode,
+ &bgeu_opcode,
+ &bgeui_opcode,
+ &bgez_opcode,
+ &blt_opcode,
+ &blti_opcode,
+ &bltu_opcode,
+ &bltui_opcode,
+ &bltz_opcode,
+ &bnall_opcode,
+ &bne_opcode,
+ &bnei_opcode,
+ &bnez_opcode,
+ &bnez_n_opcode,
+ &bnone_opcode,
+ &break_opcode,
+ &break_n_opcode,
+ &call0_opcode,
+ &call12_opcode,
+ &call4_opcode,
+ &call8_opcode,
+ &callx0_opcode,
+ &callx12_opcode,
+ &callx4_opcode,
+ &callx8_opcode,
+ &dhi_opcode,
+ &dhwb_opcode,
+ &dhwbi_opcode,
+ &dii_opcode,
+ &diwb_opcode,
+ &diwbi_opcode,
+ &dpfr_opcode,
+ &dpfro_opcode,
+ &dpfw_opcode,
+ &dpfwo_opcode,
+ &dsync_opcode,
+ &entry_opcode,
+ &esync_opcode,
+ &excw_opcode,
+ &extui_opcode,
+ &idtlb_opcode,
+ &idtlba_opcode,
+ &ihi_opcode,
+ &iii_opcode,
+ &iitlb_opcode,
+ &iitlba_opcode,
+ &ipf_opcode,
+ &isync_opcode,
+ &j_opcode,
+ &jx_opcode,
+ &l16si_opcode,
+ &l16ui_opcode,
+ &l32e_opcode,
+ &l32i_opcode,
+ &l32i_n_opcode,
+ &l32r_opcode,
+ &l8ui_opcode,
+ &ldct_opcode,
+ &lict_opcode,
+ &licw_opcode,
+ &loop_opcode,
+ &loopgtz_opcode,
+ &loopnez_opcode,
+ &memw_opcode,
+ &mov_n_opcode,
+ &moveqz_opcode,
+ &movgez_opcode,
+ &movi_opcode,
+ &movi_n_opcode,
+ &movltz_opcode,
+ &movnez_opcode,
+ &movsp_opcode,
+ &neg_opcode,
+ &nop_n_opcode,
+ &nsa_opcode,
+ &nsau_opcode,
+ &or_opcode,
+ &pdtlb_opcode,
+ &pitlb_opcode,
+ &rdtlb0_opcode,
+ &rdtlb1_opcode,
+ &ret_opcode,
+ &ret_n_opcode,
+ &retw_opcode,
+ &retw_n_opcode,
+ &rfde_opcode,
+ &rfe_opcode,
+ &rfi_opcode,
+ &rfwo_opcode,
+ &rfwu_opcode,
+ &ritlb0_opcode,
+ &ritlb1_opcode,
+ &rotw_opcode,
+ &rsil_opcode,
+ &rsr_opcode,
+ &rsync_opcode,
+ &s16i_opcode,
+ &s32e_opcode,
+ &s32i_opcode,
+ &s32i_n_opcode,
+ &s8i_opcode,
+ &sdct_opcode,
+ &sict_opcode,
+ &sicw_opcode,
+ &simcall_opcode,
+ &sll_opcode,
+ &slli_opcode,
+ &sra_opcode,
+ &srai_opcode,
+ &src_opcode,
+ &srl_opcode,
+ &srli_opcode,
+ &ssa8b_opcode,
+ &ssa8l_opcode,
+ &ssai_opcode,
+ &ssl_opcode,
+ &ssr_opcode,
+ &sub_opcode,
+ &subx2_opcode,
+ &subx4_opcode,
+ &subx8_opcode,
+ &syscall_opcode,
+ &waiti_opcode,
+ &wdtlb_opcode,
+ &witlb_opcode,
+ &wsr_opcode,
+ &xor_opcode,
+ &xsr_opcode
+};
+
+xtensa_opcode_internal **
+get_opcodes (void)
+{
+ return &opcodes[0];
+}
+
+const int
+get_num_opcodes (void)
+{
+ return 149;
+}
+
+#define xtensa_abs_op 0
+#define xtensa_add_op 1
+#define xtensa_add_n_op 2
+#define xtensa_addi_op 3
+#define xtensa_addi_n_op 4
+#define xtensa_addmi_op 5
+#define xtensa_addx2_op 6
+#define xtensa_addx4_op 7
+#define xtensa_addx8_op 8
+#define xtensa_and_op 9
+#define xtensa_ball_op 10
+#define xtensa_bany_op 11
+#define xtensa_bbc_op 12
+#define xtensa_bbci_op 13
+#define xtensa_bbs_op 14
+#define xtensa_bbsi_op 15
+#define xtensa_beq_op 16
+#define xtensa_beqi_op 17
+#define xtensa_beqz_op 18
+#define xtensa_beqz_n_op 19
+#define xtensa_bge_op 20
+#define xtensa_bgei_op 21
+#define xtensa_bgeu_op 22
+#define xtensa_bgeui_op 23
+#define xtensa_bgez_op 24
+#define xtensa_blt_op 25
+#define xtensa_blti_op 26
+#define xtensa_bltu_op 27
+#define xtensa_bltui_op 28
+#define xtensa_bltz_op 29
+#define xtensa_bnall_op 30
+#define xtensa_bne_op 31
+#define xtensa_bnei_op 32
+#define xtensa_bnez_op 33
+#define xtensa_bnez_n_op 34
+#define xtensa_bnone_op 35
+#define xtensa_break_op 36
+#define xtensa_break_n_op 37
+#define xtensa_call0_op 38
+#define xtensa_call12_op 39
+#define xtensa_call4_op 40
+#define xtensa_call8_op 41
+#define xtensa_callx0_op 42
+#define xtensa_callx12_op 43
+#define xtensa_callx4_op 44
+#define xtensa_callx8_op 45
+#define xtensa_dhi_op 46
+#define xtensa_dhwb_op 47
+#define xtensa_dhwbi_op 48
+#define xtensa_dii_op 49
+#define xtensa_diwb_op 50
+#define xtensa_diwbi_op 51
+#define xtensa_dpfr_op 52
+#define xtensa_dpfro_op 53
+#define xtensa_dpfw_op 54
+#define xtensa_dpfwo_op 55
+#define xtensa_dsync_op 56
+#define xtensa_entry_op 57
+#define xtensa_esync_op 58
+#define xtensa_excw_op 59
+#define xtensa_extui_op 60
+#define xtensa_idtlb_op 61
+#define xtensa_idtlba_op 62
+#define xtensa_ihi_op 63
+#define xtensa_iii_op 64
+#define xtensa_iitlb_op 65
+#define xtensa_iitlba_op 66
+#define xtensa_ipf_op 67
+#define xtensa_isync_op 68
+#define xtensa_j_op 69
+#define xtensa_jx_op 70
+#define xtensa_l16si_op 71
+#define xtensa_l16ui_op 72
+#define xtensa_l32e_op 73
+#define xtensa_l32i_op 74
+#define xtensa_l32i_n_op 75
+#define xtensa_l32r_op 76
+#define xtensa_l8ui_op 77
+#define xtensa_ldct_op 78
+#define xtensa_lict_op 79
+#define xtensa_licw_op 80
+#define xtensa_loop_op 81
+#define xtensa_loopgtz_op 82
+#define xtensa_loopnez_op 83
+#define xtensa_memw_op 84
+#define xtensa_mov_n_op 85
+#define xtensa_moveqz_op 86
+#define xtensa_movgez_op 87
+#define xtensa_movi_op 88
+#define xtensa_movi_n_op 89
+#define xtensa_movltz_op 90
+#define xtensa_movnez_op 91
+#define xtensa_movsp_op 92
+#define xtensa_neg_op 93
+#define xtensa_nop_n_op 94
+#define xtensa_nsa_op 95
+#define xtensa_nsau_op 96
+#define xtensa_or_op 97
+#define xtensa_pdtlb_op 98
+#define xtensa_pitlb_op 99
+#define xtensa_rdtlb0_op 100
+#define xtensa_rdtlb1_op 101
+#define xtensa_ret_op 102
+#define xtensa_ret_n_op 103
+#define xtensa_retw_op 104
+#define xtensa_retw_n_op 105
+#define xtensa_rfde_op 106
+#define xtensa_rfe_op 107
+#define xtensa_rfi_op 108
+#define xtensa_rfwo_op 109
+#define xtensa_rfwu_op 110
+#define xtensa_ritlb0_op 111
+#define xtensa_ritlb1_op 112
+#define xtensa_rotw_op 113
+#define xtensa_rsil_op 114
+#define xtensa_rsr_op 115
+#define xtensa_rsync_op 116
+#define xtensa_s16i_op 117
+#define xtensa_s32e_op 118
+#define xtensa_s32i_op 119
+#define xtensa_s32i_n_op 120
+#define xtensa_s8i_op 121
+#define xtensa_sdct_op 122
+#define xtensa_sict_op 123
+#define xtensa_sicw_op 124
+#define xtensa_simcall_op 125
+#define xtensa_sll_op 126
+#define xtensa_slli_op 127
+#define xtensa_sra_op 128
+#define xtensa_srai_op 129
+#define xtensa_src_op 130
+#define xtensa_srl_op 131
+#define xtensa_srli_op 132
+#define xtensa_ssa8b_op 133
+#define xtensa_ssa8l_op 134
+#define xtensa_ssai_op 135
+#define xtensa_ssl_op 136
+#define xtensa_ssr_op 137
+#define xtensa_sub_op 138
+#define xtensa_subx2_op 139
+#define xtensa_subx4_op 140
+#define xtensa_subx8_op 141
+#define xtensa_syscall_op 142
+#define xtensa_waiti_op 143
+#define xtensa_wdtlb_op 144
+#define xtensa_witlb_op 145
+#define xtensa_wsr_op 146
+#define xtensa_xor_op 147
+#define xtensa_xsr_op 148
+
+int
+decode_insn (const xtensa_insnbuf insn)
+{
+ switch (get_op0_field (insn)) {
+ case 0: /* QRST: op0=0000 */
+ switch (get_op1_field (insn)) {
+ case 3: /* RST3: op1=0011 */
+ switch (get_op2_field (insn)) {
+ case 8: /* MOVEQZ: op2=1000 */
+ return xtensa_moveqz_op;
+ case 9: /* MOVNEZ: op2=1001 */
+ return xtensa_movnez_op;
+ case 10: /* MOVLTZ: op2=1010 */
+ return xtensa_movltz_op;
+ case 11: /* MOVGEZ: op2=1011 */
+ return xtensa_movgez_op;
+ case 0: /* RSR: op2=0000 */
+ return xtensa_rsr_op;
+ case 1: /* WSR: op2=0001 */
+ return xtensa_wsr_op;
+ }
+ break;
+ case 9: /* LSI4: op1=1001 */
+ switch (get_op2_field (insn)) {
+ case 4: /* S32E: op2=0100 */
+ return xtensa_s32e_op;
+ case 0: /* L32E: op2=0000 */
+ return xtensa_l32e_op;
+ }
+ break;
+ case 4: /* EXTUI: op1=010x */
+ case 5: /* EXTUI: op1=010x */
+ return xtensa_extui_op;
+ case 0: /* RST0: op1=0000 */
+ switch (get_op2_field (insn)) {
+ case 15: /* SUBX8: op2=1111 */
+ return xtensa_subx8_op;
+ case 0: /* ST0: op2=0000 */
+ switch (get_r_field (insn)) {
+ case 0: /* SNM0: r=0000 */
+ switch (get_m_field (insn)) {
+ case 2: /* JR: m=10 */
+ switch (get_n_field (insn)) {
+ case 0: /* RET: n=00 */
+ return xtensa_ret_op;
+ case 1: /* RETW: n=01 */
+ return xtensa_retw_op;
+ case 2: /* JX: n=10 */
+ return xtensa_jx_op;
+ }
+ break;
+ case 3: /* CALLX: m=11 */
+ switch (get_n_field (insn)) {
+ case 0: /* CALLX0: n=00 */
+ return xtensa_callx0_op;
+ case 1: /* CALLX4: n=01 */
+ return xtensa_callx4_op;
+ case 2: /* CALLX8: n=10 */
+ return xtensa_callx8_op;
+ case 3: /* CALLX12: n=11 */
+ return xtensa_callx12_op;
+ }
+ break;
+ }
+ break;
+ case 1: /* MOVSP: r=0001 */
+ return xtensa_movsp_op;
+ case 2: /* SYNC: r=0010 */
+ switch (get_s_field (insn)) {
+ case 0: /* SYNCT: s=0000 */
+ switch (get_t_field (insn)) {
+ case 2: /* ESYNC: t=0010 */
+ return xtensa_esync_op;
+ case 3: /* DSYNC: t=0011 */
+ return xtensa_dsync_op;
+ case 8: /* EXCW: t=1000 */
+ return xtensa_excw_op;
+ case 12: /* MEMW: t=1100 */
+ return xtensa_memw_op;
+ case 0: /* ISYNC: t=0000 */
+ return xtensa_isync_op;
+ case 1: /* RSYNC: t=0001 */
+ return xtensa_rsync_op;
+ }
+ break;
+ }
+ break;
+ case 4: /* BREAK: r=0100 */
+ return xtensa_break_op;
+ case 3: /* RFEI: r=0011 */
+ switch (get_t_field (insn)) {
+ case 0: /* RFET: t=0000 */
+ switch (get_s_field (insn)) {
+ case 2: /* RFDE: s=0010 */
+ return xtensa_rfde_op;
+ case 4: /* RFWO: s=0100 */
+ return xtensa_rfwo_op;
+ case 5: /* RFWU: s=0101 */
+ return xtensa_rfwu_op;
+ case 0: /* RFE: s=0000 */
+ return xtensa_rfe_op;
+ }
+ break;
+ case 1: /* RFI: t=0001 */
+ return xtensa_rfi_op;
+ }
+ break;
+ case 5: /* SCALL: r=0101 */
+ switch (get_s_field (insn)) {
+ case 0: /* SYSCALL: s=0000 */
+ return xtensa_syscall_op;
+ case 1: /* SIMCALL: s=0001 */
+ return xtensa_simcall_op;
+ }
+ break;
+ case 6: /* RSIL: r=0110 */
+ return xtensa_rsil_op;
+ case 7: /* WAITI: r=0111 */
+ return xtensa_waiti_op;
+ }
+ break;
+ case 1: /* AND: op2=0001 */
+ return xtensa_and_op;
+ case 2: /* OR: op2=0010 */
+ return xtensa_or_op;
+ case 3: /* XOR: op2=0011 */
+ return xtensa_xor_op;
+ case 4: /* ST1: op2=0100 */
+ switch (get_r_field (insn)) {
+ case 15: /* NSAU: r=1111 */
+ return xtensa_nsau_op;
+ case 0: /* SSR: r=0000 */
+ return xtensa_ssr_op;
+ case 1: /* SSL: r=0001 */
+ return xtensa_ssl_op;
+ case 2: /* SSA8L: r=0010 */
+ return xtensa_ssa8l_op;
+ case 3: /* SSA8B: r=0011 */
+ return xtensa_ssa8b_op;
+ case 4: /* SSAI: r=0100 */
+ return xtensa_ssai_op;
+ case 8: /* ROTW: r=1000 */
+ return xtensa_rotw_op;
+ case 14: /* NSA: r=1110 */
+ return xtensa_nsa_op;
+ }
+ break;
+ case 8: /* ADD: op2=1000 */
+ return xtensa_add_op;
+ case 5: /* ST4: op2=0101 */
+ switch (get_r_field (insn)) {
+ case 15: /* RDTLB1: r=1111 */
+ return xtensa_rdtlb1_op;
+ case 0: /* IITLBA: r=0000 */
+ return xtensa_iitlba_op;
+ case 3: /* RITLB0: r=0011 */
+ return xtensa_ritlb0_op;
+ case 4: /* IITLB: r=0100 */
+ return xtensa_iitlb_op;
+ case 8: /* IDTLBA: r=1000 */
+ return xtensa_idtlba_op;
+ case 5: /* PITLB: r=0101 */
+ return xtensa_pitlb_op;
+ case 6: /* WITLB: r=0110 */
+ return xtensa_witlb_op;
+ case 7: /* RITLB1: r=0111 */
+ return xtensa_ritlb1_op;
+ case 11: /* RDTLB0: r=1011 */
+ return xtensa_rdtlb0_op;
+ case 12: /* IDTLB: r=1100 */
+ return xtensa_idtlb_op;
+ case 13: /* PDTLB: r=1101 */
+ return xtensa_pdtlb_op;
+ case 14: /* WDTLB: r=1110 */
+ return xtensa_wdtlb_op;
+ }
+ break;
+ case 6: /* RT0: op2=0110 */
+ switch (get_s_field (insn)) {
+ case 0: /* NEG: s=0000 */
+ return xtensa_neg_op;
+ case 1: /* ABS: s=0001 */
+ return xtensa_abs_op;
+ }
+ break;
+ case 9: /* ADDX2: op2=1001 */
+ return xtensa_addx2_op;
+ case 10: /* ADDX4: op2=1010 */
+ return xtensa_addx4_op;
+ case 11: /* ADDX8: op2=1011 */
+ return xtensa_addx8_op;
+ case 12: /* SUB: op2=1100 */
+ return xtensa_sub_op;
+ case 13: /* SUBX2: op2=1101 */
+ return xtensa_subx2_op;
+ case 14: /* SUBX4: op2=1110 */
+ return xtensa_subx4_op;
+ }
+ break;
+ case 1: /* RST1: op1=0001 */
+ switch (get_op2_field (insn)) {
+ case 15: /* IMP: op2=1111 */
+ switch (get_r_field (insn)) {
+ case 0: /* LICT: r=0000 */
+ return xtensa_lict_op;
+ case 1: /* SICT: r=0001 */
+ return xtensa_sict_op;
+ case 2: /* LICW: r=0010 */
+ return xtensa_licw_op;
+ case 3: /* SICW: r=0011 */
+ return xtensa_sicw_op;
+ case 8: /* LDCT: r=1000 */
+ return xtensa_ldct_op;
+ case 9: /* SDCT: r=1001 */
+ return xtensa_sdct_op;
+ }
+ break;
+ case 0: /* SLLI: op2=000x */
+ case 1: /* SLLI: op2=000x */
+ return xtensa_slli_op;
+ case 2: /* SRAI: op2=001x */
+ case 3: /* SRAI: op2=001x */
+ return xtensa_srai_op;
+ case 4: /* SRLI: op2=0100 */
+ return xtensa_srli_op;
+ case 8: /* SRC: op2=1000 */
+ return xtensa_src_op;
+ case 9: /* SRL: op2=1001 */
+ return xtensa_srl_op;
+ case 6: /* XSR: op2=0110 */
+ return xtensa_xsr_op;
+ case 10: /* SLL: op2=1010 */
+ return xtensa_sll_op;
+ case 11: /* SRA: op2=1011 */
+ return xtensa_sra_op;
+ }
+ break;
+ }
+ break;
+ case 1: /* L32R: op0=0001 */
+ return xtensa_l32r_op;
+ case 2: /* LSAI: op0=0010 */
+ switch (get_r_field (insn)) {
+ case 0: /* L8UI: r=0000 */
+ return xtensa_l8ui_op;
+ case 1: /* L16UI: r=0001 */
+ return xtensa_l16ui_op;
+ case 2: /* L32I: r=0010 */
+ return xtensa_l32i_op;
+ case 4: /* S8I: r=0100 */
+ return xtensa_s8i_op;
+ case 5: /* S16I: r=0101 */
+ return xtensa_s16i_op;
+ case 9: /* L16SI: r=1001 */
+ return xtensa_l16si_op;
+ case 6: /* S32I: r=0110 */
+ return xtensa_s32i_op;
+ case 7: /* CACHE: r=0111 */
+ switch (get_t_field (insn)) {
+ case 15: /* III: t=1111 */
+ return xtensa_iii_op;
+ case 0: /* DPFR: t=0000 */
+ return xtensa_dpfr_op;
+ case 1: /* DPFW: t=0001 */
+ return xtensa_dpfw_op;
+ case 2: /* DPFRO: t=0010 */
+ return xtensa_dpfro_op;
+ case 4: /* DHWB: t=0100 */
+ return xtensa_dhwb_op;
+ case 3: /* DPFWO: t=0011 */
+ return xtensa_dpfwo_op;
+ case 8: /* DCE: t=1000 */
+ switch (get_op1_field (insn)) {
+ case 4: /* DIWB: op1=0100 */
+ return xtensa_diwb_op;
+ case 5: /* DIWBI: op1=0101 */
+ return xtensa_diwbi_op;
+ }
+ break;
+ case 5: /* DHWBI: t=0101 */
+ return xtensa_dhwbi_op;
+ case 6: /* DHI: t=0110 */
+ return xtensa_dhi_op;
+ case 7: /* DII: t=0111 */
+ return xtensa_dii_op;
+ case 12: /* IPF: t=1100 */
+ return xtensa_ipf_op;
+ case 14: /* IHI: t=1110 */
+ return xtensa_ihi_op;
+ }
+ break;
+ case 10: /* MOVI: r=1010 */
+ return xtensa_movi_op;
+ case 12: /* ADDI: r=1100 */
+ return xtensa_addi_op;
+ case 13: /* ADDMI: r=1101 */
+ return xtensa_addmi_op;
+ }
+ break;
+ case 8: /* L32I.N: op0=1000 */
+ return xtensa_l32i_n_op;
+ case 5: /* CALL: op0=0101 */
+ switch (get_n_field (insn)) {
+ case 0: /* CALL0: n=00 */
+ return xtensa_call0_op;
+ case 1: /* CALL4: n=01 */
+ return xtensa_call4_op;
+ case 2: /* CALL8: n=10 */
+ return xtensa_call8_op;
+ case 3: /* CALL12: n=11 */
+ return xtensa_call12_op;
+ }
+ break;
+ case 6: /* SI: op0=0110 */
+ switch (get_n_field (insn)) {
+ case 0: /* J: n=00 */
+ return xtensa_j_op;
+ case 1: /* BZ: n=01 */
+ switch (get_m_field (insn)) {
+ case 0: /* BEQZ: m=00 */
+ return xtensa_beqz_op;
+ case 1: /* BNEZ: m=01 */
+ return xtensa_bnez_op;
+ case 2: /* BLTZ: m=10 */
+ return xtensa_bltz_op;
+ case 3: /* BGEZ: m=11 */
+ return xtensa_bgez_op;
+ }
+ break;
+ case 2: /* BI0: n=10 */
+ switch (get_m_field (insn)) {
+ case 0: /* BEQI: m=00 */
+ return xtensa_beqi_op;
+ case 1: /* BNEI: m=01 */
+ return xtensa_bnei_op;
+ case 2: /* BLTI: m=10 */
+ return xtensa_blti_op;
+ case 3: /* BGEI: m=11 */
+ return xtensa_bgei_op;
+ }
+ break;
+ case 3: /* BI1: n=11 */
+ switch (get_m_field (insn)) {
+ case 0: /* ENTRY: m=00 */
+ return xtensa_entry_op;
+ case 1: /* B1: m=01 */
+ switch (get_r_field (insn)) {
+ case 8: /* LOOP: r=1000 */
+ return xtensa_loop_op;
+ case 9: /* LOOPNEZ: r=1001 */
+ return xtensa_loopnez_op;
+ case 10: /* LOOPGTZ: r=1010 */
+ return xtensa_loopgtz_op;
+ }
+ break;
+ case 2: /* BLTUI: m=10 */
+ return xtensa_bltui_op;
+ case 3: /* BGEUI: m=11 */
+ return xtensa_bgeui_op;
+ }
+ break;
+ }
+ break;
+ case 9: /* S32I.N: op0=1001 */
+ return xtensa_s32i_n_op;
+ case 10: /* ADD.N: op0=1010 */
+ return xtensa_add_n_op;
+ case 7: /* B: op0=0111 */
+ switch (get_r_field (insn)) {
+ case 6: /* BBCI: r=011x */
+ case 7: /* BBCI: r=011x */
+ return xtensa_bbci_op;
+ case 0: /* BNONE: r=0000 */
+ return xtensa_bnone_op;
+ case 1: /* BEQ: r=0001 */
+ return xtensa_beq_op;
+ case 2: /* BLT: r=0010 */
+ return xtensa_blt_op;
+ case 4: /* BALL: r=0100 */
+ return xtensa_ball_op;
+ case 14: /* BBSI: r=111x */
+ case 15: /* BBSI: r=111x */
+ return xtensa_bbsi_op;
+ case 3: /* BLTU: r=0011 */
+ return xtensa_bltu_op;
+ case 5: /* BBC: r=0101 */
+ return xtensa_bbc_op;
+ case 8: /* BANY: r=1000 */
+ return xtensa_bany_op;
+ case 9: /* BNE: r=1001 */
+ return xtensa_bne_op;
+ case 10: /* BGE: r=1010 */
+ return xtensa_bge_op;
+ case 11: /* BGEU: r=1011 */
+ return xtensa_bgeu_op;
+ case 12: /* BNALL: r=1100 */
+ return xtensa_bnall_op;
+ case 13: /* BBS: r=1101 */
+ return xtensa_bbs_op;
+ }
+ break;
+ case 11: /* ADDI.N: op0=1011 */
+ return xtensa_addi_n_op;
+ case 12: /* ST2: op0=1100 */
+ switch (get_i_field (insn)) {
+ case 0: /* MOVI.N: i=0 */
+ return xtensa_movi_n_op;
+ case 1: /* BZ6: i=1 */
+ switch (get_z_field (insn)) {
+ case 0: /* BEQZ.N: z=0 */
+ return xtensa_beqz_n_op;
+ case 1: /* BNEZ.N: z=1 */
+ return xtensa_bnez_n_op;
+ }
+ break;
+ }
+ break;
+ case 13: /* ST3: op0=1101 */
+ switch (get_r_field (insn)) {
+ case 15: /* S3: r=1111 */
+ switch (get_t_field (insn)) {
+ case 0: /* RET.N: t=0000 */
+ return xtensa_ret_n_op;
+ case 1: /* RETW.N: t=0001 */
+ return xtensa_retw_n_op;
+ case 2: /* BREAK.N: t=0010 */
+ return xtensa_break_n_op;
+ case 3: /* NOP.N: t=0011 */
+ return xtensa_nop_n_op;
+ }
+ break;
+ case 0: /* MOV.N: r=0000 */
+ return xtensa_mov_n_op;
+ }
+ break;
+ }
+ return XTENSA_UNDEFINED;
+}
+
+int
+interface_version (void)
+{
+ return 3;
+}
+
+static struct config_struct config_table[] = {
+ {"IsaMemoryOrder", "BigEndian"},
+ {"PIFReadDataBits", "128"},
+ {"PIFWriteDataBits", "128"},
+ {"IsaCoprocessorCount", "0"},
+ {"IsaUseBooleans", "0"},
+ {"IsaUseDensityInstruction", "1"},
+ {0, 0}
+};
+
+struct config_struct * get_config_table (void);
+
+struct config_struct *
+get_config_table (void)
+{
+ return config_table;
+}
+
+xtensa_isa_module xtensa_isa_modules[] = {
+ { get_num_opcodes, get_opcodes, decode_insn, get_config_table },
+ { 0, 0, 0, 0 }
+};
OpenPOWER on IntegriCloud