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:
parent
0b91470ee9
commit
407509b3ae
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/vendor/binutils/dist/; revision=59024
142
contrib/binutils/bfd/cpu-sparc.c
Normal file
142
contrib/binutils/bfd/cpu-sparc.c
Normal 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],
|
||||
};
|
1863
contrib/binutils/bfd/elf32-sparc.c
Normal file
1863
contrib/binutils/bfd/elf32-sparc.c
Normal file
File diff suppressed because it is too large
Load Diff
2263
contrib/binutils/bfd/elf64-sparc.c
Normal file
2263
contrib/binutils/bfd/elf64-sparc.c
Normal file
File diff suppressed because it is too large
Load Diff
2918
contrib/binutils/bfd/sunos.c
Normal file
2918
contrib/binutils/bfd/sunos.c
Normal file
File diff suppressed because it is too large
Load Diff
3364
contrib/binutils/gas/config/tc-sparc.c
Normal file
3364
contrib/binutils/gas/config/tc-sparc.c
Normal file
File diff suppressed because it is too large
Load Diff
149
contrib/binutils/gas/config/tc-sparc.h
Normal file
149
contrib/binutils/gas/config/tc-sparc.h
Normal 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 */
|
219
contrib/binutils/include/aout/sun4.h
Normal file
219
contrib/binutils/include/aout/sun4.h
Normal 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];
|
||||
};
|
117
contrib/binutils/include/elf/sparc.h
Normal file
117
contrib/binutils/include/elf/sparc.h
Normal 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 */
|
240
contrib/binutils/include/opcode/sparc.h
Normal file
240
contrib/binutils/include/opcode/sparc.h
Normal 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 */
|
10
contrib/binutils/ld/emulparams/elf32_sparc.sh
Normal file
10
contrib/binutils/ld/emulparams/elf32_sparc.sh
Normal 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
|
12
contrib/binutils/ld/emulparams/elf64_sparc.sh
Normal file
12
contrib/binutils/ld/emulparams/elf64_sparc.sh
Normal 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
|
961
contrib/binutils/opcodes/sparc-dis.c
Normal file
961
contrib/binutils/opcodes/sparc-dis.c
Normal 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 (®_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
|
||||
}
|
1920
contrib/binutils/opcodes/sparc-opc.c
Normal file
1920
contrib/binutils/opcodes/sparc-opc.c
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user