diff options
Diffstat (limited to 'bfd')
-rw-r--r-- | bfd/ChangeLog | 30 | ||||
-rw-r--r-- | bfd/Makefile.am | 20 | ||||
-rw-r--r-- | bfd/Makefile.in | 24 | ||||
-rw-r--r-- | bfd/archures.c | 4 | ||||
-rw-r--r-- | bfd/bfd-in2.h | 34 | ||||
-rw-r--r-- | bfd/config.bfd | 6 | ||||
-rwxr-xr-x | bfd/configure | 30 | ||||
-rw-r--r-- | bfd/configure.in | 2 | ||||
-rw-r--r-- | bfd/cpu-xtensa.c | 38 | ||||
-rw-r--r-- | bfd/elf32-xtensa.c | 5846 | ||||
-rw-r--r-- | bfd/libbfd.h | 10 | ||||
-rw-r--r-- | bfd/reloc.c | 43 | ||||
-rw-r--r-- | bfd/targets.c | 4 | ||||
-rw-r--r-- | bfd/xtensa-isa.c | 593 | ||||
-rw-r--r-- | bfd/xtensa-modules.c | 6090 |
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 §ion_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 } +}; |