1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-11-28 08:02:54 +00:00

Import the Sparc bits of GNU binutils 2.9.1.

Requested by:	steve
This commit is contained in:
David E. O'Brien 2000-04-05 04:09:32 +00:00
parent 0b91470ee9
commit 407509b3ae
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/vendor/binutils/dist/; revision=59024
13 changed files with 14178 additions and 0 deletions

View File

@ -0,0 +1,142 @@
/* BFD support for the SPARC architecture.
Copyright (C) 1992, 94, 95, 96, 1997 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"
/* Don't mix 32 bit and 64 bit files. */
static const bfd_arch_info_type *sparc_compatible
PARAMS ((const bfd_arch_info_type *, const bfd_arch_info_type *));
static const bfd_arch_info_type *
sparc_compatible (a, b)
const bfd_arch_info_type *a;
const bfd_arch_info_type *b;
{
if (a->bits_per_word != b->bits_per_word)
return NULL;
return bfd_default_compatible (a, b);
}
static const bfd_arch_info_type arch_info_struct[] =
{
{
32, /* bits in a word */
32, /* bits in an address */
8, /* bits in a byte */
bfd_arch_sparc,
bfd_mach_sparc_sparclet,
"sparc",
"sparc:sparclet",
3,
false,
sparc_compatible,
bfd_default_scan,
&arch_info_struct[1],
},
{
32, /* bits in a word */
32, /* bits in an address */
8, /* bits in a byte */
bfd_arch_sparc,
bfd_mach_sparc_sparclite,
"sparc",
"sparc:sparclite",
3,
false,
sparc_compatible,
bfd_default_scan,
&arch_info_struct[2],
},
{
32, /* bits in a word */
32, /* bits in an address */
8, /* bits in a byte */
bfd_arch_sparc,
bfd_mach_sparc_v8plus,
"sparc",
"sparc:v8plus",
3,
false,
sparc_compatible,
bfd_default_scan,
&arch_info_struct[3],
},
{
32, /* bits in a word */
32, /* bits in an address */
8, /* bits in a byte */
bfd_arch_sparc,
bfd_mach_sparc_v8plusa,
"sparc",
"sparc:v8plusa",
3,
false,
sparc_compatible,
bfd_default_scan,
&arch_info_struct[4],
},
{
64, /* bits in a word */
64, /* bits in an address */
8, /* bits in a byte */
bfd_arch_sparc,
bfd_mach_sparc_v9,
"sparc",
"sparc:v9",
3,
false,
sparc_compatible,
bfd_default_scan,
&arch_info_struct[5],
},
{
64, /* bits in a word */
64, /* bits in an address */
8, /* bits in a byte */
bfd_arch_sparc,
bfd_mach_sparc_v9a,
"sparc",
"sparc:v9a",
3,
false,
sparc_compatible,
bfd_default_scan,
0,
}
};
const bfd_arch_info_type bfd_sparc_arch =
{
32, /* bits in a word */
32, /* bits in an address */
8, /* bits in a byte */
bfd_arch_sparc,
bfd_mach_sparc,
"sparc",
"sparc",
3,
true, /* the default */
sparc_compatible,
bfd_default_scan,
&arch_info_struct[0],
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

2918
contrib/binutils/bfd/sunos.c Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,149 @@
/* tc-sparc.h - Macros and type defines for the sparc.
Copyright (C) 1989, 90-96, 97, 1998 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
GAS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2,
or (at your option) any later version.
GAS is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
the GNU General Public License for more details.
You should have received a copy of the GNU General Public
License along with GAS; see the file COPYING. If not, write
to the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#ifndef TC_SPARC
#define TC_SPARC 1
#ifdef ANSI_PROTOTYPES
struct frag;
#endif
/* This is used to set the default value for `target_big_endian'. */
#define TARGET_BYTES_BIG_ENDIAN 1
#define LOCAL_LABELS_FB 1
#define TARGET_ARCH bfd_arch_sparc
extern const char *sparc_target_format PARAMS ((void));
#define TARGET_FORMAT sparc_target_format ()
#ifdef TE_SPARCAOUT
/* Bi-endian support may eventually be unconditional, but until things are
working well it's only provided for targets that need it. */
#define SPARC_BIENDIAN
#endif
#define WORKING_DOT_WORD
#define md_convert_frag(b,s,f) {as_fatal ("sparc convert_frag\n");}
#define md_create_long_jump(p,f,t,fr,s) as_fatal("sparc_create_long_jump")
#define md_create_short_jump(p,f,t,fr,s) as_fatal("sparc_create_short_jump")
#define md_estimate_size_before_relax(f,s) \
(as_fatal("estimate_size_before_relax called"),1)
#define LISTING_HEADER "SPARC GAS "
extern int sparc_pic_code;
#define md_do_align(n, fill, len, max, around) \
if ((n) && (n) <= 10 && !need_pass_2 && !(fill) \
&& now_seg != data_section && now_seg != bss_section) \
{ \
char *p; \
p = frag_var (rs_align_code, 1024, 1, (relax_substateT) 1024, \
(symbolS *) 0, (offsetT) (n), (char *) 0); \
*p = 0x00; \
goto around; \
}
/* We require .word, et. al., to be aligned correctly. */
#define md_cons_align(nbytes) sparc_cons_align (nbytes)
extern void sparc_cons_align PARAMS ((int));
#define HANDLE_ALIGN(fragp) sparc_handle_align (fragp)
extern void sparc_handle_align PARAMS ((struct frag *));
#if defined (OBJ_ELF) || defined (OBJ_AOUT)
/* This expression evaluates to false if the relocation is for a local
object for which we still want to do the relocation at runtime.
True if we are willing to perform this relocation while building
the .o file.
If the reloc is against an externally visible symbol, then the
a.out assembler should not do the relocation if generating PIC, and
the ELF assembler should never do the relocation. */
#ifdef OBJ_ELF
#define obj_relocate_extern 0
#else
#define obj_relocate_extern (! sparc_pic_code)
#endif
#define TC_RELOC_RTSYM_LOC_FIXUP(FIX) \
(obj_relocate_extern \
|| (FIX)->fx_addsy == NULL \
|| (! S_IS_EXTERNAL ((FIX)->fx_addsy) \
&& ! S_IS_WEAK ((FIX)->fx_addsy) \
&& S_IS_DEFINED ((FIX)->fx_addsy) \
&& ! S_IS_COMMON ((FIX)->fx_addsy)))
#endif
/* I know that "call 0" fails in sparc-coff if this doesn't return 1. I
don't know about other relocation types, or other formats, yet. */
#ifdef OBJ_COFF
#define TC_FORCE_RELOCATION(FIXP) \
((FIXP)->fx_r_type == BFD_RELOC_32_PCREL_S2 \
&& ((FIXP)->fx_addsy == 0 \
|| S_GET_SEGMENT ((FIXP)->fx_addsy) == absolute_section))
#define RELOC_REQUIRES_SYMBOL
#endif
#define MD_APPLY_FIX3
#define TC_HANDLES_FX_DONE
#ifdef OBJ_ELF
/* Keep relocations against global symbols. Don't turn them into
relocations against sections. This is required for the dynamic
linker to operate properly. When generating PIC, we need to keep
any non PC relative reloc. */
#define tc_fix_adjustable(FIX) \
(! S_IS_EXTERNAL ((FIX)->fx_addsy) \
&& ! S_IS_WEAK ((FIX)->fx_addsy) \
&& (! sparc_pic_code \
|| (FIX)->fx_pcrel \
|| ((FIX)->fx_subsy != NULL \
&& (S_GET_SEGMENT ((FIX)->fx_subsy) \
== S_GET_SEGMENT ((FIX)->fx_addsy))) \
|| strchr (S_GET_NAME ((FIX)->fx_addsy), '\001') != NULL \
|| strchr (S_GET_NAME ((FIX)->fx_addsy), '\002') != NULL))
#endif
#ifdef OBJ_AOUT
/* When generating PIC code, we must not adjust any reloc which will
turn into a reloc against the global offset table. */
#define tc_fix_adjustable(FIX) \
(! sparc_pic_code \
|| (FIX)->fx_pcrel \
|| (FIX)->fx_r_type == BFD_RELOC_16 \
|| (FIX)->fx_r_type == BFD_RELOC_32)
#endif
#define elf_tc_final_processing sparc_elf_final_processing
extern void sparc_elf_final_processing PARAMS ((void));
#define md_operand(x)
extern void sparc_md_end PARAMS ((void));
#define md_end() sparc_md_end ()
#endif
/* end of tc-sparc.h */

View File

@ -0,0 +1,219 @@
/* SPARC-specific values for a.out files */
/* Some systems, e.g., AIX, may have defined this in header files already
included. */
#undef TARGET_PAGE_SIZE
#define TARGET_PAGE_SIZE 0x2000 /* 8K. aka NBPG in <sys/param.h> */
/* Note that some SPARCs have 4K pages, some 8K, some others. */
#define SEG_SIZE_SPARC TARGET_PAGE_SIZE
#define SEG_SIZE_SUN3 0x20000 /* Resolution of r/w protection hw */
#define TEXT_START_ADDR TARGET_PAGE_SIZE /* Location 0 is not accessible */
#define N_HEADER_IN_TEXT(x) 1
/* Non-default definitions of the accessor macros... */
/* Segment size varies on Sun-3 versus Sun-4. */
#define N_SEGSIZE(x) (N_MACHTYPE(x) == M_SPARC? SEG_SIZE_SPARC: \
N_MACHTYPE(x) == M_68020? SEG_SIZE_SUN3: \
/* Guess? */ TARGET_PAGE_SIZE)
/* Virtual Address of text segment from the a.out file. For OMAGIC,
(almost always "unlinked .o's" these days), should be zero.
Sun added a kludge so that shared libraries linked ZMAGIC get
an address of zero if a_entry (!!!) is lower than the otherwise
expected text address. These kludges have gotta go!
For linked files, should reflect reality if we know it. */
/* This differs from the version in aout64.h (which we override by defining
it here) only for NMAGIC (we return TEXT_START_ADDR+EXEC_BYTES_SIZE;
they return 0). */
#define N_TXTADDR(x) \
(N_MAGIC(x)==OMAGIC? 0 \
: (N_MAGIC(x) == ZMAGIC && (x).a_entry < TEXT_START_ADDR)? 0 \
: TEXT_START_ADDR+EXEC_BYTES_SIZE)
/* When a file is linked against a shared library on SunOS 4, the
dynamic bit in the exec header is set, and the first symbol in the
symbol table is __DYNAMIC. Its value is the address of the
following structure. */
struct external_sun4_dynamic
{
/* The version number of the structure. SunOS 4.1.x creates files
with version number 3, which is what this structure is based on.
According to gdb, version 2 is similar. I believe that version 2
used a different type of procedure linkage table, and there may
have been other differences. */
bfd_byte ld_version[4];
/* The virtual address of a 28 byte structure used in debugging.
The contents are filled in at run time by ld.so. */
bfd_byte ldd[4];
/* The virtual address of another structure with information about
how to relocate the executable at run time. */
bfd_byte ld[4];
};
/* The size of the debugging structure pointed to by the debugger
field of __DYNAMIC. */
#define EXTERNAL_SUN4_DYNAMIC_DEBUGGER_SIZE (24)
/* The structure pointed to by the linker field of __DYNAMIC. As far
as I can tell, most of the addresses in this structure are offsets
within the file, but some are actually virtual addresses. */
struct internal_sun4_dynamic_link
{
/* Linked list of loaded objects. This is filled in at runtime by
ld.so and probably by dlopen. */
unsigned long ld_loaded;
/* The address of the list of names of shared objects which must be
included at runtime. Each entry in the list is 16 bytes: the 4
byte address of the string naming the object (e.g., for -lc this
is "c"); 4 bytes of flags--the high bit is whether to search for
the object using the library path; the 2 byte major version
number; the 2 byte minor version number; the 4 byte address of
the next entry in the list (zero if this is the last entry). The
version numbers seem to only be non-zero when doing library
searching. */
unsigned long ld_need;
/* The address of the path to search for the shared objects which
must be included. This points to a string in PATH format which
is generated from the -L arguments to the linker. According to
the man page, ld.so implicitly adds ${LD_LIBRARY_PATH} to the
beginning of this string and /lib:/usr/lib:/usr/local/lib to the
end. The string is terminated by a null byte. This field is
zero if there is no additional path. */
unsigned long ld_rules;
/* The address of the global offset table. This appears to be a
virtual address, not a file offset. The first entry in the
global offset table seems to be the virtual address of the
sun4_dynamic structure (the same value as the __DYNAMIC symbol).
The global offset table is used for PIC code to hold the
addresses of variables. A dynamically linked file which does not
itself contain PIC code has a four byte global offset table. */
unsigned long ld_got;
/* The address of the procedure linkage table. This appears to be a
virtual address, not a file offset.
On a SPARC, the table is composed of 12 byte entries, each of
which consists of three instructions. The first entry is
sethi %hi(0),%g1
jmp %g1
nop
These instructions are changed by ld.so into a jump directly into
ld.so itself. Each subsequent entry is
save %sp, -96, %sp
call <address of first entry in procedure linkage table>
<reloc_number | 0x01000000>
The reloc_number is the number of the reloc to use to resolve
this entry. The reloc will be a JMP_SLOT reloc against some
symbol that is not defined in this object file but should be
defined in a shared object (if it is not, ld.so will report a
runtime error and exit). The constant 0x010000000 turns the
reloc number into a sethi of %g0, which does nothing since %g0 is
hardwired to zero.
When one of these entries is executed, it winds up calling into
ld.so. ld.so looks at the reloc number, available via the return
address, to determine which entry this is. It then looks at the
reloc and patches up the entry in the table into a sethi and jmp
to the real address followed by a nop. This means that the reloc
lookup only has to happen once, and it also means that the
relocation only needs to be done if the function is actually
called. The relocation is expensive because ld.so must look up
the symbol by name.
The size of the procedure linkage table is given by the ld_plt_sz
field. */
unsigned long ld_plt;
/* The address of the relocs. These are in the same format as
ordinary relocs. Symbol index numbers refer to the symbols
pointed to by ld_stab. I think the only way to determine the
number of relocs is to assume that all the bytes from ld_rel to
ld_hash contain reloc entries. */
unsigned long ld_rel;
/* The address of a hash table of symbols. The hash table has
roughly the same number of entries as there are dynamic symbols;
I think the only way to get the exact size is to assume that
every byte from ld_hash to ld_stab is devoted to the hash table.
Each entry in the hash table is eight bytes. The first four
bytes are a symbol index into the dynamic symbols. The second
four bytes are the index of the next hash table entry in the
bucket. The ld_buckets field gives the number of buckets, say B.
The first B entries in the hash table each start a bucket which
is chained through the second four bytes of each entry. A value
of zero ends the chain.
The hash function is simply
h = 0;
while (*string != '\0')
h = (h << 1) + *string++;
h &= 0x7fffffff;
To look up a symbol, compute the hash value of the name. Take
the modulos of hash value and the number of buckets. Start at
that entry in the hash table. See if the symbol (from the first
four bytes of the hash table entry) has the name you are looking
for. If not, use the chain field (the second four bytes of the
hash table entry) to move on to the next entry in this bucket.
If the chain field is zero you have reached the end of the
bucket, and the symbol is not in the hash table. */
unsigned long ld_hash;
/* The address of the symbol table. This is a list of
external_nlist structures. The string indices are relative to
the ld_symbols field. I think the only way to determine the
number of symbols is to assume that all the bytes between ld_stab
and ld_symbols are external_nlist structures. */
unsigned long ld_stab;
/* I don't know what this is for. It seems to always be zero. */
unsigned long ld_stab_hash;
/* The number of buckets in the hash table. */
unsigned long ld_buckets;
/* The address of the symbol string table. The first string in this
string table need not be the empty string. */
unsigned long ld_symbols;
/* The size in bytes of the symbol string table. */
unsigned long ld_symb_size;
/* The size in bytes of the text segment. */
unsigned long ld_text;
/* The size in bytes of the procedure linkage table. */
unsigned long ld_plt_sz;
};
/* The external form of the structure. */
struct external_sun4_dynamic_link
{
bfd_byte ld_loaded[4];
bfd_byte ld_need[4];
bfd_byte ld_rules[4];
bfd_byte ld_got[4];
bfd_byte ld_plt[4];
bfd_byte ld_rel[4];
bfd_byte ld_hash[4];
bfd_byte ld_stab[4];
bfd_byte ld_stab_hash[4];
bfd_byte ld_buckets[4];
bfd_byte ld_symbols[4];
bfd_byte ld_symb_size[4];
bfd_byte ld_text[4];
bfd_byte ld_plt_sz[4];
};

View File

@ -0,0 +1,117 @@
/* SPARC ELF support for BFD.
Copyright (C) 1996, 1997 Free Software Foundation, Inc.
By Doug Evans, Cygnus Support, <dje@cygnus.com>.
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. */
#ifndef _ELF_SPARC_H
#define _ELF_SPARC_H
/* Processor specific flags for the ELF header e_flags field. */
/* These are defined by Sun. */
#define EF_SPARC_32PLUS_MASK 0xffff00 /* bits indicating V8+ type */
#define EF_SPARC_32PLUS 0x000100 /* generic V8+ features */
#define EF_SPARC_SUN_US1 0x000200 /* Sun UltraSPARC1 extensions */
#define EF_SPARC_HAL_R1 0x000400 /* HAL R1 extensions */
/* This name is used in the V9 ABI. */
#define EF_SPARC_EXT_MASK 0xffff00 /* reserved for vendor extensions */
/* V9 memory models */
#define EF_SPARCV9_MM 0x3 /* memory model mask */
#define EF_SPARCV9_TSO 0x0 /* total store ordering */
#define EF_SPARCV9_PSO 0x1 /* partial store ordering */
#define EF_SPARCV9_RMO 0x2 /* relaxed store ordering */
/* Section indices. */
#define SHN_BEFORE 0xff00 /* used with SHF_ORDERED */
#define SHN_AFTER 0xff01 /* used with SHF_ORDERED */
/* Section flags. */
#define SHF_EXCLUDE 0x80000000 /* exclude from linking */
#define SHF_ORDERED 0x40000000 /* treat sh_link,sh_info specially */
/* Symbol types. */
#define STT_REGISTER 13 /* global reg reserved to app. */
/* Relocation types. */
enum elf_sparc_reloc_type {
R_SPARC_NONE = 0,
R_SPARC_8, R_SPARC_16, R_SPARC_32,
R_SPARC_DISP8, R_SPARC_DISP16, R_SPARC_DISP32,
R_SPARC_WDISP30, R_SPARC_WDISP22,
R_SPARC_HI22, R_SPARC_22,
R_SPARC_13, R_SPARC_LO10,
R_SPARC_GOT10, R_SPARC_GOT13, R_SPARC_GOT22,
R_SPARC_PC10, R_SPARC_PC22,
R_SPARC_WPLT30,
R_SPARC_COPY,
R_SPARC_GLOB_DAT, R_SPARC_JMP_SLOT,
R_SPARC_RELATIVE,
R_SPARC_UA32,
/* ??? These 6 relocs are new but not currently used. For binary
compatility in the sparc64-elf toolchain, we leave them out.
A non-binary upward compatible change is expected for sparc64-elf. */
#ifndef SPARC64_OLD_RELOCS
/* ??? New relocs on the UltraSPARC. Not sure what they're for yet. */
R_SPARC_PLT32, R_SPARC_HIPLT22, R_SPARC_LOPLT10,
R_SPARC_PCPLT32, R_SPARC_PCPLT22, R_SPARC_PCPLT10,
#endif
/* v9 relocs */
R_SPARC_10, R_SPARC_11, R_SPARC_64,
R_SPARC_OLO10, R_SPARC_HH22, R_SPARC_HM10, R_SPARC_LM22,
R_SPARC_PC_HH22, R_SPARC_PC_HM10, R_SPARC_PC_LM22,
R_SPARC_WDISP16, R_SPARC_WDISP19,
R_SPARC_UNUSED_42,
R_SPARC_7, R_SPARC_5, R_SPARC_6,
R_SPARC_DISP64, R_SPARC_PLT64,
R_SPARC_HIX22, R_SPARC_LOX10,
R_SPARC_H44, R_SPARC_M44, R_SPARC_L44,
R_SPARC_REGISTER,
R_SPARC_UA64, R_SPARC_UA16,
R_SPARC_max
};
/* Relocation macros. */
#define ELF64_R_TYPE_DATA(info) (((bfd_vma) (info) << 32) >> 40)
#define ELF64_R_TYPE_ID(info) (((bfd_vma) (info) << 56) >> 56)
#define ELF64_R_TYPE_INFO(data, type) (((bfd_vma) (data) << 8) \
+ (bfd_vma) (type))
#define DT_SPARC_REGISTER 0x70000001
/*
* FIXME: NOT ABI -- GET RID OF THIS
* Defines the format used by the .plt. Currently defined values are
* 0 -- reserved to SI
* 1 -- absolute address in .got.plt
* 2 -- got-relative address in .got.plt
*/
#define DT_SPARC_PLTFMT 0x70000001
#endif /* _ELF_SPARC_H */

View File

@ -0,0 +1,240 @@
/* Definitions for opcode table for the sparc.
Copyright (C) 1989, 91, 92, 93, 94, 95, 96, 1997
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler, GDB, the GNU debugger, and
the GNU Binutils.
GAS/GDB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GAS/GDB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GAS or GDB; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include <ansidecl.h>
/* The SPARC opcode table (and other related data) is defined in
the opcodes library in sparc-opc.c. If you change anything here, make
sure you fix up that file, and vice versa. */
/* FIXME-someday: perhaps the ,a's and such should be embedded in the
instruction's name rather than the args. This would make gas faster, pinsn
slower, but would mess up some macros a bit. xoxorich. */
/* List of instruction sets variations.
These values are such that each element is either a superset of a
preceding each one or they conflict in which case SPARC_OPCODE_CONFLICT_P
returns non-zero.
The values are indices into `sparc_opcode_archs' defined in sparc-opc.c.
Don't change this without updating sparc-opc.c. */
enum sparc_opcode_arch_val {
SPARC_OPCODE_ARCH_V6 = 0,
SPARC_OPCODE_ARCH_V7,
SPARC_OPCODE_ARCH_V8,
SPARC_OPCODE_ARCH_SPARCLET,
SPARC_OPCODE_ARCH_SPARCLITE,
/* v9 variants must appear last */
SPARC_OPCODE_ARCH_V9,
SPARC_OPCODE_ARCH_V9A, /* v9 with ultrasparc additions */
SPARC_OPCODE_ARCH_BAD /* error return from sparc_opcode_lookup_arch */
};
/* The highest architecture in the table. */
#define SPARC_OPCODE_ARCH_MAX (SPARC_OPCODE_ARCH_BAD - 1)
/* Given an enum sparc_opcode_arch_val, return the bitmask to use in
insn encoding/decoding. */
#define SPARC_OPCODE_ARCH_MASK(arch) (1 << (arch))
/* Given a valid sparc_opcode_arch_val, return non-zero if it's v9. */
#define SPARC_OPCODE_ARCH_V9_P(arch) ((arch) >= SPARC_OPCODE_ARCH_V9)
/* Table of cpu variants. */
struct sparc_opcode_arch {
const char *name;
/* Mask of sparc_opcode_arch_val's supported.
EG: For v7 this would be
(SPARC_OPCODE_ARCH_MASK (..._V6) | SPARC_OPCODE_ARCH_MASK (..._V7)).
These are short's because sparc_opcode.architecture is. */
short supported;
};
extern const struct sparc_opcode_arch sparc_opcode_archs[];
/* Given architecture name, look up it's sparc_opcode_arch_val value. */
extern enum sparc_opcode_arch_val sparc_opcode_lookup_arch
PARAMS ((const char *));
/* Return the bitmask of supported architectures for ARCH. */
#define SPARC_OPCODE_SUPPORTED(ARCH) (sparc_opcode_archs[ARCH].supported)
/* Non-zero if ARCH1 conflicts with ARCH2.
IE: ARCH1 as a supported bit set that ARCH2 doesn't, and vice versa. */
#define SPARC_OPCODE_CONFLICT_P(ARCH1, ARCH2) \
(((SPARC_OPCODE_SUPPORTED (ARCH1) & SPARC_OPCODE_SUPPORTED (ARCH2)) \
!= SPARC_OPCODE_SUPPORTED (ARCH1)) \
&& ((SPARC_OPCODE_SUPPORTED (ARCH1) & SPARC_OPCODE_SUPPORTED (ARCH2)) \
!= SPARC_OPCODE_SUPPORTED (ARCH2)))
/* Structure of an opcode table entry. */
struct sparc_opcode {
const char *name;
unsigned long match; /* Bits that must be set. */
unsigned long lose; /* Bits that must not be set. */
const char *args;
/* This was called "delayed" in versions before the flags. */
char flags;
short architecture; /* Bitmask of sparc_opcode_arch_val's. */
};
#define F_DELAYED 1 /* Delayed branch */
#define F_ALIAS 2 /* Alias for a "real" instruction */
#define F_UNBR 4 /* Unconditional branch */
#define F_CONDBR 8 /* Conditional branch */
#define F_JSR 16 /* Subroutine call */
#define F_FLOAT 32 /* Floating point instruction (not a branch) */
#define F_FBR 64 /* Floating point branch */
/* FIXME: Add F_ANACHRONISTIC flag for v9. */
/*
All sparc opcodes are 32 bits, except for the `set' instruction (really a
macro), which is 64 bits. It is handled as a special case.
The match component is a mask saying which bits must match a particular
opcode in order for an instruction to be an instance of that opcode.
The args component is a string containing one character for each operand of the
instruction.
Kinds of operands:
# Number used by optimizer. It is ignored.
1 rs1 register.
2 rs2 register.
d rd register.
e frs1 floating point register.
v frs1 floating point register (double/even).
V frs1 floating point register (quad/multiple of 4).
f frs2 floating point register.
B frs2 floating point register (double/even).
R frs2 floating point register (quad/multiple of 4).
g frsd floating point register.
H frsd floating point register (double/even).
J frsd floating point register (quad/multiple of 4).
b crs1 coprocessor register
c crs2 coprocessor register
D crsd coprocessor register
m alternate space register (asr) in rd
M alternate space register (asr) in rs1
h 22 high bits.
X 5 bit unsigned immediate
Y 6 bit unsigned immediate
K MEMBAR mask (7 bits). (v9)
j 10 bit Immediate. (v9)
I 11 bit Immediate. (v9)
i 13 bit Immediate.
n 22 bit immediate.
k 2+14 bit PC relative immediate. (v9)
G 19 bit PC relative immediate. (v9)
l 22 bit PC relative immediate.
L 30 bit PC relative immediate.
a Annul. The annul bit is set.
A Alternate address space. Stored as 8 bits.
C Coprocessor state register.
F floating point state register.
p Processor state register.
N Branch predict clear ",pn" (v9)
T Branch predict set ",pt" (v9)
z %icc. (v9)
Z %xcc. (v9)
q Floating point queue.
r Single register that is both rs1 and rd.
O Single register that is both rs2 and rd.
Q Coprocessor queue.
S Special case.
t Trap base register.
w Window invalid mask register.
y Y register.
u sparclet coprocessor registers in rd position
U sparclet coprocessor registers in rs1 position
E %ccr. (v9)
s %fprs. (v9)
P %pc. (v9)
W %tick. (v9)
o %asi. (v9)
6 %fcc0. (v9)
7 %fcc1. (v9)
8 %fcc2. (v9)
9 %fcc3. (v9)
! Privileged Register in rd (v9)
? Privileged Register in rs1 (v9)
* Prefetch function constant. (v9)
x OPF field (v9 impdep).
0 32/64 bit immediate for set or setx (v9) insns
_ Ancillary state register in rd (v9a)
/ Ancillary state register in rs1 (v9a)
The following chars are unused: (note: ,[] are used as punctuation)
[345]
*/
#define OP2(x) (((x)&0x7) << 22) /* op2 field of format2 insns */
#define OP3(x) (((x)&0x3f) << 19) /* op3 field of format3 insns */
#define OP(x) ((unsigned)((x)&0x3) << 30) /* op field of all insns */
#define OPF(x) (((x)&0x1ff) << 5) /* opf field of float insns */
#define OPF_LOW5(x) OPF((x)&0x1f) /* v9 */
#define F3F(x, y, z) (OP(x) | OP3(y) | OPF(z)) /* format3 float insns */
#define F3I(x) (((x)&0x1) << 13) /* immediate field of format 3 insns */
#define F2(x, y) (OP(x) | OP2(y)) /* format 2 insns */
#define F3(x, y, z) (OP(x) | OP3(y) | F3I(z)) /* format3 insns */
#define F1(x) (OP(x))
#define DISP30(x) ((x)&0x3fffffff)
#define ASI(x) (((x)&0xff) << 5) /* asi field of format3 insns */
#define RS2(x) ((x)&0x1f) /* rs2 field */
#define SIMM13(x) ((x)&0x1fff) /* simm13 field */
#define RD(x) (((x)&0x1f) << 25) /* destination register field */
#define RS1(x) (((x)&0x1f) << 14) /* rs1 field */
#define ASI_RS2(x) (SIMM13(x))
#define MEMBAR(x) ((x)&0x7f)
#define SLCPOP(x) (((x)&0x7f) << 6) /* sparclet cpop */
#define ANNUL (1<<29)
#define BPRED (1<<19) /* v9 */
#define IMMED F3I(1)
#define RD_G0 RD(~0)
#define RS1_G0 RS1(~0)
#define RS2_G0 RS2(~0)
extern const struct sparc_opcode sparc_opcodes[];
extern const int sparc_num_opcodes;
extern int sparc_encode_asi PARAMS ((const char *));
extern const char *sparc_decode_asi PARAMS ((int));
extern int sparc_encode_membar PARAMS ((const char *));
extern const char *sparc_decode_membar PARAMS ((int));
extern int sparc_encode_prefetch PARAMS ((const char *));
extern const char *sparc_decode_prefetch PARAMS ((int));
extern int sparc_encode_sparclet_cpreg PARAMS ((const char *));
extern const char *sparc_decode_sparclet_cpreg PARAMS ((int));
/*
* Local Variables:
* fill-column: 131
* comment-column: 0
* End:
*/
/* end of sparc.h */

View File

@ -0,0 +1,10 @@
SCRIPT_NAME=elf
OUTPUT_FORMAT="elf32-sparc"
TEXT_START_ADDR=0x10000
MAXPAGESIZE=0x10000
NONPAGED_TEXT_START_ADDR=0x10000
ARCH=sparc
MACHINE=
TEMPLATE_NAME=elf32
DATA_PLT=
GENERATE_SHLIB_SCRIPT=yes

View File

@ -0,0 +1,12 @@
SCRIPT_NAME=elf
ELFSIZE=64
TEMPLATE_NAME=elf32
OUTPUT_FORMAT="elf64-sparc"
TEXT_START_ADDR=0x100000
MAXPAGESIZE=0x100000
NONPAGED_TEXT_START_ADDR=0x100000
ARCH="sparc:v9"
MACHINE=
DATA_PLT=
GENERATE_SHLIB_SCRIPT=yes
NOP=0x01000000

View File

@ -0,0 +1,961 @@
/* Print SPARC instructions.
Copyright (C) 1989, 91-94, 1995, 1996, 1997 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 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 "ansidecl.h"
#include "sysdep.h"
#include "opcode/sparc.h"
#include "dis-asm.h"
#include "libiberty.h"
/* Bitmask of v9 architectures. */
#define MASK_V9 ((1 << SPARC_OPCODE_ARCH_V9) \
| (1 << SPARC_OPCODE_ARCH_V9A))
/* 1 if INSN is for v9 only. */
#define V9_ONLY_P(insn) (! ((insn)->architecture & ~MASK_V9))
/* 1 if INSN is for v9. */
#define V9_P(insn) (((insn)->architecture & MASK_V9) != 0)
/* The sorted opcode table. */
static const struct sparc_opcode **sorted_opcodes;
/* For faster lookup, after insns are sorted they are hashed. */
/* ??? I think there is room for even more improvement. */
#define HASH_SIZE 256
/* It is important that we only look at insn code bits as that is how the
opcode table is hashed. OPCODE_BITS is a table of valid bits for each
of the main types (0,1,2,3). */
static int opcode_bits[4] = { 0x01c00000, 0x0, 0x01f80000, 0x01f80000 };
#define HASH_INSN(INSN) \
((((INSN) >> 24) & 0xc0) | (((INSN) & opcode_bits[((INSN) >> 30) & 3]) >> 19))
struct opcode_hash {
struct opcode_hash *next;
const struct sparc_opcode *opcode;
};
static struct opcode_hash *opcode_hash_table[HASH_SIZE];
static void build_hash_table
PARAMS ((const struct sparc_opcode **, struct opcode_hash **, int));
static int is_delayed_branch PARAMS ((unsigned long));
static int compare_opcodes PARAMS ((const PTR, const PTR));
static int compute_arch_mask PARAMS ((unsigned long));
/* Sign-extend a value which is N bits long. */
#define SEX(value, bits) \
((((int)(value)) << ((8 * sizeof (int)) - bits)) \
>> ((8 * sizeof (int)) - bits) )
static char *reg_names[] =
{ "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
"o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
"l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
"i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7",
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
"f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
"f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
"f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
"f32", "f33", "f34", "f35", "f36", "f37", "f38", "f39",
"f40", "f41", "f42", "f43", "f44", "f45", "f46", "f47",
"f48", "f49", "f50", "f51", "f52", "f53", "f54", "f55",
"f56", "f57", "f58", "f59", "f60", "f61", "f62", "f63",
/* psr, wim, tbr, fpsr, cpsr are v8 only. */
"y", "psr", "wim", "tbr", "pc", "npc", "fpsr", "cpsr"
};
#define freg_names (&reg_names[4 * 8])
/* These are ordered according to there register number in
rdpr and wrpr insns. */
static char *v9_priv_reg_names[] =
{
"tpc", "tnpc", "tstate", "tt", "tick", "tba", "pstate", "tl",
"pil", "cwp", "cansave", "canrestore", "cleanwin", "otherwin",
"wstate", "fq"
/* "ver" - special cased */
};
/* These are ordered according to there register number in
rd and wr insns (-16). */
static char *v9a_asr_reg_names[] =
{
"pcr", "pic", "dcr", "gsr", "set_softint", "clear_softint",
"softint", "tick_cmpr"
};
/* Macros used to extract instruction fields. Not all fields have
macros defined here, only those which are actually used. */
#define X_RD(i) (((i) >> 25) & 0x1f)
#define X_RS1(i) (((i) >> 14) & 0x1f)
#define X_LDST_I(i) (((i) >> 13) & 1)
#define X_ASI(i) (((i) >> 5) & 0xff)
#define X_RS2(i) (((i) >> 0) & 0x1f)
#define X_IMM(i,n) (((i) >> 0) & ((1 << (n)) - 1))
#define X_SIMM(i,n) SEX (X_IMM ((i), (n)), (n))
#define X_DISP22(i) (((i) >> 0) & 0x3fffff)
#define X_IMM22(i) X_DISP22 (i)
#define X_DISP30(i) (((i) >> 0) & 0x3fffffff)
/* These are for v9. */
#define X_DISP16(i) (((((i) >> 20) & 3) << 14) | (((i) >> 0) & 0x3fff))
#define X_DISP19(i) (((i) >> 0) & 0x7ffff)
#define X_MEMBAR(i) ((i) & 0x7f)
/* Here is the union which was used to extract instruction fields
before the shift and mask macros were written.
union sparc_insn
{
unsigned long int code;
struct
{
unsigned int anop:2;
#define op ldst.anop
unsigned int anrd:5;
#define rd ldst.anrd
unsigned int op3:6;
unsigned int anrs1:5;
#define rs1 ldst.anrs1
unsigned int i:1;
unsigned int anasi:8;
#define asi ldst.anasi
unsigned int anrs2:5;
#define rs2 ldst.anrs2
#define shcnt rs2
} ldst;
struct
{
unsigned int anop:2, anrd:5, op3:6, anrs1:5, i:1;
unsigned int IMM13:13;
#define imm13 IMM13.IMM13
} IMM13;
struct
{
unsigned int anop:2;
unsigned int a:1;
unsigned int cond:4;
unsigned int op2:3;
unsigned int DISP22:22;
#define disp22 branch.DISP22
#define imm22 disp22
} branch;
struct
{
unsigned int anop:2;
unsigned int a:1;
unsigned int z:1;
unsigned int rcond:3;
unsigned int op2:3;
unsigned int DISP16HI:2;
unsigned int p:1;
unsigned int _rs1:5;
unsigned int DISP16LO:14;
} branch16;
struct
{
unsigned int anop:2;
unsigned int adisp30:30;
#define disp30 call.adisp30
} call;
};
*/
/* Nonzero if INSN is the opcode for a delayed branch. */
static int
is_delayed_branch (insn)
unsigned long insn;
{
struct opcode_hash *op;
for (op = opcode_hash_table[HASH_INSN (insn)]; op; op = op->next)
{
CONST struct sparc_opcode *opcode = op->opcode;
if ((opcode->match & insn) == opcode->match
&& (opcode->lose & insn) == 0)
return (opcode->flags & F_DELAYED);
}
return 0;
}
/* extern void qsort (); */
/* Records current mask of SPARC_OPCODE_ARCH_FOO values, used to pass value
to compare_opcodes. */
static unsigned int current_arch_mask;
/* Print one instruction from MEMADDR on INFO->STREAM.
We suffix the instruction with a comment that gives the absolute
address involved, as well as its symbolic form, if the instruction
is preceded by a findable `sethi' and it either adds an immediate
displacement to that register, or it is an `add' or `or' instruction
on that register. */
int
print_insn_sparc (memaddr, info)
bfd_vma memaddr;
disassemble_info *info;
{
FILE *stream = info->stream;
bfd_byte buffer[4];
unsigned long insn;
register struct opcode_hash *op;
/* Nonzero of opcode table has been initialized. */
static int opcodes_initialized = 0;
/* bfd mach number of last call. */
static unsigned long current_mach = 0;
if (!opcodes_initialized
|| info->mach != current_mach)
{
int i;
current_arch_mask = compute_arch_mask (info->mach);
if (!opcodes_initialized)
sorted_opcodes = (const struct sparc_opcode **)
xmalloc (sparc_num_opcodes * sizeof (struct sparc_opcode *));
/* Reset the sorted table so we can resort it. */
for (i = 0; i < sparc_num_opcodes; ++i)
sorted_opcodes[i] = &sparc_opcodes[i];
qsort ((char *) sorted_opcodes, sparc_num_opcodes,
sizeof (sorted_opcodes[0]), compare_opcodes);
build_hash_table (sorted_opcodes, opcode_hash_table, sparc_num_opcodes);
current_mach = info->mach;
opcodes_initialized = 1;
}
{
int status =
(*info->read_memory_func) (memaddr, buffer, sizeof (buffer), info);
if (status != 0)
{
(*info->memory_error_func) (status, memaddr, info);
return -1;
}
}
if (info->endian == BFD_ENDIAN_BIG)
insn = bfd_getb32 (buffer);
else
insn = bfd_getl32 (buffer);
info->insn_info_valid = 1; /* We do return this info */
info->insn_type = dis_nonbranch; /* Assume non branch insn */
info->branch_delay_insns = 0; /* Assume no delay */
info->target = 0; /* Assume no target known */
for (op = opcode_hash_table[HASH_INSN (insn)]; op; op = op->next)
{
CONST struct sparc_opcode *opcode = op->opcode;
/* If the insn isn't supported by the current architecture, skip it. */
if (! (opcode->architecture & current_arch_mask))
continue;
if ((opcode->match & insn) == opcode->match
&& (opcode->lose & insn) == 0)
{
/* Nonzero means that we have found an instruction which has
the effect of adding or or'ing the imm13 field to rs1. */
int imm_added_to_rs1 = 0;
/* Nonzero means that we have found a plus sign in the args
field of the opcode table. */
int found_plus = 0;
/* Nonzero means we have an annulled branch. */
int is_annulled = 0;
/* Do we have an `add' or `or' instruction combining an
immediate with rs1? */
if (opcode->match == 0x80102000 || opcode->match == 0x80002000)
/* (or) (add) */
imm_added_to_rs1 = 1;
if (X_RS1 (insn) != X_RD (insn)
&& strchr (opcode->args, 'r') != 0)
/* Can't do simple format if source and dest are different. */
continue;
if (X_RS2 (insn) != X_RD (insn)
&& strchr (opcode->args, 'O') != 0)
/* Can't do simple format if source and dest are different. */
continue;
(*info->fprintf_func) (stream, opcode->name);
{
register CONST char *s;
if (opcode->args[0] != ',')
(*info->fprintf_func) (stream, " ");
for (s = opcode->args; *s != '\0'; ++s)
{
while (*s == ',')
{
(*info->fprintf_func) (stream, ",");
++s;
switch (*s) {
case 'a':
(*info->fprintf_func) (stream, "a");
is_annulled = 1;
++s;
continue;
case 'N':
(*info->fprintf_func) (stream, "pn");
++s;
continue;
case 'T':
(*info->fprintf_func) (stream, "pt");
++s;
continue;
default:
break;
} /* switch on arg */
} /* while there are comma started args */
(*info->fprintf_func) (stream, " ");
switch (*s)
{
case '+':
found_plus = 1;
/* note fall-through */
default:
(*info->fprintf_func) (stream, "%c", *s);
break;
case '#':
(*info->fprintf_func) (stream, "0");
break;
#define reg(n) (*info->fprintf_func) (stream, "%%%s", reg_names[n])
case '1':
case 'r':
reg (X_RS1 (insn));
break;
case '2':
case 'O':
reg (X_RS2 (insn));
break;
case 'd':
reg (X_RD (insn));
break;
#undef reg
#define freg(n) (*info->fprintf_func) (stream, "%%%s", freg_names[n])
#define fregx(n) (*info->fprintf_func) (stream, "%%%s", freg_names[((n) & ~1) | (((n) & 1) << 5)])
case 'e':
freg (X_RS1 (insn));
break;
case 'v': /* double/even */
case 'V': /* quad/multiple of 4 */
fregx (X_RS1 (insn));
break;
case 'f':
freg (X_RS2 (insn));
break;
case 'B': /* double/even */
case 'R': /* quad/multiple of 4 */
fregx (X_RS2 (insn));
break;
case 'g':
freg (X_RD (insn));
break;
case 'H': /* double/even */
case 'J': /* quad/multiple of 4 */
fregx (X_RD (insn));
break;
#undef freg
#undef fregx
#define creg(n) (*info->fprintf_func) (stream, "%%c%u", (unsigned int) (n))
case 'b':
creg (X_RS1 (insn));
break;
case 'c':
creg (X_RS2 (insn));
break;
case 'D':
creg (X_RD (insn));
break;
#undef creg
case 'h':
(*info->fprintf_func) (stream, "%%hi(%#x)",
(0xFFFFFFFF
& ((int) X_IMM22 (insn) << 10)));
break;
case 'i': /* 13 bit immediate */
case 'I': /* 11 bit immediate */
case 'j': /* 10 bit immediate */
{
int imm;
if (*s == 'i')
imm = X_SIMM (insn, 13);
else if (*s == 'I')
imm = X_SIMM (insn, 11);
else
imm = X_SIMM (insn, 10);
/* Check to see whether we have a 1+i, and take
note of that fact.
Note: because of the way we sort the table,
we will be matching 1+i rather than i+1,
so it is OK to assume that i is after +,
not before it. */
if (found_plus)
imm_added_to_rs1 = 1;
if (imm <= 9)
(*info->fprintf_func) (stream, "%d", imm);
else
(*info->fprintf_func) (stream, "%#x", imm);
}
break;
case 'X': /* 5 bit unsigned immediate */
case 'Y': /* 6 bit unsigned immediate */
{
int imm = X_IMM (insn, *s == 'X' ? 5 : 6);
if (imm <= 9)
(info->fprintf_func) (stream, "%d", imm);
else
(info->fprintf_func) (stream, "%#x", (unsigned) imm);
}
break;
case 'K':
{
int mask = X_MEMBAR (insn);
int bit = 0x40, printed_one = 0;
const char *name;
if (mask == 0)
(info->fprintf_func) (stream, "0");
else
while (bit)
{
if (mask & bit)
{
if (printed_one)
(info->fprintf_func) (stream, "|");
name = sparc_decode_membar (bit);
(info->fprintf_func) (stream, "%s", name);
printed_one = 1;
}
bit >>= 1;
}
break;
}
case 'k':
info->target = memaddr + SEX (X_DISP16 (insn), 16) * 4;
(*info->print_address_func) (info->target, info);
break;
case 'G':
info->target = memaddr + SEX (X_DISP19 (insn), 19) * 4;
(*info->print_address_func) (info->target, info);
break;
case '6':
case '7':
case '8':
case '9':
(*info->fprintf_func) (stream, "%%fcc%c", *s - '6' + '0');
break;
case 'z':
(*info->fprintf_func) (stream, "%%icc");
break;
case 'Z':
(*info->fprintf_func) (stream, "%%xcc");
break;
case 'E':
(*info->fprintf_func) (stream, "%%ccr");
break;
case 's':
(*info->fprintf_func) (stream, "%%fprs");
break;
case 'o':
(*info->fprintf_func) (stream, "%%asi");
break;
case 'W':
(*info->fprintf_func) (stream, "%%tick");
break;
case 'P':
(*info->fprintf_func) (stream, "%%pc");
break;
case '?':
if (X_RS1 (insn) == 31)
(*info->fprintf_func) (stream, "%%ver");
else if ((unsigned) X_RS1 (insn) < 16)
(*info->fprintf_func) (stream, "%%%s",
v9_priv_reg_names[X_RS1 (insn)]);
else
(*info->fprintf_func) (stream, "%%reserved");
break;
case '!':
if ((unsigned) X_RD (insn) < 15)
(*info->fprintf_func) (stream, "%%%s",
v9_priv_reg_names[X_RD (insn)]);
else
(*info->fprintf_func) (stream, "%%reserved");
break;
case '/':
if (X_RS1 (insn) < 16 || X_RS1 (insn) > 23)
(*info->fprintf_func) (stream, "%%reserved");
else
(*info->fprintf_func) (stream, "%%%s",
v9a_asr_reg_names[X_RS1 (insn)-16]);
break;
case '_':
if (X_RD (insn) < 16 || X_RD (insn) > 23)
(*info->fprintf_func) (stream, "%%reserved");
else
(*info->fprintf_func) (stream, "%%%s",
v9a_asr_reg_names[X_RD (insn)-16]);
break;
case '*':
{
const char *name = sparc_decode_prefetch (X_RD (insn));
if (name)
(*info->fprintf_func) (stream, "%s", name);
else
(*info->fprintf_func) (stream, "%d", X_RD (insn));
break;
}
case 'M':
(*info->fprintf_func) (stream, "%%asr%d", X_RS1 (insn));
break;
case 'm':
(*info->fprintf_func) (stream, "%%asr%d", X_RD (insn));
break;
case 'L':
info->target = memaddr + SEX (X_DISP30 (insn), 30) * 4;
(*info->print_address_func) (info->target, info);
break;
case 'n':
(*info->fprintf_func)
(stream, "%#x", SEX (X_DISP22 (insn), 22));
break;
case 'l':
info->target = memaddr + SEX (X_DISP22 (insn), 22) * 4;
(*info->print_address_func) (info->target, info);
break;
case 'A':
{
const char *name = sparc_decode_asi (X_ASI (insn));
if (name)
(*info->fprintf_func) (stream, "%s", name);
else
(*info->fprintf_func) (stream, "(%d)", X_ASI (insn));
break;
}
case 'C':
(*info->fprintf_func) (stream, "%%csr");
break;
case 'F':
(*info->fprintf_func) (stream, "%%fsr");
break;
case 'p':
(*info->fprintf_func) (stream, "%%psr");
break;
case 'q':
(*info->fprintf_func) (stream, "%%fq");
break;
case 'Q':
(*info->fprintf_func) (stream, "%%cq");
break;
case 't':
(*info->fprintf_func) (stream, "%%tbr");
break;
case 'w':
(*info->fprintf_func) (stream, "%%wim");
break;
case 'x':
(*info->fprintf_func) (stream, "%d",
((X_LDST_I (insn) << 8)
+ X_ASI (insn)));
break;
case 'y':
(*info->fprintf_func) (stream, "%%y");
break;
case 'u':
case 'U':
{
int val = *s == 'U' ? X_RS1 (insn) : X_RD (insn);
const char *name = sparc_decode_sparclet_cpreg (val);
if (name)
(*info->fprintf_func) (stream, "%s", name);
else
(*info->fprintf_func) (stream, "%%cpreg(%d)", val);
break;
}
}
}
}
/* If we are adding or or'ing something to rs1, then
check to see whether the previous instruction was
a sethi to the same register as in the sethi.
If so, attempt to print the result of the add or
or (in this context add and or do the same thing)
and its symbolic value. */
if (imm_added_to_rs1)
{
unsigned long prev_insn;
int errcode;
errcode =
(*info->read_memory_func)
(memaddr - 4, buffer, sizeof (buffer), info);
if (info->endian == BFD_ENDIAN_BIG)
prev_insn = bfd_getb32 (buffer);
else
prev_insn = bfd_getl32 (buffer);
if (errcode == 0)
{
/* If it is a delayed branch, we need to look at the
instruction before the delayed branch. This handles
sequences such as
sethi %o1, %hi(_foo), %o1
call _printf
or %o1, %lo(_foo), %o1
*/
if (is_delayed_branch (prev_insn))
{
errcode = (*info->read_memory_func)
(memaddr - 8, buffer, sizeof (buffer), info);
if (info->endian == BFD_ENDIAN_BIG)
prev_insn = bfd_getb32 (buffer);
else
prev_insn = bfd_getl32 (buffer);
}
}
/* If there was a problem reading memory, then assume
the previous instruction was not sethi. */
if (errcode == 0)
{
/* Is it sethi to the same register? */
if ((prev_insn & 0xc1c00000) == 0x01000000
&& X_RD (prev_insn) == X_RS1 (insn))
{
(*info->fprintf_func) (stream, "\t! ");
info->target =
(0xFFFFFFFF & (int) X_IMM22 (prev_insn) << 10)
| X_SIMM (insn, 13);
(*info->print_address_func) (info->target, info);
info->insn_type = dis_dref;
info->data_size = 4; /* FIXME!!! */
}
}
}
if (opcode->flags & (F_UNBR|F_CONDBR|F_JSR))
{
/* FIXME -- check is_annulled flag */
if (opcode->flags & F_UNBR)
info->insn_type = dis_branch;
if (opcode->flags & F_CONDBR)
info->insn_type = dis_condbranch;
if (opcode->flags & F_JSR)
info->insn_type = dis_jsr;
if (opcode->flags & F_DELAYED)
info->branch_delay_insns = 1;
}
return sizeof (buffer);
}
}
info->insn_type = dis_noninsn; /* Mark as non-valid instruction */
(*info->fprintf_func) (stream, "unknown");
return sizeof (buffer);
}
/* Given BFD mach number, return a mask of SPARC_OPCODE_ARCH_FOO values. */
static int
compute_arch_mask (mach)
unsigned long mach;
{
switch (mach)
{
case 0 :
case bfd_mach_sparc :
return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V8);
case bfd_mach_sparc_sparclet :
return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLET);
case bfd_mach_sparc_sparclite :
/* sparclites insns are recognized by default (because that's how
they've always been treated, for better or worse). Kludge this by
indicating generic v8 is also selected. */
return (SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLITE)
| SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V8));
case bfd_mach_sparc_v8plus :
case bfd_mach_sparc_v9 :
return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9);
case bfd_mach_sparc_v8plusa :
case bfd_mach_sparc_v9a :
return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9A);
}
abort ();
}
/* Compare opcodes A and B. */
static int
compare_opcodes (a, b)
const PTR a;
const PTR b;
{
struct sparc_opcode *op0 = * (struct sparc_opcode **) a;
struct sparc_opcode *op1 = * (struct sparc_opcode **) b;
unsigned long int match0 = op0->match, match1 = op1->match;
unsigned long int lose0 = op0->lose, lose1 = op1->lose;
register unsigned int i;
/* If one (and only one) insn isn't supported by the current architecture,
prefer the one that is. If neither are supported, but they're both for
the same architecture, continue processing. Otherwise (both unsupported
and for different architectures), prefer lower numbered arch's (fudged
by comparing the bitmasks). */
if (op0->architecture & current_arch_mask)
{
if (! (op1->architecture & current_arch_mask))
return -1;
}
else
{
if (op1->architecture & current_arch_mask)
return 1;
else if (op0->architecture != op1->architecture)
return op0->architecture - op1->architecture;
}
/* If a bit is set in both match and lose, there is something
wrong with the opcode table. */
if (match0 & lose0)
{
fprintf (stderr, "Internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n",
op0->name, match0, lose0);
op0->lose &= ~op0->match;
lose0 = op0->lose;
}
if (match1 & lose1)
{
fprintf (stderr, "Internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n",
op1->name, match1, lose1);
op1->lose &= ~op1->match;
lose1 = op1->lose;
}
/* Because the bits that are variable in one opcode are constant in
another, it is important to order the opcodes in the right order. */
for (i = 0; i < 32; ++i)
{
unsigned long int x = 1 << i;
int x0 = (match0 & x) != 0;
int x1 = (match1 & x) != 0;
if (x0 != x1)
return x1 - x0;
}
for (i = 0; i < 32; ++i)
{
unsigned long int x = 1 << i;
int x0 = (lose0 & x) != 0;
int x1 = (lose1 & x) != 0;
if (x0 != x1)
return x1 - x0;
}
/* They are functionally equal. So as long as the opcode table is
valid, we can put whichever one first we want, on aesthetic grounds. */
/* Our first aesthetic ground is that aliases defer to real insns. */
{
int alias_diff = (op0->flags & F_ALIAS) - (op1->flags & F_ALIAS);
if (alias_diff != 0)
/* Put the one that isn't an alias first. */
return alias_diff;
}
/* Except for aliases, two "identical" instructions had
better have the same opcode. This is a sanity check on the table. */
i = strcmp (op0->name, op1->name);
if (i)
{
if (op0->flags & F_ALIAS) /* If they're both aliases, be arbitrary. */
return i;
else
fprintf (stderr,
"Internal error: bad sparc-opcode.h: \"%s\" == \"%s\"\n",
op0->name, op1->name);
}
/* Fewer arguments are preferred. */
{
int length_diff = strlen (op0->args) - strlen (op1->args);
if (length_diff != 0)
/* Put the one with fewer arguments first. */
return length_diff;
}
/* Put 1+i before i+1. */
{
char *p0 = (char *) strchr (op0->args, '+');
char *p1 = (char *) strchr (op1->args, '+');
if (p0 && p1)
{
/* There is a plus in both operands. Note that a plus
sign cannot be the first character in args,
so the following [-1]'s are valid. */
if (p0[-1] == 'i' && p1[1] == 'i')
/* op0 is i+1 and op1 is 1+i, so op1 goes first. */
return 1;
if (p0[1] == 'i' && p1[-1] == 'i')
/* op0 is 1+i and op1 is i+1, so op0 goes first. */
return -1;
}
}
/* Put 1,i before i,1. */
{
int i0 = strncmp (op0->args, "i,1", 3) == 0;
int i1 = strncmp (op1->args, "i,1", 3) == 0;
if (i0 ^ i1)
return i0 - i1;
}
/* They are, as far as we can tell, identical.
Since qsort may have rearranged the table partially, there is
no way to tell which one was first in the opcode table as
written, so just say there are equal. */
/* ??? This is no longer true now that we sort a vector of pointers,
not the table itself. */
return 0;
}
/* Build a hash table from the opcode table.
OPCODE_TABLE is a sorted list of pointers into the opcode table. */
static void
build_hash_table (opcode_table, hash_table, num_opcodes)
const struct sparc_opcode **opcode_table;
struct opcode_hash **hash_table;
int num_opcodes;
{
register int i;
int hash_count[HASH_SIZE];
static struct opcode_hash *hash_buf = NULL;
/* Start at the end of the table and work backwards so that each
chain is sorted. */
memset (hash_table, 0, HASH_SIZE * sizeof (hash_table[0]));
memset (hash_count, 0, HASH_SIZE * sizeof (hash_count[0]));
if (hash_buf != NULL)
free (hash_buf);
hash_buf = (struct opcode_hash *) xmalloc (sizeof (struct opcode_hash) * num_opcodes);
for (i = num_opcodes - 1; i >= 0; --i)
{
register int hash = HASH_INSN (opcode_table[i]->match);
register struct opcode_hash *h = &hash_buf[i];
h->next = hash_table[hash];
h->opcode = opcode_table[i];
hash_table[hash] = h;
++hash_count[hash];
}
#if 0 /* for debugging */
{
int min_count = num_opcodes, max_count = 0;
int total;
for (i = 0; i < HASH_SIZE; ++i)
{
if (hash_count[i] < min_count)
min_count = hash_count[i];
if (hash_count[i] > max_count)
max_count = hash_count[i];
total += hash_count[i];
}
printf ("Opcode hash table stats: min %d, max %d, ave %f\n",
min_count, max_count, (double) total / HASH_SIZE);
}
#endif
}

File diff suppressed because it is too large Load Diff