diff options
Diffstat (limited to 'contrib/binutils/gas/config')
57 files changed, 0 insertions, 50111 deletions
diff --git a/contrib/binutils/gas/config/aout_gnu.h b/contrib/binutils/gas/config/aout_gnu.h deleted file mode 100644 index badf9cb21c73b..0000000000000 --- a/contrib/binutils/gas/config/aout_gnu.h +++ /dev/null @@ -1,455 +0,0 @@ -/* This file is aout_gnu.h - - Copyright (C) 1987-1992 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 __A_OUT_GNU_H__ -#define __A_OUT_GNU_H__ - -/* There are two main flavours of a.out, one which uses the standard - relocations, and one which uses extended relocations. - - Today, the extended reloc uses are - TC_SPARC, TC_A29K - - each must define the enum reloc_type - -*/ - -#define USE_EXTENDED_RELOC (defined(TC_SPARC) || defined(TC_A29K)) - -#if defined(TC_SPARC) || defined(TC_A29K) -enum reloc_type - { - RELOC_8, RELOC_16, RELOC_32,/* simple relocations */ - RELOC_DISP8, RELOC_DISP16, RELOC_DISP32, /* pc-rel displacement */ - RELOC_WDISP30, RELOC_WDISP22, - RELOC_HI22, RELOC_22, - RELOC_13, RELOC_LO10, - RELOC_SFA_BASE, RELOC_SFA_OFF13, - RELOC_BASE10, RELOC_BASE13, RELOC_BASE22, /* P.I.C. (base-relative) */ - RELOC_PC10, RELOC_PC22, /* for some sort of pc-rel P.I.C. (?) */ - RELOC_JMP_TBL, /* P.I.C. jump table */ - RELOC_SEGOFF16, /* reputedly for shared libraries somehow */ - RELOC_GLOB_DAT, RELOC_JMP_SLOT, RELOC_RELATIVE, - RELOC_10, RELOC_11, - RELOC_WDISP2_14, - RELOC_WDISP19, - RELOC_HHI22, - RELOC_HLO10, - - /* 29K relocation types */ - RELOC_JUMPTARG, RELOC_CONST, RELOC_CONSTH, - - RELOC_WDISP14, RELOC_WDISP21, - - NO_RELOC - }; - -#endif /* TC_SPARC or TC_A29K */ - - -#define __GNU_EXEC_MACROS__ - -#ifndef __STRUCT_EXEC_OVERRIDE__ - -/* This is the layout on disk of a Unix V7, Berkeley, SunOS, Vax Ultrix - "struct exec". Don't assume that on this machine, the "struct exec" - will lay out the same sizes or alignments. */ - -struct exec_bytes - { - unsigned char a_info[4]; - unsigned char a_text[4]; - unsigned char a_data[4]; - unsigned char a_bss[4]; - unsigned char a_syms[4]; - unsigned char a_entry[4]; - unsigned char a_trsize[4]; - unsigned char a_drsize[4]; - }; - -/* How big the "struct exec" is on disk */ -#define EXEC_BYTES_SIZE (8 * 4) - -/* This is the layout in memory of a "struct exec" while we process it. */ - -struct exec -{ - unsigned long a_info; /* Use macros N_MAGIC, etc for access */ - unsigned a_text; /* length of text, in bytes */ - unsigned a_data; /* length of data, in bytes */ - unsigned a_bss; /* length of uninitialized data area for file, in bytes */ - unsigned a_syms; /* length of symbol table data in file, in bytes */ - unsigned a_entry; /* start address */ - unsigned a_trsize; /* length of relocation info for text, in bytes */ - unsigned a_drsize; /* length of relocation info for data, in bytes */ -}; - -#endif /* __STRUCT_EXEC_OVERRIDE__ */ - -/* these go in the N_MACHTYPE field */ -/* These symbols could be defined by code from Suns...punt 'em */ -#undef M_UNKNOWN -#undef M_68010 -#undef M_68020 -#undef M_SPARC -enum machine_type - { - M_UNKNOWN = 0, - M_68010 = 1, - M_68020 = 2, - M_SPARC = 3, - /* skip a bunch so we don't run into any of sun's numbers */ - M_386 = 100, - M_29K = 101, - M_RS6000 = 102, /* IBM RS/6000 */ - /* HP/BSD formats */ - M_HP200 = 200, /* hp200 (68010) BSD binary */ - M_HP300 = 300, /* hp300 (68020+68881) BSD binary */ - M_HPUX23 = 0x020C /* hp200/300 HPUX binary */ - }; - -#define N_MAGIC(exec) ((exec).a_info & 0xffff) -#define N_MACHTYPE(exec) ((enum machine_type)(((exec).a_info >> 16) & 0xff)) -#define N_FLAGS(exec) (((exec).a_info >> 24) & 0xff) -#define N_SET_INFO(exec, magic, type, flags) \ - ((exec).a_info = ((magic) & 0xffff) \ - | (((int)(type) & 0xff) << 16) \ - | (((flags) & 0xff) << 24)) -#define N_SET_MAGIC(exec, magic) \ - ((exec).a_info = (((exec).a_info & 0xffff0000) | ((magic) & 0xffff))) - -#define N_SET_MACHTYPE(exec, machtype) \ - ((exec).a_info = \ - ((exec).a_info&0xff00ffff) | ((((int)(machtype))&0xff) << 16)) - -#define N_SET_FLAGS(exec, flags) \ - ((exec).a_info = \ - ((exec).a_info&0x00ffffff) | (((flags) & 0xff) << 24)) - -/* Code indicating object file or impure executable. */ -#ifndef OMAGIC -#define OMAGIC 0407 -#endif -/* Code indicating pure executable. */ -#define NMAGIC 0410 -/* Code indicating demand-paged executable. */ -#define ZMAGIC 0413 - -/* Virtual Address of text segment from the a.out file. For OMAGIC, - (almost always "unlinked .o's" these days), should be zero. - For linked files, should reflect reality if we know it. */ - -#ifndef N_TXTADDR -#define N_TXTADDR(x) (N_MAGIC(x)==OMAGIC? 0 : TEXT_START_ADDR) -#endif - -#ifndef N_BADMAG -#define N_BADMAG(x) (N_MAGIC(x) != OMAGIC \ - && N_MAGIC(x) != NMAGIC \ - && N_MAGIC(x) != ZMAGIC) -#endif - -/* By default, segment size is constant. But on some machines, it can - be a function of the a.out header (e.g. machine type). */ -#ifndef N_SEGSIZE -#define N_SEGSIZE(x) SEGMENT_SIZE -#endif - -/* This complexity is for encapsulated COFF support */ -#ifndef _N_HDROFF -#define _N_HDROFF(x) (N_SEGSIZE(x) - sizeof (struct exec)) -#endif - -#ifndef N_TXTOFF -#define N_TXTOFF(x) (N_MAGIC(x) == ZMAGIC ? \ - _N_HDROFF((x)) + sizeof (struct exec) : \ - sizeof (struct exec)) -#endif - - -#ifndef N_DATOFF -#define N_DATOFF(x) ( N_TXTOFF(x) + (x).a_text ) -#endif - -#ifndef N_TRELOFF -#define N_TRELOFF(x) ( N_DATOFF(x) + (x).a_data ) -#endif - -#ifndef N_DRELOFF -#define N_DRELOFF(x) ( N_TRELOFF(x) + (x).a_trsize ) -#endif - -#ifndef N_SYMOFF -#define N_SYMOFF(x) ( N_DRELOFF(x) + (x).a_drsize ) -#endif - -#ifndef N_STROFF -#define N_STROFF(x) ( N_SYMOFF(x) + (x).a_syms ) -#endif - -/* Address of text segment in memory after it is loaded. */ -#ifndef N_TXTADDR -#define N_TXTADDR(x) 0 -#endif - -#ifndef N_DATADDR -#define N_DATADDR(x) \ - (N_MAGIC(x)==OMAGIC? (N_TXTADDR(x)+(x).a_text) \ - : (N_SEGSIZE(x) + ((N_TXTADDR(x)+(x).a_text-1) & ~(N_SEGSIZE(x)-1)))) -#endif - -/* Address of bss segment in memory after it is loaded. */ -#define N_BSSADDR(x) (N_DATADDR(x) + (x).a_data) - -struct nlist - { - union - { - char *n_name; - struct nlist *n_next; - long n_strx; - } - n_un; - unsigned char n_type; - char n_other; - short n_desc; - unsigned long n_value; - }; - -#define N_UNDF 0 -#define N_ABS 2 -#define N_TEXT 4 -#define N_DATA 6 -#define N_BSS 8 -#define N_COMM 0x12 /* common (visible in shared lib commons) */ -#define N_FN 0x1F /* File name of a .o file */ - -/* Note: N_EXT can only usefully be OR-ed with N_UNDF, N_ABS, N_TEXT, - N_DATA, or N_BSS. When the low-order bit of other types is set, - (e.g. N_WARNING versus N_FN), they are two different types. */ -#define N_EXT 1 -#define N_TYPE 036 -#define N_STAB 0340 - -/* The following type indicates the definition of a symbol as being - an indirect reference to another symbol. The other symbol - appears as an undefined reference, immediately following this symbol. - - Indirection is asymmetrical. The other symbol's value will be used - to satisfy requests for the indirect symbol, but not vice versa. - If the other symbol does not have a definition, libraries will - be searched to find a definition. */ - -#define N_INDR 0xa - -/* The following symbols refer to set elements. - All the N_SET[ATDB] symbols with the same name form one set. - Space is allocated for the set in the text section, and each set - element's value is stored into one word of the space. - The first word of the space is the length of the set (number of elements). - - The address of the set is made into an N_SETV symbol - whose name is the same as the name of the set. - This symbol acts like a N_DATA global symbol - in that it can satisfy undefined external references. */ - -/* These appear as input to LD, in a .o file. */ -#define N_SETA 0x14 /* Absolute set element symbol */ -#define N_SETT 0x16 /* Text set element symbol */ -#define N_SETD 0x18 /* Data set element symbol */ -#define N_SETB 0x1A /* Bss set element symbol */ - -/* This is output from LD. */ -#define N_SETV 0x1C /* Pointer to set vector in data area. */ - -/* Warning symbol. The text gives a warning message, the next symbol - in the table will be undefined. When the symbol is referenced, the - message is printed. */ - -#define N_WARNING 0x1e - -/* Weak symbols. These are a GNU extension to the a.out format. The - semantics are those of ELF weak symbols. Weak symbols are always - externally visible. The N_WEAK? values are squeezed into the - available slots. The value of a N_WEAKU symbol is 0. The values - of the other types are the definitions. */ -#define N_WEAKU 0x0d /* Weak undefined symbol. */ -#define N_WEAKA 0x0e /* Weak absolute symbol. */ -#define N_WEAKT 0x0f /* Weak text symbol. */ -#define N_WEAKD 0x10 /* Weak data symbol. */ -#define N_WEAKB 0x11 /* Weak bss symbol. */ - -/* This structure describes a single relocation to be performed. - The text-relocation section of the file is a vector of these structures, - all of which apply to the text section. - Likewise, the data-relocation section applies to the data section. */ - -/* The following enum and struct were borrowed from SunOS's - /usr/include/sun4/a.out.h and extended to handle - other machines. It is currently used on SPARC and AMD 29000. - - reloc_ext_bytes is how it looks on disk. reloc_info_extended is - how we might process it on a native host. */ -#if USE_EXTENDED_RELOC - -struct reloc_ext_bytes - { - unsigned char r_address[4]; - unsigned char r_index[3]; - unsigned char r_bits[1]; - unsigned char r_addend[4]; - }; - - -#define RELOC_EXT_BITS_EXTERN_BIG 0x80 -#define RELOC_EXT_BITS_EXTERN_LITTLE 0x01 - -#define RELOC_EXT_BITS_TYPE_BIG 0x1F -#define RELOC_EXT_BITS_TYPE_SH_BIG 0 -#define RELOC_EXT_BITS_TYPE_LITTLE 0xF8 -#define RELOC_EXT_BITS_TYPE_SH_LITTLE 3 - -#define RELOC_EXT_SIZE 12 /* Bytes per relocation entry */ - -struct reloc_info_extended -{ - unsigned long r_address; - unsigned int r_index:24; -# define r_symbolnum r_index - unsigned r_extern:1; - unsigned:2; - /* RS/6000 compiler does not support enum bitfield - enum reloc_type r_type:5; */ - enum reloc_type r_type; - long int r_addend; -}; - -#else - -/* The standard, old-fashioned, Berkeley compatible relocation struct */ - - - -#ifdef TC_I860 -/* NOTE: three bits max, see struct reloc_info_i860.r_type */ -enum i860_reloc_type - { - NO_RELOC = 0, BRADDR, LOW0, LOW1, LOW2, LOW3, LOW4, SPLIT0, SPLIT1, SPLIT2, RELOC_32, - }; - -typedef enum i860_reloc_type reloc_type; - -/* NOTE: two bits max, see reloc_info_i860.r_type */ -enum highlow_type - { - NO_SPEC = 0, PAIR, HIGH, HIGHADJ, - }; - - -struct reloc_info_i860 -{ - unsigned long r_address; - /* - * Using bit fields here is a bad idea because the order is not portable. :-( - */ - unsigned int r_symbolnum:24; - unsigned int r_pcrel:1; - unsigned int r_extern:1; - /* combining the two field simplifies the argument passing in "new_fix()" */ - /* and is compatible with the existing Sparc #ifdef's */ - /* r_type: highlow_type - bits 5,4; reloc_type - bits 3-0 */ - unsigned int r_type:6; - long r_addend; -}; - -#endif /* TC_I860 */ - - -struct reloc_std_bytes - { - unsigned char r_address[4]; - unsigned char r_index[3]; - unsigned char r_bits[1]; - }; - -#define RELOC_STD_BITS_PCREL_BIG 0x80 -#define RELOC_STD_BITS_PCREL_LITTLE 0x01 - -#define RELOC_STD_BITS_LENGTH_BIG 0x60 -#define RELOC_STD_BITS_LENGTH_SH_BIG 5 /* To shift to units place */ -#define RELOC_STD_BITS_LENGTH_LITTLE 0x06 -#define RELOC_STD_BITS_LENGTH_SH_LITTLE 1 - -#define RELOC_STD_BITS_EXTERN_BIG 0x10 -#define RELOC_STD_BITS_EXTERN_LITTLE 0x08 - -#define RELOC_STD_BITS_BASEREL_BIG 0x08 -#define RELOC_STD_BITS_BASEREL_LITTLE 0x08 - -#define RELOC_STD_BITS_JMPTABLE_BIG 0x04 -#define RELOC_STD_BITS_JMPTABLE_LITTLE 0x04 - -#define RELOC_STD_BITS_RELATIVE_BIG 0x02 -#define RELOC_STD_BITS_RELATIVE_LITTLE 0x02 - -#define RELOC_STD_SIZE 8 /* Bytes per relocation entry */ - -#endif /* USE_EXTENDED_RELOC */ - -#ifndef CUSTOM_RELOC_FORMAT -struct relocation_info -{ - /* Address (within segment) to be relocated. */ - int r_address; - /* The meaning of r_symbolnum depends on r_extern. */ - unsigned int r_symbolnum:24; - /* Nonzero means value is a pc-relative offset - and it should be relocated for changes in its own address - as well as for changes in the symbol or section specified. */ - unsigned int r_pcrel:1; - /* Length (as exponent of 2) of the field to be relocated. - Thus, a value of 2 indicates 1<<2 bytes. */ - unsigned int r_length:2; - /* 1 => relocate with value of symbol. - r_symbolnum is the index of the symbol - in file's the symbol table. - 0 => relocate with the address of a segment. - r_symbolnum is N_TEXT, N_DATA, N_BSS or N_ABS - (the N_EXT bit may be set also, but signifies nothing). */ - unsigned int r_extern:1; - /* The next three bits are for SunOS shared libraries, and seem to - be undocumented. */ -#ifdef TC_NS32K - unsigned int r_bsr:1; - unsigned int r_disp:2; -#else - unsigned int r_baserel:1; /* Linkage table relative */ - unsigned int r_jmptable:1; /* pc-relative to jump table */ - unsigned int r_relative:1; /* "relative relocation" */ -#endif /* TC_NS32K */ - /* unused */ - unsigned int r_pad:1; /* Padding -- set to zero */ -}; - -#endif /* CUSTOM_RELOC_FORMAT */ - -#endif /* __A_OUT_GNU_H__ */ - -/* end of aout_gnu.h */ diff --git a/contrib/binutils/gas/config/atof-ieee.c b/contrib/binutils/gas/config/atof-ieee.c deleted file mode 100644 index 2e3c0dc6d0f6c..0000000000000 --- a/contrib/binutils/gas/config/atof-ieee.c +++ /dev/null @@ -1,717 +0,0 @@ -/* atof_ieee.c - turn a Flonum into an IEEE floating point number - Copyright (C) 1987, 92, 93, 94, 95, 96, 97, 98, 99, 2000 - 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. */ - -#include "as.h" - -/* Flonums returned here. */ -extern FLONUM_TYPE generic_floating_point_number; - -static int next_bits PARAMS ((int)); -static void unget_bits PARAMS ((int)); -static void make_invalid_floating_point_number PARAMS ((LITTLENUM_TYPE *)); - -extern const char EXP_CHARS[]; -/* Precision in LittleNums. */ -/* Don't count the gap in the m68k extended precision format. */ -#define MAX_PRECISION (5) -#define F_PRECISION (2) -#define D_PRECISION (4) -#define X_PRECISION (5) -#define P_PRECISION (5) - -/* Length in LittleNums of guard bits. */ -#define GUARD (2) - -static const unsigned long mask[] = -{ - 0x00000000, - 0x00000001, - 0x00000003, - 0x00000007, - 0x0000000f, - 0x0000001f, - 0x0000003f, - 0x0000007f, - 0x000000ff, - 0x000001ff, - 0x000003ff, - 0x000007ff, - 0x00000fff, - 0x00001fff, - 0x00003fff, - 0x00007fff, - 0x0000ffff, - 0x0001ffff, - 0x0003ffff, - 0x0007ffff, - 0x000fffff, - 0x001fffff, - 0x003fffff, - 0x007fffff, - 0x00ffffff, - 0x01ffffff, - 0x03ffffff, - 0x07ffffff, - 0x0fffffff, - 0x1fffffff, - 0x3fffffff, - 0x7fffffff, - 0xffffffff, -}; - - -static int bits_left_in_littlenum; -static int littlenums_left; -static LITTLENUM_TYPE *littlenum_pointer; - -static int -next_bits (number_of_bits) - int number_of_bits; -{ - int return_value; - - if (!littlenums_left) - return (0); - if (number_of_bits >= bits_left_in_littlenum) - { - return_value = mask[bits_left_in_littlenum] & *littlenum_pointer; - number_of_bits -= bits_left_in_littlenum; - return_value <<= number_of_bits; - - if (--littlenums_left) - { - bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS - number_of_bits; - --littlenum_pointer; - return_value |= (*littlenum_pointer >> bits_left_in_littlenum) & mask[number_of_bits]; - } - } - else - { - bits_left_in_littlenum -= number_of_bits; - return_value = mask[number_of_bits] & (*littlenum_pointer >> bits_left_in_littlenum); - } - return (return_value); -} - -/* Num had better be less than LITTLENUM_NUMBER_OF_BITS */ -static void -unget_bits (num) - int num; -{ - if (!littlenums_left) - { - ++littlenum_pointer; - ++littlenums_left; - bits_left_in_littlenum = num; - } - else if (bits_left_in_littlenum + num > LITTLENUM_NUMBER_OF_BITS) - { - bits_left_in_littlenum = num - (LITTLENUM_NUMBER_OF_BITS - bits_left_in_littlenum); - ++littlenum_pointer; - ++littlenums_left; - } - else - bits_left_in_littlenum += num; -} - -static void -make_invalid_floating_point_number (words) - LITTLENUM_TYPE *words; -{ - as_bad (_("cannot create floating-point number")); - words[0] = (LITTLENUM_TYPE) ((unsigned) -1) >> 1; /* Zero the leftmost bit */ - words[1] = (LITTLENUM_TYPE) -1; - words[2] = (LITTLENUM_TYPE) -1; - words[3] = (LITTLENUM_TYPE) -1; - words[4] = (LITTLENUM_TYPE) -1; - words[5] = (LITTLENUM_TYPE) -1; -} - -/************************************************************************\ - * Warning: this returns 16-bit LITTLENUMs. It is up to the caller * - * to figure out any alignment problems and to conspire for the * - * bytes/word to be emitted in the right order. Bigendians beware! * - * * -\************************************************************************/ - -/* Note that atof-ieee always has X and P precisions enabled. it is up - to md_atof to filter them out if the target machine does not support - them. */ - -/* Returns pointer past text consumed. */ -char * -atof_ieee (str, what_kind, words) - char *str; /* Text to convert to binary. */ - int what_kind; /* 'd', 'f', 'g', 'h' */ - LITTLENUM_TYPE *words; /* Build the binary here. */ -{ - /* Extra bits for zeroed low-order bits. The 1st MAX_PRECISION are - zeroed, the last contain flonum bits. */ - static LITTLENUM_TYPE bits[MAX_PRECISION + MAX_PRECISION + GUARD]; - char *return_value; - /* Number of 16-bit words in the format. */ - int precision; - long exponent_bits; - FLONUM_TYPE save_gen_flonum; - - /* We have to save the generic_floating_point_number because it - contains storage allocation about the array of LITTLENUMs where - the value is actually stored. We will allocate our own array of - littlenums below, but have to restore the global one on exit. */ - save_gen_flonum = generic_floating_point_number; - - return_value = str; - generic_floating_point_number.low = bits + MAX_PRECISION; - generic_floating_point_number.high = NULL; - generic_floating_point_number.leader = NULL; - generic_floating_point_number.exponent = 0; - generic_floating_point_number.sign = '\0'; - - /* Use more LittleNums than seems necessary: the highest flonum may - have 15 leading 0 bits, so could be useless. */ - - memset (bits, '\0', sizeof (LITTLENUM_TYPE) * MAX_PRECISION); - - switch (what_kind) - { - case 'f': - case 'F': - case 's': - case 'S': - precision = F_PRECISION; - exponent_bits = 8; - break; - - case 'd': - case 'D': - case 'r': - case 'R': - precision = D_PRECISION; - exponent_bits = 11; - break; - - case 'x': - case 'X': - case 'e': - case 'E': - precision = X_PRECISION; - exponent_bits = 15; - break; - - case 'p': - case 'P': - - precision = P_PRECISION; - exponent_bits = -1; - break; - - default: - make_invalid_floating_point_number (words); - return (NULL); - } - - generic_floating_point_number.high - = generic_floating_point_number.low + precision - 1 + GUARD; - - if (atof_generic (&return_value, ".", EXP_CHARS, - &generic_floating_point_number)) - { - make_invalid_floating_point_number (words); - return (NULL); - } - gen_to_words (words, precision, exponent_bits); - - /* Restore the generic_floating_point_number's storage alloc (and - everything else). */ - generic_floating_point_number = save_gen_flonum; - - return return_value; -} - -/* Turn generic_floating_point_number into a real float/double/extended. */ -int -gen_to_words (words, precision, exponent_bits) - LITTLENUM_TYPE *words; - int precision; - long exponent_bits; -{ - int return_value = 0; - - long exponent_1; - long exponent_2; - long exponent_3; - long exponent_4; - int exponent_skippage; - LITTLENUM_TYPE word1; - LITTLENUM_TYPE *lp; - LITTLENUM_TYPE *words_end; - - words_end = words + precision; -#ifdef TC_M68K - if (precision == X_PRECISION) - /* On the m68k the extended precision format has a gap of 16 bits - between the exponent and the mantissa. */ - words_end++; -#endif - - if (generic_floating_point_number.low > generic_floating_point_number.leader) - { - /* 0.0e0 seen. */ - if (generic_floating_point_number.sign == '+') - words[0] = 0x0000; - else - words[0] = 0x8000; - memset (&words[1], '\0', - (words_end - words - 1) * sizeof (LITTLENUM_TYPE)); - return (return_value); - } - - /* NaN: Do the right thing */ - if (generic_floating_point_number.sign == 0) - { - if (precision == F_PRECISION) - { - words[0] = 0x7fff; - words[1] = 0xffff; - } - else if (precision == X_PRECISION) - { -#ifdef TC_M68K - words[0] = 0x7fff; - words[1] = 0; - words[2] = 0xffff; - words[3] = 0xffff; - words[4] = 0xffff; - words[5] = 0xffff; -#else /* ! TC_M68K */ -#ifdef TC_I386 - words[0] = 0xffff; - words[1] = 0xc000; - words[2] = 0; - words[3] = 0; - words[4] = 0; -#else /* ! TC_I386 */ - abort (); -#endif /* ! TC_I386 */ -#endif /* ! TC_M68K */ - } - else - { - words[0] = 0x7fff; - words[1] = 0xffff; - words[2] = 0xffff; - words[3] = 0xffff; - } - return return_value; - } - else if (generic_floating_point_number.sign == 'P') - { - /* +INF: Do the right thing */ - if (precision == F_PRECISION) - { - words[0] = 0x7f80; - words[1] = 0; - } - else if (precision == X_PRECISION) - { -#ifdef TC_M68K - words[0] = 0x7fff; - words[1] = 0; - words[2] = 0; - words[3] = 0; - words[4] = 0; - words[5] = 0; -#else /* ! TC_M68K */ -#ifdef TC_I386 - words[0] = 0x7fff; - words[1] = 0x8000; - words[2] = 0; - words[3] = 0; - words[4] = 0; -#else /* ! TC_I386 */ - abort (); -#endif /* ! TC_I386 */ -#endif /* ! TC_M68K */ - } - else - { - words[0] = 0x7ff0; - words[1] = 0; - words[2] = 0; - words[3] = 0; - } - return (return_value); - } - else if (generic_floating_point_number.sign == 'N') - { - /* Negative INF */ - if (precision == F_PRECISION) - { - words[0] = 0xff80; - words[1] = 0x0; - } - else if (precision == X_PRECISION) - { -#ifdef TC_M68K - words[0] = 0xffff; - words[1] = 0; - words[2] = 0; - words[3] = 0; - words[4] = 0; - words[5] = 0; -#else /* ! TC_M68K */ -#ifdef TC_I386 - words[0] = 0xffff; - words[1] = 0x8000; - words[2] = 0; - words[3] = 0; - words[4] = 0; -#else /* ! TC_I386 */ - abort (); -#endif /* ! TC_I386 */ -#endif /* ! TC_M68K */ - } - else - { - words[0] = 0xfff0; - words[1] = 0x0; - words[2] = 0x0; - words[3] = 0x0; - } - return (return_value); - } - /* - * The floating point formats we support have: - * Bit 15 is sign bit. - * Bits 14:n are excess-whatever exponent. - * Bits n-1:0 (if any) are most significant bits of fraction. - * Bits 15:0 of the next word(s) are the next most significant bits. - * - * So we need: number of bits of exponent, number of bits of - * mantissa. - */ - bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS; - littlenum_pointer = generic_floating_point_number.leader; - littlenums_left = (1 - + generic_floating_point_number.leader - - generic_floating_point_number.low); - /* Seek (and forget) 1st significant bit */ - for (exponent_skippage = 0; !next_bits (1); ++exponent_skippage);; - exponent_1 = (generic_floating_point_number.exponent - + generic_floating_point_number.leader - + 1 - - generic_floating_point_number.low); - /* Radix LITTLENUM_RADIX, point just higher than - generic_floating_point_number.leader. */ - exponent_2 = exponent_1 * LITTLENUM_NUMBER_OF_BITS; - /* Radix 2. */ - exponent_3 = exponent_2 - exponent_skippage; - /* Forget leading zeros, forget 1st bit. */ - exponent_4 = exponent_3 + ((1 << (exponent_bits - 1)) - 2); - /* Offset exponent. */ - - lp = words; - - /* Word 1. Sign, exponent and perhaps high bits. */ - word1 = ((generic_floating_point_number.sign == '+') - ? 0 - : (1 << (LITTLENUM_NUMBER_OF_BITS - 1))); - - /* Assume 2's complement integers. */ - if (exponent_4 <= 0) - { - int prec_bits; - int num_bits; - - unget_bits (1); - num_bits = -exponent_4; - prec_bits = LITTLENUM_NUMBER_OF_BITS * precision - (exponent_bits + 1 + num_bits); -#ifdef TC_I386 - if (precision == X_PRECISION && exponent_bits == 15) - { - /* On the i386 a denormalized extended precision float is - shifted down by one, effectively decreasing the exponent - bias by one. */ - prec_bits -= 1; - num_bits += 1; - } -#endif - - if (num_bits >= LITTLENUM_NUMBER_OF_BITS - exponent_bits) - { - /* Bigger than one littlenum */ - num_bits -= (LITTLENUM_NUMBER_OF_BITS - 1) - exponent_bits; - *lp++ = word1; - if (num_bits + exponent_bits + 1 > precision * LITTLENUM_NUMBER_OF_BITS) - { - /* Exponent overflow */ - make_invalid_floating_point_number (words); - return (return_value); - } -#ifdef TC_M68K - if (precision == X_PRECISION && exponent_bits == 15) - *lp++ = 0; -#endif - while (num_bits >= LITTLENUM_NUMBER_OF_BITS) - { - num_bits -= LITTLENUM_NUMBER_OF_BITS; - *lp++ = 0; - } - if (num_bits) - *lp++ = next_bits (LITTLENUM_NUMBER_OF_BITS - (num_bits)); - } - else - { - if (precision == X_PRECISION && exponent_bits == 15) - { - *lp++ = word1; -#ifdef TC_M68K - *lp++ = 0; -#endif - *lp++ = next_bits (LITTLENUM_NUMBER_OF_BITS - num_bits); - } - else - { - word1 |= next_bits ((LITTLENUM_NUMBER_OF_BITS - 1) - (exponent_bits + num_bits)); - *lp++ = word1; - } - } - while (lp < words_end) - *lp++ = next_bits (LITTLENUM_NUMBER_OF_BITS); - - /* Round the mantissa up, but don't change the number */ - if (next_bits (1)) - { - --lp; - if (prec_bits >= LITTLENUM_NUMBER_OF_BITS) - { - int n = 0; - int tmp_bits; - - n = 0; - tmp_bits = prec_bits; - while (tmp_bits > LITTLENUM_NUMBER_OF_BITS) - { - if (lp[n] != (LITTLENUM_TYPE) - 1) - break; - --n; - tmp_bits -= LITTLENUM_NUMBER_OF_BITS; - } - if (tmp_bits > LITTLENUM_NUMBER_OF_BITS - || (lp[n] & mask[tmp_bits]) != mask[tmp_bits] - || (prec_bits != (precision * LITTLENUM_NUMBER_OF_BITS - - exponent_bits - 1) -#ifdef TC_I386 - /* An extended precision float with only the integer - bit set would be invalid. That must be converted - to the smallest normalized number. */ - && !(precision == X_PRECISION - && prec_bits == (precision * LITTLENUM_NUMBER_OF_BITS - - exponent_bits - 2)) -#endif - )) - { - unsigned long carry; - - for (carry = 1; carry && (lp >= words); lp--) - { - carry = *lp + carry; - *lp = carry; - carry >>= LITTLENUM_NUMBER_OF_BITS; - } - } - else - { - /* This is an overflow of the denormal numbers. We - need to forget what we have produced, and instead - generate the smallest normalized number. */ - lp = words; - word1 = ((generic_floating_point_number.sign == '+') - ? 0 - : (1 << (LITTLENUM_NUMBER_OF_BITS - 1))); - word1 |= (1 - << ((LITTLENUM_NUMBER_OF_BITS - 1) - - exponent_bits)); - *lp++ = word1; -#ifdef TC_I386 - /* Set the integer bit in the extended precision format. - This cannot happen on the m68k where the mantissa - just overflows into the integer bit above. */ - if (precision == X_PRECISION) - *lp++ = 1 << (LITTLENUM_NUMBER_OF_BITS - 1); -#endif - while (lp < words_end) - *lp++ = 0; - } - } - else - *lp += 1; - } - - return return_value; - } - else if ((unsigned long) exponent_4 >= mask[exponent_bits]) - { - /* - * Exponent overflow. Lose immediately. - */ - - /* - * We leave return_value alone: admit we read the - * number, but return a floating exception - * because we can't encode the number. - */ - make_invalid_floating_point_number (words); - return return_value; - } - else - { - word1 |= (exponent_4 << ((LITTLENUM_NUMBER_OF_BITS - 1) - exponent_bits)) - | next_bits ((LITTLENUM_NUMBER_OF_BITS - 1) - exponent_bits); - } - - *lp++ = word1; - - /* X_PRECISION is special: on the 68k, it has 16 bits of zero in the - middle. Either way, it is then followed by a 1 bit. */ - if (exponent_bits == 15 && precision == X_PRECISION) - { -#ifdef TC_M68K - *lp++ = 0; -#endif - *lp++ = (1 << (LITTLENUM_NUMBER_OF_BITS - 1) - | next_bits (LITTLENUM_NUMBER_OF_BITS - 1)); - } - - /* The rest of the words are just mantissa bits. */ - while (lp < words_end) - *lp++ = next_bits (LITTLENUM_NUMBER_OF_BITS); - - if (next_bits (1)) - { - unsigned long carry; - /* - * Since the NEXT bit is a 1, round UP the mantissa. - * The cunning design of these hidden-1 floats permits - * us to let the mantissa overflow into the exponent, and - * it 'does the right thing'. However, we lose if the - * highest-order bit of the lowest-order word flips. - * Is that clear? - */ - - /* #if (sizeof(carry)) < ((sizeof(bits[0]) * BITS_PER_CHAR) + 2) - Please allow at least 1 more bit in carry than is in a LITTLENUM. - We need that extra bit to hold a carry during a LITTLENUM carry - propagation. Another extra bit (kept 0) will assure us that we - don't get a sticky sign bit after shifting right, and that - permits us to propagate the carry without any masking of bits. - #endif */ - for (carry = 1, lp--; carry; lp--) - { - carry = *lp + carry; - *lp = carry; - carry >>= LITTLENUM_NUMBER_OF_BITS; - if (lp == words) - break; - } - if (precision == X_PRECISION && exponent_bits == 15) - { - /* Extended precision numbers have an explicit integer bit - that we may have to restore. */ - if (lp == words) - { -#ifdef TC_M68K - /* On the m68k there is a gap of 16 bits. We must - explicitly propagate the carry into the exponent. */ - words[0] += words[1]; - words[1] = 0; - lp++; -#endif - /* Put back the integer bit. */ - lp[1] |= 1 << (LITTLENUM_NUMBER_OF_BITS - 1); - } - } - if ((word1 ^ *words) & (1 << (LITTLENUM_NUMBER_OF_BITS - 1))) - { - /* We leave return_value alone: admit we read the - * number, but return a floating exception - * because we can't encode the number. - */ - *words &= ~(1 << (LITTLENUM_NUMBER_OF_BITS - 1)); - /* make_invalid_floating_point_number (words); */ - /* return return_value; */ - } - } - return (return_value); -} - -#if 0 /* unused */ -/* This routine is a real kludge. Someone really should do it better, - but I'm too lazy, and I don't understand this stuff all too well - anyway. (JF) */ -static void -int_to_gen (x) - long x; -{ - char buf[20]; - char *bufp; - - sprintf (buf, "%ld", x); - bufp = &buf[0]; - if (atof_generic (&bufp, ".", EXP_CHARS, &generic_floating_point_number)) - as_bad (_("Error converting number to floating point (Exponent overflow?)")); -} -#endif - -#ifdef TEST -char * -print_gen (gen) - FLONUM_TYPE *gen; -{ - FLONUM_TYPE f; - LITTLENUM_TYPE arr[10]; - double dv; - float fv; - static char sbuf[40]; - - if (gen) - { - f = generic_floating_point_number; - generic_floating_point_number = *gen; - } - gen_to_words (&arr[0], 4, 11); - memcpy (&dv, &arr[0], sizeof (double)); - sprintf (sbuf, "%x %x %x %x %.14G ", arr[0], arr[1], arr[2], arr[3], dv); - gen_to_words (&arr[0], 2, 8); - memcpy (&fv, &arr[0], sizeof (float)); - sprintf (sbuf + strlen (sbuf), "%x %x %.12g\n", arr[0], arr[1], fv); - - if (gen) - { - generic_floating_point_number = f; - } - - return (sbuf); -} - -#endif - -/* end of atof-ieee.c */ diff --git a/contrib/binutils/gas/config/atof-vax.c b/contrib/binutils/gas/config/atof-vax.c deleted file mode 100644 index 8ba290faca832..0000000000000 --- a/contrib/binutils/gas/config/atof-vax.c +++ /dev/null @@ -1,517 +0,0 @@ -/* atof_vax.c - turn a Flonum into a VAX floating point number - Copyright (C) 1987, 1992, 93, 95, 1997 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. */ - -#include "as.h" - -static int atof_vax_sizeof PARAMS ((int)); -static int next_bits PARAMS ((int)); -static void make_invalid_floating_point_number PARAMS ((LITTLENUM_TYPE *)); -static int what_kind_of_float PARAMS ((int, int *, long *)); -static char *atof_vax PARAMS ((char *, int, LITTLENUM_TYPE *)); - -/* Precision in LittleNums. */ -#define MAX_PRECISION (8) -#define H_PRECISION (8) -#define G_PRECISION (4) -#define D_PRECISION (4) -#define F_PRECISION (2) - -/* Length in LittleNums of guard bits. */ -#define GUARD (2) - -int flonum_gen2vax PARAMS ((int format_letter, FLONUM_TYPE * f, - LITTLENUM_TYPE * words)); - -/* Number of chars in flonum type 'letter'. */ -static int -atof_vax_sizeof (letter) - int letter; -{ - int return_value; - - /* - * Permitting uppercase letters is probably a bad idea. - * Please use only lower-cased letters in case the upper-cased - * ones become unsupported! - */ - switch (letter) - { - case 'f': - case 'F': - return_value = 4; - break; - - case 'd': - case 'D': - case 'g': - case 'G': - return_value = 8; - break; - - case 'h': - case 'H': - return_value = 16; - break; - - default: - return_value = 0; - break; - } - return (return_value); -} /* atof_vax_sizeof */ - -static const long mask[] = -{ - 0x00000000, - 0x00000001, - 0x00000003, - 0x00000007, - 0x0000000f, - 0x0000001f, - 0x0000003f, - 0x0000007f, - 0x000000ff, - 0x000001ff, - 0x000003ff, - 0x000007ff, - 0x00000fff, - 0x00001fff, - 0x00003fff, - 0x00007fff, - 0x0000ffff, - 0x0001ffff, - 0x0003ffff, - 0x0007ffff, - 0x000fffff, - 0x001fffff, - 0x003fffff, - 0x007fffff, - 0x00ffffff, - 0x01ffffff, - 0x03ffffff, - 0x07ffffff, - 0x0fffffff, - 0x1fffffff, - 0x3fffffff, - 0x7fffffff, - 0xffffffff -}; - - -/* Shared between flonum_gen2vax and next_bits */ -static int bits_left_in_littlenum; -static LITTLENUM_TYPE *littlenum_pointer; -static LITTLENUM_TYPE *littlenum_end; - -static int -next_bits (number_of_bits) - int number_of_bits; -{ - int return_value; - - if (littlenum_pointer < littlenum_end) - return 0; - if (number_of_bits >= bits_left_in_littlenum) - { - return_value = mask[bits_left_in_littlenum] & *littlenum_pointer; - number_of_bits -= bits_left_in_littlenum; - return_value <<= number_of_bits; - bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS - number_of_bits; - littlenum_pointer--; - if (littlenum_pointer >= littlenum_end) - return_value |= ((*littlenum_pointer) >> (bits_left_in_littlenum)) & mask[number_of_bits]; - } - else - { - bits_left_in_littlenum -= number_of_bits; - return_value = mask[number_of_bits] & ((*littlenum_pointer) >> bits_left_in_littlenum); - } - return (return_value); -} - -static void -make_invalid_floating_point_number (words) - LITTLENUM_TYPE *words; -{ - *words = 0x8000; /* Floating Reserved Operand Code */ -} - -static int /* 0 means letter is OK. */ -what_kind_of_float (letter, precisionP, exponent_bitsP) - int letter; /* In: lowercase please. What kind of float? */ - int *precisionP; /* Number of 16-bit words in the float. */ - long *exponent_bitsP; /* Number of exponent bits. */ -{ - int retval; /* 0: OK. */ - - retval = 0; - switch (letter) - { - case 'f': - *precisionP = F_PRECISION; - *exponent_bitsP = 8; - break; - - case 'd': - *precisionP = D_PRECISION; - *exponent_bitsP = 8; - break; - - case 'g': - *precisionP = G_PRECISION; - *exponent_bitsP = 11; - break; - - case 'h': - *precisionP = H_PRECISION; - *exponent_bitsP = 15; - break; - - default: - retval = 69; - break; - } - return (retval); -} - -/***********************************************************************\ - * * - * Warning: this returns 16-bit LITTLENUMs, because that is * - * what the VAX thinks in. It is up to the caller to figure * - * out any alignment problems and to conspire for the bytes/word * - * to be emitted in the right order. Bigendians beware! * - * * - \***********************************************************************/ - -static char * /* Return pointer past text consumed. */ -atof_vax (str, what_kind, words) - char *str; /* Text to convert to binary. */ - int what_kind; /* 'd', 'f', 'g', 'h' */ - LITTLENUM_TYPE *words; /* Build the binary here. */ -{ - FLONUM_TYPE f; - LITTLENUM_TYPE bits[MAX_PRECISION + MAX_PRECISION + GUARD]; - /* Extra bits for zeroed low-order bits. */ - /* The 1st MAX_PRECISION are zeroed, */ - /* the last contain flonum bits. */ - char *return_value; - int precision; /* Number of 16-bit words in the format. */ - long exponent_bits; - - return_value = str; - f.low = bits + MAX_PRECISION; - f.high = NULL; - f.leader = NULL; - f.exponent = 0; - f.sign = '\0'; - - if (what_kind_of_float (what_kind, &precision, &exponent_bits)) - { - return_value = NULL; /* We lost. */ - make_invalid_floating_point_number (words); - } - - if (return_value) - { - memset (bits, '\0', sizeof (LITTLENUM_TYPE) * MAX_PRECISION); - - /* Use more LittleNums than seems */ - /* necessary: the highest flonum may have */ - /* 15 leading 0 bits, so could be useless. */ - f.high = f.low + precision - 1 + GUARD; - - if (atof_generic (&return_value, ".", "eE", &f)) - { - make_invalid_floating_point_number (words); - return_value = NULL; /* we lost */ - } - else - { - if (flonum_gen2vax (what_kind, &f, words)) - { - return_value = NULL; - } - } - } - return (return_value); -} /* atof_vax() */ - -/* - * In: a flonum, a vax floating point format. - * Out: a vax floating-point bit pattern. - */ - -int /* 0: OK. */ -flonum_gen2vax (format_letter, f, words) - char format_letter; /* One of 'd' 'f' 'g' 'h'. */ - FLONUM_TYPE *f; - LITTLENUM_TYPE *words; /* Deliver answer here. */ -{ - LITTLENUM_TYPE *lp; - int precision; - long exponent_bits; - int return_value; /* 0 == OK. */ - - return_value = what_kind_of_float (format_letter, &precision, &exponent_bits); - - if (return_value != 0) - { - make_invalid_floating_point_number (words); - } - else - { - if (f->low > f->leader) - { - /* 0.0e0 seen. */ - memset (words, '\0', sizeof (LITTLENUM_TYPE) * precision); - } - else - { - long exponent_1; - long exponent_2; - long exponent_3; - long exponent_4; - int exponent_skippage; - LITTLENUM_TYPE word1; - - /* JF: Deal with new Nan, +Inf and -Inf codes */ - if (f->sign != '-' && f->sign != '+') - { - make_invalid_floating_point_number (words); - return return_value; - } - /* - * All vaxen floating_point formats (so far) have: - * Bit 15 is sign bit. - * Bits 14:n are excess-whatever exponent. - * Bits n-1:0 (if any) are most significant bits of fraction. - * Bits 15:0 of the next word are the next most significant bits. - * And so on for each other word. - * - * All this to be compatible with a KF11?? (Which is still faster - * than lots of vaxen I can think of, but it also has higher - * maintenance costs ... sigh). - * - * So we need: number of bits of exponent, number of bits of - * mantissa. - */ - -#ifdef NEVER /******* This zeroing seems redundant - Dean 3may86 **********/ - /* - * No matter how few bits we got back from the atof() - * routine, add enough zero littlenums so the rest of the - * code won't run out of "significant" bits in the mantissa. - */ - { - LITTLENUM_TYPE *ltp; - for (ltp = f->leader + 1; - ltp <= f->low + precision; - ltp++) - { - *ltp = 0; - } - } -#endif - - bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS; - littlenum_pointer = f->leader; - littlenum_end = f->low; - /* Seek (and forget) 1st significant bit */ - for (exponent_skippage = 0; - !next_bits (1); - exponent_skippage++);; - - exponent_1 = f->exponent + f->leader + 1 - f->low; - /* Radix LITTLENUM_RADIX, point just higher than f->leader. */ - exponent_2 = exponent_1 * LITTLENUM_NUMBER_OF_BITS; - /* Radix 2. */ - exponent_3 = exponent_2 - exponent_skippage; - /* Forget leading zeros, forget 1st bit. */ - exponent_4 = exponent_3 + (1 << (exponent_bits - 1)); - /* Offset exponent. */ - - if (exponent_4 & ~mask[exponent_bits]) - { - /* - * Exponent overflow. Lose immediately. - */ - - make_invalid_floating_point_number (words); - - /* - * We leave return_value alone: admit we read the - * number, but return a floating exception - * because we can't encode the number. - */ - } - else - { - lp = words; - - /* Word 1. Sign, exponent and perhaps high bits. */ - /* Assume 2's complement integers. */ - word1 = (((exponent_4 & mask[exponent_bits]) << (15 - exponent_bits)) - | ((f->sign == '+') ? 0 : 0x8000) - | next_bits (15 - exponent_bits)); - *lp++ = word1; - - /* The rest of the words are just mantissa bits. */ - for (; lp < words + precision; lp++) - { - *lp = next_bits (LITTLENUM_NUMBER_OF_BITS); - } - - if (next_bits (1)) - { - /* - * Since the NEXT bit is a 1, round UP the mantissa. - * The cunning design of these hidden-1 floats permits - * us to let the mantissa overflow into the exponent, and - * it 'does the right thing'. However, we lose if the - * highest-order bit of the lowest-order word flips. - * Is that clear? - */ - - unsigned long carry; - - /* - #if (sizeof(carry)) < ((sizeof(bits[0]) * BITS_PER_CHAR) + 2) - Please allow at least 1 more bit in carry than is in a LITTLENUM. - We need that extra bit to hold a carry during a LITTLENUM carry - propagation. Another extra bit (kept 0) will assure us that we - don't get a sticky sign bit after shifting right, and that - permits us to propagate the carry without any masking of bits. - #endif - */ - for (carry = 1, lp--; - carry && (lp >= words); - lp--) - { - carry = *lp + carry; - *lp = carry; - carry >>= LITTLENUM_NUMBER_OF_BITS; - } - - if ((word1 ^ *words) & (1 << (LITTLENUM_NUMBER_OF_BITS - 1))) - { - make_invalid_floating_point_number (words); - /* - * We leave return_value alone: admit we read the - * number, but return a floating exception - * because we can't encode the number. - */ - } - } /* if (we needed to round up) */ - } /* if (exponent overflow) */ - } /* if (0.0e0) */ - } /* if (float_type was OK) */ - return (return_value); -} /* flonum_gen2vax() */ - - -/* JF this used to be in vax.c but this looks like a better place for it */ - -/* - * md_atof() - * - * In: input_line_pointer->the 1st character of a floating-point - * number. - * 1 letter denoting the type of statement that wants a - * binary floating point number returned. - * Address of where to build floating point literal. - * Assumed to be 'big enough'. - * Address of where to return size of literal (in chars). - * - * Out: Input_line_pointer->of next char after floating number. - * Error message, or 0. - * Floating point literal. - * Number of chars we used for the literal. - */ - -#define MAXIMUM_NUMBER_OF_LITTLENUMS (8) /* For .hfloats. */ - -char * -md_atof (what_statement_type, literalP, sizeP) - int what_statement_type; - char *literalP; - int *sizeP; -{ - LITTLENUM_TYPE words[MAXIMUM_NUMBER_OF_LITTLENUMS]; - register char kind_of_float; - register int number_of_chars; - register LITTLENUM_TYPE *littlenumP; - - switch (what_statement_type) - { - case 'F': /* .float */ - case 'f': /* .ffloat */ - kind_of_float = 'f'; - break; - - case 'D': /* .double */ - case 'd': /* .dfloat */ - kind_of_float = 'd'; - break; - - case 'g': /* .gfloat */ - kind_of_float = 'g'; - break; - - case 'h': /* .hfloat */ - kind_of_float = 'h'; - break; - - default: - kind_of_float = 0; - break; - }; - - if (kind_of_float) - { - register LITTLENUM_TYPE *limit; - - input_line_pointer = atof_vax (input_line_pointer, - kind_of_float, - words); - /* - * The atof_vax() builds up 16-bit numbers. - * Since the assembler may not be running on - * a little-endian machine, be very careful about - * converting words to chars. - */ - number_of_chars = atof_vax_sizeof (kind_of_float); - know (number_of_chars <= MAXIMUM_NUMBER_OF_LITTLENUMS * sizeof (LITTLENUM_TYPE)); - limit = words + (number_of_chars / sizeof (LITTLENUM_TYPE)); - for (littlenumP = words; littlenumP < limit; littlenumP++) - { - md_number_to_chars (literalP, *littlenumP, sizeof (LITTLENUM_TYPE)); - literalP += sizeof (LITTLENUM_TYPE); - }; - } - else - { - number_of_chars = 0; - }; - - *sizeP = number_of_chars; - return kind_of_float ? 0 : "Bad call to md_atof()"; -} - -/* end of atof-vax.c */ diff --git a/contrib/binutils/gas/config/e-i386aout.c b/contrib/binutils/gas/config/e-i386aout.c deleted file mode 100644 index 18fdf689c73a1..0000000000000 --- a/contrib/binutils/gas/config/e-i386aout.c +++ /dev/null @@ -1,17 +0,0 @@ -#include "as.h" -#include "emul.h" - -static const char * -i386aout_bfd_name () -{ - abort (); - return NULL; -} - -#define emul_bfd_name i386aout_bfd_name -#define emul_format &aout_format_ops - -#define emul_name "i386aout" -#define emul_struct_name i386aout -#define emul_default_endian 0 -#include "emul-target.h" diff --git a/contrib/binutils/gas/config/e-i386coff.c b/contrib/binutils/gas/config/e-i386coff.c deleted file mode 100644 index afed72886acfa..0000000000000 --- a/contrib/binutils/gas/config/e-i386coff.c +++ /dev/null @@ -1,17 +0,0 @@ -#include "as.h" -#include "emul.h" - -static const char * -i386coff_bfd_name () -{ - abort (); - return NULL; -} - -#define emul_bfd_name i386coff_bfd_name -#define emul_format &coff_format_ops - -#define emul_name "i386coff" -#define emul_struct_name i386coff -#define emul_default_endian 0 -#include "emul-target.h" diff --git a/contrib/binutils/gas/config/e-i386elf.c b/contrib/binutils/gas/config/e-i386elf.c deleted file mode 100644 index a16701e811e18..0000000000000 --- a/contrib/binutils/gas/config/e-i386elf.c +++ /dev/null @@ -1,17 +0,0 @@ -#include "as.h" -#include "emul.h" - -static const char * -i386elf_bfd_name () -{ - abort (); - return NULL; -} - -#define emul_bfd_name i386elf_bfd_name -#define emul_format &elf_format_ops - -#define emul_name "i386elf" -#define emul_struct_name i386elf -#define emul_default_endian 0 -#include "emul-target.h" diff --git a/contrib/binutils/gas/config/i386coff.mt b/contrib/binutils/gas/config/i386coff.mt deleted file mode 100644 index efda833651817..0000000000000 --- a/contrib/binutils/gas/config/i386coff.mt +++ /dev/null @@ -1 +0,0 @@ -TDEFINES=-DI386COFF diff --git a/contrib/binutils/gas/config/obj-aout.c b/contrib/binutils/gas/config/obj-aout.c deleted file mode 100644 index eabbe924e6c9b..0000000000000 --- a/contrib/binutils/gas/config/obj-aout.c +++ /dev/null @@ -1,692 +0,0 @@ -/* a.out object file format - Copyright (C) 1989, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 2000 - 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. */ - -#define OBJ_HEADER "obj-aout.h" - -#include "as.h" -#ifdef BFD_ASSEMBLER -#undef NO_RELOC -#include "aout/aout64.h" -#endif -#include "obstack.h" - -#ifndef BFD_ASSEMBLER -/* in: segT out: N_TYPE bits */ -const short seg_N_TYPE[] = -{ - N_ABS, - N_TEXT, - N_DATA, - N_BSS, - N_UNDF, /* unknown */ - N_UNDF, /* error */ - N_UNDF, /* expression */ - N_UNDF, /* debug */ - N_UNDF, /* ntv */ - N_UNDF, /* ptv */ - N_REGISTER, /* register */ -}; - -const segT N_TYPE_seg[N_TYPE + 2] = -{ /* N_TYPE == 0x1E = 32-2 */ - SEG_UNKNOWN, /* N_UNDF == 0 */ - SEG_GOOF, - SEG_ABSOLUTE, /* N_ABS == 2 */ - SEG_GOOF, - SEG_TEXT, /* N_TEXT == 4 */ - SEG_GOOF, - SEG_DATA, /* N_DATA == 6 */ - SEG_GOOF, - SEG_BSS, /* N_BSS == 8 */ - SEG_GOOF, - SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, - SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, - SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, - SEG_REGISTER, /* dummy N_REGISTER for regs = 30 */ - SEG_GOOF, -}; -#endif - -static void obj_aout_line PARAMS ((int)); -static void obj_aout_weak PARAMS ((int)); -static void obj_aout_type PARAMS ((int)); - -const pseudo_typeS aout_pseudo_table[] = -{ - {"line", obj_aout_line, 0}, /* source code line number */ - {"ln", obj_aout_line, 0}, /* coff line number that we use anyway */ - - {"weak", obj_aout_weak, 0}, /* mark symbol as weak. */ - - {"type", obj_aout_type, 0}, - - /* coff debug pseudos (ignored) */ - {"def", s_ignore, 0}, - {"dim", s_ignore, 0}, - {"endef", s_ignore, 0}, - {"ident", s_ignore, 0}, - {"line", s_ignore, 0}, - {"ln", s_ignore, 0}, - {"scl", s_ignore, 0}, - {"size", s_ignore, 0}, - {"tag", s_ignore, 0}, - {"val", s_ignore, 0}, - {"version", s_ignore, 0}, - - {"optim", s_ignore, 0}, /* For sun386i cc (?) */ - - /* other stuff */ - {"ABORT", s_abort, 0}, - - {NULL, NULL, 0} /* end sentinel */ -}; /* aout_pseudo_table */ - - -#ifdef BFD_ASSEMBLER - -void -obj_aout_frob_symbol (sym, punt) - symbolS *sym; - int *punt; -{ - flagword flags; - asection *sec; - int desc, type, other; - - flags = symbol_get_bfdsym (sym)->flags; - desc = aout_symbol (symbol_get_bfdsym (sym))->desc; - type = aout_symbol (symbol_get_bfdsym (sym))->type; - other = aout_symbol (symbol_get_bfdsym (sym))->other; - sec = S_GET_SEGMENT (sym); - - /* Only frob simple symbols this way right now. */ - if (! (type & ~ (N_TYPE | N_EXT))) - { - if (type == (N_UNDF | N_EXT) - && sec == &bfd_abs_section) - { - sec = bfd_und_section_ptr; - S_SET_SEGMENT (sym, sec); - } - - if ((type & N_TYPE) != N_INDR - && (type & N_TYPE) != N_SETA - && (type & N_TYPE) != N_SETT - && (type & N_TYPE) != N_SETD - && (type & N_TYPE) != N_SETB - && type != N_WARNING - && (sec == &bfd_abs_section - || sec == &bfd_und_section)) - return; - if (flags & BSF_EXPORT) - type |= N_EXT; - - switch (type & N_TYPE) - { - case N_SETA: - case N_SETT: - case N_SETD: - case N_SETB: - /* Set the debugging flag for constructor symbols so that - BFD leaves them alone. */ - symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING; - - /* You can't put a common symbol in a set. The way a set - element works is that the symbol has a definition and a - name, and the linker adds the definition to the set of - that name. That does not work for a common symbol, - because the linker can't tell which common symbol the - user means. FIXME: Using as_bad here may be - inappropriate, since the user may want to force a - particular type without regard to the semantics of sets; - on the other hand, we certainly don't want anybody to be - mislead into thinking that their code will work. */ - if (S_IS_COMMON (sym)) - as_bad (_("Attempt to put a common symbol into set %s"), - S_GET_NAME (sym)); - /* Similarly, you can't put an undefined symbol in a set. */ - else if (! S_IS_DEFINED (sym)) - as_bad (_("Attempt to put an undefined symbol into set %s"), - S_GET_NAME (sym)); - - break; - case N_INDR: - /* Put indirect symbols in the indirect section. */ - S_SET_SEGMENT (sym, bfd_ind_section_ptr); - symbol_get_bfdsym (sym)->flags |= BSF_INDIRECT; - if (type & N_EXT) - { - symbol_get_bfdsym (sym)->flags |= BSF_EXPORT; - symbol_get_bfdsym (sym)->flags &=~ BSF_LOCAL; - } - break; - case N_WARNING: - /* Mark warning symbols. */ - symbol_get_bfdsym (sym)->flags |= BSF_WARNING; - break; - } - } - else - { - symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING; - } - - aout_symbol (symbol_get_bfdsym (sym))->type = type; - - /* Double check weak symbols. */ - if (S_IS_WEAK (sym)) - { - if (S_IS_COMMON (sym)) - as_bad (_("Symbol `%s' can not be both weak and common"), - S_GET_NAME (sym)); - } -} - -void -obj_aout_frob_file () -{ - /* Relocation processing may require knowing the VMAs of the sections. - Since writing to a section will cause the BFD back end to compute the - VMAs, fake it out here.... */ - bfd_byte b = 0; - boolean x = true; - if (bfd_section_size (stdoutput, text_section) != 0) - { - x = bfd_set_section_contents (stdoutput, text_section, &b, (file_ptr) 0, - (bfd_size_type) 1); - } - else if (bfd_section_size (stdoutput, data_section) != 0) - { - x = bfd_set_section_contents (stdoutput, data_section, &b, (file_ptr) 0, - (bfd_size_type) 1); - } - assert (x == true); -} - -#else /* ! BFD_ASSEMBLER */ - -/* Relocation. */ - -/* - * emit_relocations() - * - * Crawl along a fixS chain. Emit the segment's relocations. - */ -void -obj_emit_relocations (where, fixP, segment_address_in_file) - char **where; - fixS *fixP; /* Fixup chain for this segment. */ - relax_addressT segment_address_in_file; -{ - for (; fixP; fixP = fixP->fx_next) - if (fixP->fx_done == 0) - { - symbolS *sym; - - sym = fixP->fx_addsy; - while (sym->sy_value.X_op == O_symbol - && (! S_IS_DEFINED (sym) || S_IS_COMMON (sym))) - sym = sym->sy_value.X_add_symbol; - fixP->fx_addsy = sym; - - if (! sym->sy_resolved && ! S_IS_DEFINED (sym)) - { - char *file; - unsigned int line; - - if (expr_symbol_where (sym, &file, &line)) - as_bad_where (file, line, _("unresolved relocation")); - else - as_bad (_("bad relocation: symbol `%s' not in symbol table"), - S_GET_NAME (sym)); - } - - tc_aout_fix_to_chars (*where, fixP, segment_address_in_file); - *where += md_reloc_size; - } -} - -#ifndef obj_header_append -/* Aout file generation & utilities */ -void -obj_header_append (where, headers) - char **where; - object_headers *headers; -{ - tc_headers_hook (headers); - -#ifdef CROSS_COMPILE - md_number_to_chars (*where, headers->header.a_info, sizeof (headers->header.a_info)); - *where += sizeof (headers->header.a_info); - md_number_to_chars (*where, headers->header.a_text, sizeof (headers->header.a_text)); - *where += sizeof (headers->header.a_text); - md_number_to_chars (*where, headers->header.a_data, sizeof (headers->header.a_data)); - *where += sizeof (headers->header.a_data); - md_number_to_chars (*where, headers->header.a_bss, sizeof (headers->header.a_bss)); - *where += sizeof (headers->header.a_bss); - md_number_to_chars (*where, headers->header.a_syms, sizeof (headers->header.a_syms)); - *where += sizeof (headers->header.a_syms); - md_number_to_chars (*where, headers->header.a_entry, sizeof (headers->header.a_entry)); - *where += sizeof (headers->header.a_entry); - md_number_to_chars (*where, headers->header.a_trsize, sizeof (headers->header.a_trsize)); - *where += sizeof (headers->header.a_trsize); - md_number_to_chars (*where, headers->header.a_drsize, sizeof (headers->header.a_drsize)); - *where += sizeof (headers->header.a_drsize); - -#else /* CROSS_COMPILE */ - - append (where, (char *) &headers->header, sizeof (headers->header)); -#endif /* CROSS_COMPILE */ - -} -#endif /* ! defined (obj_header_append) */ - -void -obj_symbol_to_chars (where, symbolP) - char **where; - symbolS *symbolP; -{ - md_number_to_chars ((char *) &(S_GET_OFFSET (symbolP)), S_GET_OFFSET (symbolP), sizeof (S_GET_OFFSET (symbolP))); - md_number_to_chars ((char *) &(S_GET_DESC (symbolP)), S_GET_DESC (symbolP), sizeof (S_GET_DESC (symbolP))); - md_number_to_chars ((char *) &(symbolP->sy_symbol.n_value), S_GET_VALUE (symbolP), sizeof (symbolP->sy_symbol.n_value)); - - append (where, (char *) &symbolP->sy_symbol, sizeof (obj_symbol_type)); -} - -void -obj_emit_symbols (where, symbol_rootP) - char **where; - symbolS *symbol_rootP; -{ - symbolS *symbolP; - - /* Emit all symbols left in the symbol chain. */ - for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP)) - { - /* Used to save the offset of the name. It is used to point - to the string in memory but must be a file offset. */ - register char *temp; - - temp = S_GET_NAME (symbolP); - S_SET_OFFSET (symbolP, symbolP->sy_name_offset); - - /* Any symbol still undefined and is not a dbg symbol is made N_EXT. */ - if (!S_IS_DEBUG (symbolP) && !S_IS_DEFINED (symbolP)) - S_SET_EXTERNAL (symbolP); - - /* Adjust the type of a weak symbol. */ - if (S_GET_WEAK (symbolP)) - { - switch (S_GET_TYPE (symbolP)) - { - case N_UNDF: S_SET_TYPE (symbolP, N_WEAKU); break; - case N_ABS: S_SET_TYPE (symbolP, N_WEAKA); break; - case N_TEXT: S_SET_TYPE (symbolP, N_WEAKT); break; - case N_DATA: S_SET_TYPE (symbolP, N_WEAKD); break; - case N_BSS: S_SET_TYPE (symbolP, N_WEAKB); break; - default: as_bad (_("%s: bad type for weak symbol"), temp); break; - } - } - - obj_symbol_to_chars (where, symbolP); - S_SET_NAME (symbolP, temp); - } -} - -#endif /* ! BFD_ASSEMBLER */ - -static void -obj_aout_line (ignore) - int ignore; -{ - /* Assume delimiter is part of expression. - BSD4.2 as fails with delightful bug, so we - are not being incompatible here. */ - new_logical_line ((char *) NULL, (int) (get_absolute_expression ())); - demand_empty_rest_of_line (); -} /* obj_aout_line() */ - -/* Handle .weak. This is a GNU extension. */ - -static void -obj_aout_weak (ignore) - int ignore; -{ - char *name; - int c; - symbolS *symbolP; - - do - { - name = input_line_pointer; - c = get_symbol_end (); - symbolP = symbol_find_or_make (name); - *input_line_pointer = c; - SKIP_WHITESPACE (); - S_SET_WEAK (symbolP); - if (c == ',') - { - input_line_pointer++; - SKIP_WHITESPACE (); - if (*input_line_pointer == '\n') - c = '\n'; - } - } - while (c == ','); - demand_empty_rest_of_line (); -} - -/* Handle .type. On {Net,Open}BSD, this is used to set the n_other field, - which is then apparently used when doing dynamic linking. Older - versions ogas ignored the .type pseudo-op, so we also ignore it if - we can't parse it. */ - -static void -obj_aout_type (ignore) - int ignore; -{ - char *name; - int c; - symbolS *sym; - - name = input_line_pointer; - c = get_symbol_end (); - sym = symbol_find (name); - *input_line_pointer = c; - if (sym != NULL) - { - SKIP_WHITESPACE (); - if (*input_line_pointer == ',') - { - ++input_line_pointer; - SKIP_WHITESPACE (); - if (*input_line_pointer == '@') - { - ++input_line_pointer; - if (strncmp (input_line_pointer, "object", 6) == 0) -#ifdef BFD_ASSEMBLER - aout_symbol (symbol_get_bfdsym (sym))->other = 1; -#else - S_SET_OTHER (sym, 1); -#endif - else if (strncmp (input_line_pointer, "function", 8) == 0) -#ifdef BFD_ASSEMBLER - aout_symbol (symbol_get_bfdsym (sym))->other = 2; -#else - S_SET_OTHER (sym, 2); -#endif - } - } - } - - /* Ignore everything else on the line. */ - s_ignore (0); -} - -#ifndef BFD_ASSEMBLER - -void -obj_crawl_symbol_chain (headers) - object_headers *headers; -{ - symbolS *symbolP; - symbolS **symbolPP; - int symbol_number = 0; - - tc_crawl_symbol_chain (headers); - - symbolPP = &symbol_rootP; /*->last symbol chain link. */ - while ((symbolP = *symbolPP) != NULL) - { - if (symbolP->sy_mri_common) - { - if (S_IS_EXTERNAL (symbolP)) - as_bad (_("%s: global symbols not supported in common sections"), - S_GET_NAME (symbolP)); - *symbolPP = symbol_next (symbolP); - continue; - } - - if (flag_readonly_data_in_text && (S_GET_SEGMENT (symbolP) == SEG_DATA)) - { - S_SET_SEGMENT (symbolP, SEG_TEXT); - } /* if pusing data into text */ - - resolve_symbol_value (symbolP, 1); - - /* Skip symbols which were equated to undefined or common - symbols. */ - if (symbolP->sy_value.X_op == O_symbol - && (! S_IS_DEFINED (symbolP) || S_IS_COMMON (symbolP))) - { - *symbolPP = symbol_next (symbolP); - continue; - } - - /* OK, here is how we decide which symbols go out into the brave - new symtab. Symbols that do are: - - * symbols with no name (stabd's?) - * symbols with debug info in their N_TYPE - - Symbols that don't are: - * symbols that are registers - * symbols with \1 as their 3rd character (numeric labels) - * "local labels" as defined by S_LOCAL_NAME(name) if the -L - switch was passed to gas. - - All other symbols are output. We complain if a deleted - symbol was marked external. */ - - - if (!S_IS_REGISTER (symbolP) - && (!S_GET_NAME (symbolP) - || S_IS_DEBUG (symbolP) - || !S_IS_DEFINED (symbolP) - || S_IS_EXTERNAL (symbolP) - || (S_GET_NAME (symbolP)[0] != '\001' - && (flag_keep_locals || !S_LOCAL_NAME (symbolP))))) - { - symbolP->sy_number = symbol_number++; - - /* The + 1 after strlen account for the \0 at the - end of each string */ - if (!S_IS_STABD (symbolP)) - { - /* Ordinary case. */ - symbolP->sy_name_offset = string_byte_count; - string_byte_count += strlen (S_GET_NAME (symbolP)) + 1; - } - else /* .Stabd case. */ - symbolP->sy_name_offset = 0; - symbolPP = &symbolP->sy_next; - } - else - { - if (S_IS_EXTERNAL (symbolP) || !S_IS_DEFINED (symbolP)) - /* This warning should never get triggered any more. - Well, maybe if you're doing twisted things with - register names... */ - { - as_bad (_("Local symbol %s never defined."), decode_local_label_name (S_GET_NAME (symbolP))); - } /* oops. */ - - /* Unhook it from the chain */ - *symbolPP = symbol_next (symbolP); - } /* if this symbol should be in the output */ - } /* for each symbol */ - - H_SET_SYMBOL_TABLE_SIZE (headers, symbol_number); -} - -/* - * Find strings by crawling along symbol table chain. - */ - -void -obj_emit_strings (where) - char **where; -{ - symbolS *symbolP; - -#ifdef CROSS_COMPILE - /* Gotta do md_ byte-ordering stuff for string_byte_count first - KWK */ - md_number_to_chars (*where, string_byte_count, sizeof (string_byte_count)); - *where += sizeof (string_byte_count); -#else /* CROSS_COMPILE */ - append (where, (char *) &string_byte_count, (unsigned long) sizeof (string_byte_count)); -#endif /* CROSS_COMPILE */ - - for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP)) - { - if (S_GET_NAME (symbolP)) - append (&next_object_file_charP, S_GET_NAME (symbolP), - (unsigned long) (strlen (S_GET_NAME (symbolP)) + 1)); - } /* walk symbol chain */ -} - -#ifndef AOUT_VERSION -#define AOUT_VERSION 0 -#endif - -void -obj_pre_write_hook (headers) - object_headers *headers; -{ - H_SET_DYNAMIC (headers, 0); - H_SET_VERSION (headers, AOUT_VERSION); - H_SET_MACHTYPE (headers, AOUT_MACHTYPE); - tc_aout_pre_write_hook (headers); -} - -void -DEFUN_VOID (s_sect) -{ - /* Strip out the section name */ - char *section_name; - char *section_name_end; - char c; - - unsigned int len; - unsigned int exp; - char *save; - - section_name = input_line_pointer; - c = get_symbol_end (); - section_name_end = input_line_pointer; - - len = section_name_end - section_name; - input_line_pointer++; - save = input_line_pointer; - - SKIP_WHITESPACE (); - if (c == ',') - { - exp = get_absolute_expression (); - } - else if (*input_line_pointer == ',') - { - input_line_pointer++; - exp = get_absolute_expression (); - } - else - { - input_line_pointer = save; - exp = 0; - } - if (exp >= 1000) - { - as_bad (_("subsegment index too high")); - } - - if (strcmp (section_name, ".text") == 0) - { - subseg_set (SEG_TEXT, (subsegT) exp); - } - - if (strcmp (section_name, ".data") == 0) - { - if (flag_readonly_data_in_text) - subseg_set (SEG_TEXT, (subsegT) exp + 1000); - else - subseg_set (SEG_DATA, (subsegT) exp); - } - - *section_name_end = c; -} - -#endif /* ! BFD_ASSEMBLER */ - -#ifdef BFD_ASSEMBLER - -/* Support for an AOUT emulation. */ - -static void aout_pop_insert PARAMS ((void)); -static int obj_aout_s_get_other PARAMS ((symbolS *)); -static int obj_aout_s_get_desc PARAMS ((symbolS *)); - -static void -aout_pop_insert () -{ - pop_insert (aout_pseudo_table); -} - -static int -obj_aout_s_get_other (sym) - symbolS *sym; -{ - return aout_symbol (symbol_get_bfdsym (sym))->other; -} - -static int -obj_aout_s_get_desc (sym) - symbolS *sym; -{ - return aout_symbol (symbol_get_bfdsym (sym))->desc; -} - - -const struct format_ops aout_format_ops = -{ - bfd_target_aout_flavour, - 1, /* dfl_leading_underscore */ - 0, /* emit_section_symbols */ - obj_aout_frob_symbol, - obj_aout_frob_file, - 0, /* frob_file_after_relocs */ - 0, /* s_get_size */ - 0, /* s_set_size */ - 0, /* s_get_align */ - 0, /* s_set_align */ - obj_aout_s_get_other, - obj_aout_s_get_desc, - 0, /* copy_symbol_attributes */ - 0, /* generate_asm_lineno */ - 0, /* process_stab */ - 0, /* sec_sym_ok_for_reloc */ - aout_pop_insert, - 0, /* ecoff_set_ext */ - 0, /* read_begin_hook */ - 0 /* symbol_new_hook */ -}; -#endif BFD_ASSEMBLER - -/* end of obj-aout.c */ diff --git a/contrib/binutils/gas/config/obj-aout.h b/contrib/binutils/gas/config/obj-aout.h deleted file mode 100644 index d08302a49bf49..0000000000000 --- a/contrib/binutils/gas/config/obj-aout.h +++ /dev/null @@ -1,252 +0,0 @@ -/* obj-aout.h, a.out object file format for gas, the assembler. - Copyright (C) 1989, 90, 91, 92, 93, 94, 95, 96, 98, 99, 2000 - 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. */ - -/* Tag to validate a.out object file format processing */ -#define OBJ_AOUT 1 - -#include "targ-cpu.h" - -#ifdef BFD_ASSEMBLER - -#include "bfd/libaout.h" - -#define OUTPUT_FLAVOR bfd_target_aout_flavour - -#else /* ! BFD_ASSEMBLER */ - -#ifndef VMS -#include "aout_gnu.h" /* Needed to define struct nlist. Sigh. */ -#else -#include "a_out.h" -#endif - -#ifndef AOUT_MACHTYPE -#define AOUT_MACHTYPE 0 -#endif /* AOUT_MACHTYPE */ - -extern const short seg_N_TYPE[]; -extern const segT N_TYPE_seg[]; - -#ifndef DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE -#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE (OMAGIC) -#endif /* DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE */ - -#endif /* ! BFD_ASSEMBLER */ - -extern const pseudo_typeS aout_pseudo_table[]; - -#ifndef obj_pop_insert -#define obj_pop_insert() pop_insert (aout_pseudo_table) -#endif - -/* SYMBOL TABLE */ -/* Symbol table entry data type */ - -typedef struct nlist obj_symbol_type; /* Symbol table entry */ - -/* Symbol table macros and constants */ - -#ifdef BFD_ASSEMBLER - -#define S_SET_OTHER(S,V) \ - (aout_symbol (symbol_get_bfdsym (S))->other = (V)) -#define S_SET_TYPE(S,T) \ - (aout_symbol (symbol_get_bfdsym (S))->type = (T)) -#define S_SET_DESC(S,D) \ - (aout_symbol (symbol_get_bfdsym (S))->desc = (D)) -#define S_GET_OTHER(S) \ - (aout_symbol (symbol_get_bfdsym (S))->other) -#define S_GET_TYPE(S) \ - (aout_symbol (symbol_get_bfdsym (S))->type) -#define S_GET_DESC(S) \ - (aout_symbol (symbol_get_bfdsym (S))->desc) - -asection *text_section, *data_section, *bss_section; - -#define obj_frob_symbol(S,PUNT) obj_aout_frob_symbol (S, &PUNT) -#define obj_frob_file() obj_aout_frob_file () -extern void obj_aout_frob_symbol PARAMS ((symbolS *, int *)); -extern void obj_aout_frob_file PARAMS ((void)); - -#define obj_sec_sym_ok_for_reloc(SEC) (1) - -#else - -/* We use the sy_obj field to record whether a symbol is weak. */ -#define OBJ_SYMFIELD_TYPE char - -/* - * Macros to extract information from a symbol table entry. - * This syntaxic indirection allows independence regarding a.out or coff. - * The argument (s) of all these macros is a pointer to a symbol table entry. - */ - -/* True if the symbol is external */ -#define S_IS_EXTERNAL(s) ((s)->sy_symbol.n_type & N_EXT) - -/* True if symbol has been defined, ie is in N_{TEXT,DATA,BSS,ABS} or N_EXT */ -#define S_IS_DEFINED(s) \ - (S_GET_TYPE (s) != N_UNDF || S_GET_DESC (s) != 0) - -#define S_IS_COMMON(s) \ - (S_GET_TYPE (s) == N_UNDF && S_GET_VALUE (s) != 0) - -#define S_IS_REGISTER(s) ((s)->sy_symbol.n_type == N_REGISTER) - -/* True if a debug special symbol entry */ -#define S_IS_DEBUG(s) ((s)->sy_symbol.n_type & N_STAB) -/* True if a symbol is local symbol name */ -#define S_IS_LOCAL(s) \ - ((S_GET_NAME (s) \ - && !S_IS_DEBUG (s) \ - && (strchr (S_GET_NAME (s), '\001') != NULL \ - || strchr (S_GET_NAME (s), '\002') != NULL \ - || (S_LOCAL_NAME(s) && !flag_keep_locals))) \ - || (flag_strip_local_absolute \ - && ! S_IS_EXTERNAL(s) \ - && S_GET_SEGMENT (s) == absolute_section)) -/* True if a symbol is not defined in this file */ -#define S_IS_EXTERN(s) ((s)->sy_symbol.n_type & N_EXT) -/* True if the symbol has been generated because of a .stabd directive */ -#define S_IS_STABD(s) (S_GET_NAME(s) == (char *)0) - -/* Accessors */ -/* The name of the symbol */ -#define S_GET_NAME(s) ((s)->sy_symbol.n_un.n_name) -/* The pointer to the string table */ -#define S_GET_OFFSET(s) ((s)->sy_symbol.n_un.n_strx) -/* The type of the symbol */ -#define S_GET_TYPE(s) ((s)->sy_symbol.n_type & N_TYPE) -/* The numeric value of the segment */ -#define S_GET_SEGMENT(s) (N_TYPE_seg[S_GET_TYPE(s)]) -/* The n_other expression value */ -#define S_GET_OTHER(s) ((s)->sy_symbol.n_other) -/* The n_desc expression value */ -#define S_GET_DESC(s) ((s)->sy_symbol.n_desc) -/* Whether the symbol is weak. */ -#define S_GET_WEAK(s) ((s)->sy_obj) - -/* Modifiers */ -/* Assume that a symbol cannot be simultaneously in more than on segment */ -/* set segment */ -#define S_SET_SEGMENT(s,seg) ((s)->sy_symbol.n_type &= ~N_TYPE,(s)->sy_symbol.n_type|=SEGMENT_TO_SYMBOL_TYPE(seg)) -/* The symbol is external */ -#define S_SET_EXTERNAL(s) ((s)->sy_symbol.n_type |= N_EXT) -/* The symbol is not external */ -#define S_CLEAR_EXTERNAL(s) ((s)->sy_symbol.n_type &= ~N_EXT) -/* Set the name of the symbol */ -#define S_SET_NAME(s,v) ((s)->sy_symbol.n_un.n_name = (v)) -/* Set the offset in the string table */ -#define S_SET_OFFSET(s,v) ((s)->sy_symbol.n_un.n_strx = (v)) -/* Set the n_type field */ -#define S_SET_TYPE(s,t) ((s)->sy_symbol.n_type = (t)) -/* Set the n_other expression value */ -#define S_SET_OTHER(s,v) ((s)->sy_symbol.n_other = (v)) -/* Set the n_desc expression value */ -#define S_SET_DESC(s,v) ((s)->sy_symbol.n_desc = (v)) -/* Mark the symbol as weak. This causes n_type to be adjusted when - the symbol is written out. */ -#define S_SET_WEAK(s) ((s)->sy_obj = 1) - -/* File header macro and type definition */ - -#define H_GET_FILE_SIZE(h) (H_GET_HEADER_SIZE(h) \ - + H_GET_TEXT_SIZE(h) \ - + H_GET_DATA_SIZE(h) \ - + H_GET_SYMBOL_TABLE_SIZE(h) \ - + H_GET_TEXT_RELOCATION_SIZE(h) \ - + H_GET_DATA_RELOCATION_SIZE(h) \ - + H_GET_STRING_SIZE(h)) - -#define H_GET_HEADER_SIZE(h) (EXEC_BYTES_SIZE) -#define H_GET_TEXT_SIZE(h) ((h)->header.a_text) -#define H_GET_DATA_SIZE(h) ((h)->header.a_data) -#define H_GET_BSS_SIZE(h) ((h)->header.a_bss) -#define H_GET_TEXT_RELOCATION_SIZE(h) ((h)->header.a_trsize) -#define H_GET_DATA_RELOCATION_SIZE(h) ((h)->header.a_drsize) -#define H_GET_SYMBOL_TABLE_SIZE(h) ((h)->header.a_syms) -#define H_GET_ENTRY_POINT(h) ((h)->header.a_entry) -#define H_GET_STRING_SIZE(h) ((h)->string_table_size) -#define H_GET_LINENO_SIZE(h) (0) - -#define H_GET_DYNAMIC(h) ((h)->header.a_info >> 31) -#define H_GET_VERSION(h) (((h)->header.a_info >> 24) & 0x7f) -#define H_GET_MACHTYPE(h) (((h)->header.a_info >> 16) & 0xff) -#define H_GET_MAGIC_NUMBER(h) ((h)->header.a_info & 0xffff) - -#define H_SET_DYNAMIC(h,v) ((h)->header.a_info = (((v) << 31) \ - | (H_GET_VERSION(h) << 24) \ - | (H_GET_MACHTYPE(h) << 16) \ - | (H_GET_MAGIC_NUMBER(h)))) - -#define H_SET_VERSION(h,v) ((h)->header.a_info = ((H_GET_DYNAMIC(h) << 31) \ - | ((v) << 24) \ - | (H_GET_MACHTYPE(h) << 16) \ - | (H_GET_MAGIC_NUMBER(h)))) - -#define H_SET_MACHTYPE(h,v) ((h)->header.a_info = ((H_GET_DYNAMIC(h) << 31) \ - | (H_GET_VERSION(h) << 24) \ - | ((v) << 16) \ - | (H_GET_MAGIC_NUMBER(h)))) - -#define H_SET_MAGIC_NUMBER(h,v) ((h)->header.a_info = ((H_GET_DYNAMIC(h) << 31) \ - | (H_GET_VERSION(h) << 24) \ - | (H_GET_MACHTYPE(h) << 16) \ - | ((v)))) - -#define H_SET_TEXT_SIZE(h,v) ((h)->header.a_text = md_section_align(SEG_TEXT, (v))) -#define H_SET_DATA_SIZE(h,v) ((h)->header.a_data = md_section_align(SEG_DATA, (v))) -#define H_SET_BSS_SIZE(h,v) ((h)->header.a_bss = md_section_align(SEG_BSS, (v))) - -#define H_SET_RELOCATION_SIZE(h,t,d) (H_SET_TEXT_RELOCATION_SIZE((h),(t)),\ - H_SET_DATA_RELOCATION_SIZE((h),(d))) - -#define H_SET_TEXT_RELOCATION_SIZE(h,v) ((h)->header.a_trsize = (v)) -#define H_SET_DATA_RELOCATION_SIZE(h,v) ((h)->header.a_drsize = (v)) -#define H_SET_SYMBOL_TABLE_SIZE(h,v) ((h)->header.a_syms = (v) * 12) - -#define H_SET_ENTRY_POINT(h,v) ((h)->header.a_entry = (v)) -#define H_SET_STRING_SIZE(h,v) ((h)->string_table_size = (v)) - -typedef struct - { - struct exec header; /* a.out header */ - long string_table_size; /* names + '\0' + sizeof(int) */ - } - -object_headers; - -/* line numbering stuff. */ -#define OBJ_EMIT_LINENO(a, b, c) {;} - -struct fix; -void tc_aout_fix_to_chars PARAMS ((char *where, struct fix *fixP, relax_addressT segment_address)); - -#endif - -#define obj_read_begin_hook() {;} -#define obj_symbol_new_hook(s) {;} - -#define EMIT_SECTION_SYMBOLS 0 - -#define AOUT_STABS - -/* end of obj-aout.h */ diff --git a/contrib/binutils/gas/config/obj-coff.c b/contrib/binutils/gas/config/obj-coff.c deleted file mode 100644 index d7508680336ae..0000000000000 --- a/contrib/binutils/gas/config/obj-coff.c +++ /dev/null @@ -1,4616 +0,0 @@ -/* coff object file format - Copyright (C) 1989, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 2000 - Free Software Foundation, Inc. - - This file is part of GAS. - - 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. */ - -#define OBJ_HEADER "obj-coff.h" - -#include "as.h" -#include "obstack.h" -#include "subsegs.h" - -/* I think this is probably always correct. */ -#ifndef KEEP_RELOC_INFO -#define KEEP_RELOC_INFO -#endif - -static void obj_coff_bss PARAMS ((int)); -const char *s_get_name PARAMS ((symbolS * s)); -static void obj_coff_ln PARAMS ((int)); -static void obj_coff_def PARAMS ((int)); -static void obj_coff_endef PARAMS ((int)); -static void obj_coff_dim PARAMS ((int)); -static void obj_coff_line PARAMS ((int)); -static void obj_coff_size PARAMS ((int)); -static void obj_coff_scl PARAMS ((int)); -static void obj_coff_tag PARAMS ((int)); -static void obj_coff_val PARAMS ((int)); -static void obj_coff_type PARAMS ((int)); -static void obj_coff_ident PARAMS ((int)); -#ifdef BFD_ASSEMBLER -static void obj_coff_loc PARAMS((int)); -#endif - -/* This is used to hold the symbol built by a sequence of pseudo-ops - from .def and .endef. */ -static symbolS *def_symbol_in_progress; - -/* stack stuff */ -typedef struct - { - unsigned long chunk_size; - unsigned long element_size; - unsigned long size; - char *data; - unsigned long pointer; - } -stack; - -static stack * -stack_init (chunk_size, element_size) - unsigned long chunk_size; - unsigned long element_size; -{ - stack *st; - - st = (stack *) malloc (sizeof (stack)); - if (!st) - return 0; - st->data = malloc (chunk_size); - if (!st->data) - { - free (st); - return 0; - } - st->pointer = 0; - st->size = chunk_size; - st->chunk_size = chunk_size; - st->element_size = element_size; - return st; -} - -#if 0 -/* Not currently used. */ -static void -stack_delete (st) - stack *st; -{ - free (st->data); - free (st); -} -#endif - -static char * -stack_push (st, element) - stack *st; - char *element; -{ - if (st->pointer + st->element_size >= st->size) - { - st->size += st->chunk_size; - if ((st->data = xrealloc (st->data, st->size)) == (char *) 0) - return (char *) 0; - } - memcpy (st->data + st->pointer, element, st->element_size); - st->pointer += st->element_size; - return st->data + st->pointer; -} - -static char * -stack_pop (st) - stack *st; -{ - if (st->pointer < st->element_size) - { - st->pointer = 0; - return (char *) 0; - } - st->pointer -= st->element_size; - return st->data + st->pointer; -} - -/* - * Maintain a list of the tagnames of the structres. - */ - -static struct hash_control *tag_hash; - -static void -tag_init () -{ - tag_hash = hash_new (); -} - -static void -tag_insert (name, symbolP) - const char *name; - symbolS *symbolP; -{ - const char *error_string; - - if ((error_string = hash_jam (tag_hash, name, (char *) symbolP))) - { - as_fatal (_("Inserting \"%s\" into structure table failed: %s"), - name, error_string); - } -} - -static symbolS * -tag_find (name) - char *name; -{ -#ifdef STRIP_UNDERSCORE - if (*name == '_') - name++; -#endif /* STRIP_UNDERSCORE */ - return (symbolS *) hash_find (tag_hash, name); -} - -static symbolS * -tag_find_or_make (name) - char *name; -{ - symbolS *symbolP; - - if ((symbolP = tag_find (name)) == NULL) - { - symbolP = symbol_new (name, undefined_section, - 0, &zero_address_frag); - - tag_insert (S_GET_NAME (symbolP), symbolP); -#ifdef BFD_ASSEMBLER - symbol_table_insert (symbolP); -#endif - } /* not found */ - - return symbolP; -} - -/* We accept the .bss directive to set the section for backward - compatibility with earlier versions of gas. */ - -static void -obj_coff_bss (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - if (*input_line_pointer == '\n') - subseg_new (".bss", get_absolute_expression ()); - else - s_lcomm (0); -} - -/* Handle .weak. This is a GNU extension. */ - -static void -obj_coff_weak (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - char *name; - int c; - symbolS *symbolP; - - do - { - name = input_line_pointer; - c = get_symbol_end (); - symbolP = symbol_find_or_make (name); - *input_line_pointer = c; - SKIP_WHITESPACE (); - -#ifdef BFD_ASSEMLER - S_SET_WEAK (symbolP); -#endif - -#ifdef TE_PE - S_SET_STORAGE_CLASS (symbolP, C_NT_WEAK); -#else - S_SET_STORAGE_CLASS (symbolP, C_WEAKEXT); -#endif - - if (c == ',') - { - input_line_pointer++; - SKIP_WHITESPACE (); - if (*input_line_pointer == '\n') - c = '\n'; - } - } - while (c == ','); - - demand_empty_rest_of_line (); -} - -#ifdef BFD_ASSEMBLER - -static void SA_SET_SYM_TAGNDX PARAMS ((symbolS *, symbolS *)); - -#define GET_FILENAME_STRING(X) \ -((char*)(&((X)->sy_symbol.ost_auxent->x_file.x_n.x_offset))[1]) - -/* @@ Ick. */ -static segT -fetch_coff_debug_section () -{ - static segT debug_section; - if (!debug_section) - { - CONST asymbol *s; - s = bfd_make_debug_symbol (stdoutput, (char *) 0, 0); - assert (s != 0); - debug_section = s->section; - } - return debug_section; -} - -void -SA_SET_SYM_ENDNDX (sym, val) - symbolS *sym; - symbolS *val; -{ - combined_entry_type *entry, *p; - - entry = &coffsymbol (symbol_get_bfdsym (sym))->native[1]; - p = coffsymbol (symbol_get_bfdsym (val))->native; - entry->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.p = p; - entry->fix_end = 1; -} - -static void -SA_SET_SYM_TAGNDX (sym, val) - symbolS *sym; - symbolS *val; -{ - combined_entry_type *entry, *p; - - entry = &coffsymbol (symbol_get_bfdsym (sym))->native[1]; - p = coffsymbol (symbol_get_bfdsym (val))->native; - entry->u.auxent.x_sym.x_tagndx.p = p; - entry->fix_tag = 1; -} - -static int -S_GET_DATA_TYPE (sym) - symbolS *sym; -{ - return coffsymbol (symbol_get_bfdsym (sym))->native->u.syment.n_type; -} - -int -S_SET_DATA_TYPE (sym, val) - symbolS *sym; - int val; -{ - coffsymbol (symbol_get_bfdsym (sym))->native->u.syment.n_type = val; - return val; -} - -int -S_GET_STORAGE_CLASS (sym) - symbolS *sym; -{ - return coffsymbol (symbol_get_bfdsym (sym))->native->u.syment.n_sclass; -} - -int -S_SET_STORAGE_CLASS (sym, val) - symbolS *sym; - int val; -{ - coffsymbol (symbol_get_bfdsym (sym))->native->u.syment.n_sclass = val; - return val; -} - -/* Merge a debug symbol containing debug information into a normal symbol. */ - -void -c_symbol_merge (debug, normal) - symbolS *debug; - symbolS *normal; -{ - S_SET_DATA_TYPE (normal, S_GET_DATA_TYPE (debug)); - S_SET_STORAGE_CLASS (normal, S_GET_STORAGE_CLASS (debug)); - - if (S_GET_NUMBER_AUXILIARY (debug) > S_GET_NUMBER_AUXILIARY (normal)) - { - /* take the most we have */ - S_SET_NUMBER_AUXILIARY (normal, S_GET_NUMBER_AUXILIARY (debug)); - } - - if (S_GET_NUMBER_AUXILIARY (debug) > 0) - { - /* Move all the auxiliary information. */ - memcpy (SYM_AUXINFO (normal), SYM_AUXINFO (debug), - (S_GET_NUMBER_AUXILIARY (debug) - * sizeof (*SYM_AUXINFO (debug)))); - } - - /* Move the debug flags. */ - SF_SET_DEBUG_FIELD (normal, SF_GET_DEBUG_FIELD (debug)); -} - -void -c_dot_file_symbol (filename) - char *filename; -{ - symbolS *symbolP; - - /* BFD converts filename to a .file symbol with an aux entry. It - also handles chaining. */ - symbolP = symbol_new (filename, bfd_abs_section_ptr, 0, &zero_address_frag); - - S_SET_STORAGE_CLASS (symbolP, C_FILE); - S_SET_NUMBER_AUXILIARY (symbolP, 1); - - symbol_get_bfdsym (symbolP)->flags = BSF_DEBUGGING; - -#ifndef NO_LISTING - { - extern int listing; - if (listing) - { - listing_source_file (filename); - } - } -#endif - - /* Make sure that the symbol is first on the symbol chain */ - if (symbol_rootP != symbolP) - { - symbol_remove (symbolP, &symbol_rootP, &symbol_lastP); - symbol_insert (symbolP, symbol_rootP, &symbol_rootP, &symbol_lastP); - } /* if not first on the list */ -} - -/* Line number handling */ - -struct line_no { - struct line_no *next; - fragS *frag; - alent l; -}; - -int coff_line_base; - -/* Symbol of last function, which we should hang line#s off of. */ -static symbolS *line_fsym; - -#define in_function() (line_fsym != 0) -#define clear_function() (line_fsym = 0) -#define set_function(F) (line_fsym = (F), coff_add_linesym (F)) - - -void -coff_obj_symbol_new_hook (symbolP) - symbolS *symbolP; -{ - long sz = (OBJ_COFF_MAX_AUXENTRIES + 1) * sizeof (combined_entry_type); - char * s = (char *) xmalloc (sz); - - memset (s, 0, sz); - coffsymbol (symbol_get_bfdsym (symbolP))->native = (combined_entry_type *) s; - - S_SET_DATA_TYPE (symbolP, T_NULL); - S_SET_STORAGE_CLASS (symbolP, 0); - S_SET_NUMBER_AUXILIARY (symbolP, 0); - - if (S_IS_STRING (symbolP)) - SF_SET_STRING (symbolP); - - if (S_IS_LOCAL (symbolP)) - SF_SET_LOCAL (symbolP); -} - - -/* - * Handle .ln directives. - */ - -static symbolS *current_lineno_sym; -static struct line_no *line_nos; -/* @@ Blindly assume all .ln directives will be in the .text section... */ -int coff_n_line_nos; - -static void -add_lineno (frag, offset, num) - fragS *frag; - int offset; - int num; -{ - struct line_no *new_line = - (struct line_no *) xmalloc (sizeof (struct line_no)); - if (!current_lineno_sym) - { - abort (); - } - if (num <= 0) - { - /* Zero is used as an end marker in the file. */ - as_warn (_("Line numbers must be positive integers\n")); - num = 1; - } - new_line->next = line_nos; - new_line->frag = frag; - new_line->l.line_number = num; - new_line->l.u.offset = offset; - line_nos = new_line; - coff_n_line_nos++; -} - -void -coff_add_linesym (sym) - symbolS *sym; -{ - if (line_nos) - { - coffsymbol (symbol_get_bfdsym (current_lineno_sym))->lineno = - (alent *) line_nos; - coff_n_line_nos++; - line_nos = 0; - } - current_lineno_sym = sym; -} - -static void -obj_coff_ln (appline) - int appline; -{ - int l; - - if (! appline && def_symbol_in_progress != NULL) - { - as_warn (_(".ln pseudo-op inside .def/.endef: ignored.")); - demand_empty_rest_of_line (); - return; - } - - l = get_absolute_expression (); - if (!appline) - { - add_lineno (frag_now, frag_now_fix (), l); - } - - if (appline) - new_logical_line ((char *) NULL, l - 1); - -#ifndef NO_LISTING - { - extern int listing; - - if (listing) - { - if (! appline) - l += coff_line_base - 1; - listing_source_line (l); - } - } -#endif - - demand_empty_rest_of_line (); -} - -/* .loc is essentially the same as .ln; parse it for assembler - compatibility. */ - -static void -obj_coff_loc (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - int lineno; - - /* FIXME: Why do we need this check? We need it for ECOFF, but why - do we need it for COFF? */ - if (now_seg != text_section) - { - as_warn (_(".loc outside of .text")); - demand_empty_rest_of_line (); - return; - } - - if (def_symbol_in_progress != NULL) - { - as_warn (_(".loc pseudo-op inside .def/.endef: ignored.")); - demand_empty_rest_of_line (); - return; - } - - /* Skip the file number. */ - SKIP_WHITESPACE (); - get_absolute_expression (); - SKIP_WHITESPACE (); - - lineno = get_absolute_expression (); - -#ifndef NO_LISTING - { - extern int listing; - - if (listing) - { - lineno += coff_line_base - 1; - listing_source_line (lineno); - } - } -#endif - - demand_empty_rest_of_line (); - - add_lineno (frag_now, frag_now_fix (), lineno); -} - -/* Handle the .ident pseudo-op. */ - -static void -obj_coff_ident (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - segT current_seg = now_seg; - subsegT current_subseg = now_subseg; - -#ifdef TE_PE - { - segT sec; - - /* We could put it in .comment, but that creates an extra section - that shouldn't be loaded into memory, which requires linker - changes... For now, until proven otherwise, use .rdata. */ - sec = subseg_new (".rdata$zzz", 0); - bfd_set_section_flags (stdoutput, sec, - ((SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA) - & bfd_applicable_section_flags (stdoutput))); - } -#else - subseg_new (".comment", 0); -#endif - - stringer (1); - subseg_set (current_seg, current_subseg); -} - -/* - * def() - * - * Handle .def directives. - * - * One might ask : why can't we symbol_new if the symbol does not - * already exist and fill it with debug information. Because of - * the C_EFCN special symbol. It would clobber the value of the - * function symbol before we have a chance to notice that it is - * a C_EFCN. And a second reason is that the code is more clear this - * way. (at least I think it is :-). - * - */ - -#define SKIP_SEMI_COLON() while (*input_line_pointer++ != ';') -#define SKIP_WHITESPACES() while (*input_line_pointer == ' ' || \ - *input_line_pointer == '\t') \ - input_line_pointer++; - -static void -obj_coff_def (what) - int what ATTRIBUTE_UNUSED; -{ - char name_end; /* Char after the end of name */ - char *symbol_name; /* Name of the debug symbol */ - char *symbol_name_copy; /* Temporary copy of the name */ - unsigned int symbol_name_length; - - if (def_symbol_in_progress != NULL) - { - as_warn (_(".def pseudo-op used inside of .def/.endef: ignored.")); - demand_empty_rest_of_line (); - return; - } /* if not inside .def/.endef */ - - SKIP_WHITESPACES (); - - symbol_name = input_line_pointer; -#ifdef STRIP_UNDERSCORE - if (symbol_name[0] == '_' && symbol_name[1] != 0) - symbol_name++; -#endif /* STRIP_UNDERSCORE */ - - name_end = get_symbol_end (); - symbol_name_length = strlen (symbol_name); - symbol_name_copy = xmalloc (symbol_name_length + 1); - strcpy (symbol_name_copy, symbol_name); -#ifdef tc_canonicalize_symbol_name - symbol_name_copy = tc_canonicalize_symbol_name (symbol_name_copy); -#endif - - /* Initialize the new symbol */ - def_symbol_in_progress = symbol_make (symbol_name_copy); - symbol_set_frag (def_symbol_in_progress, &zero_address_frag); - S_SET_VALUE (def_symbol_in_progress, 0); - - if (S_IS_STRING (def_symbol_in_progress)) - SF_SET_STRING (def_symbol_in_progress); - - *input_line_pointer = name_end; - - demand_empty_rest_of_line (); -} - -unsigned int dim_index; - -static void -obj_coff_endef (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - symbolS *symbolP; - - /* DIM BUG FIX sac@cygnus.com */ - dim_index = 0; - if (def_symbol_in_progress == NULL) - { - as_warn (_(".endef pseudo-op used outside of .def/.endef: ignored.")); - demand_empty_rest_of_line (); - return; - } /* if not inside .def/.endef */ - - /* Set the section number according to storage class. */ - switch (S_GET_STORAGE_CLASS (def_symbol_in_progress)) - { - case C_STRTAG: - case C_ENTAG: - case C_UNTAG: - SF_SET_TAG (def_symbol_in_progress); - /* intentional fallthrough */ - case C_FILE: - case C_TPDEF: - SF_SET_DEBUG (def_symbol_in_progress); - S_SET_SEGMENT (def_symbol_in_progress, fetch_coff_debug_section ()); - break; - - case C_EFCN: - SF_SET_LOCAL (def_symbol_in_progress); /* Do not emit this symbol. */ - /* intentional fallthrough */ - case C_BLOCK: - SF_SET_PROCESS (def_symbol_in_progress); /* Will need processing before writing */ - /* intentional fallthrough */ - case C_FCN: - { - CONST char *name; - S_SET_SEGMENT (def_symbol_in_progress, text_section); - - name = S_GET_NAME (def_symbol_in_progress); - if (name[0] == '.' && name[2] == 'f' && name[3] == '\0') - { - switch (name[1]) - { - case 'b': - /* .bf */ - if (! in_function ()) - as_warn (_("`%s' symbol without preceding function"), name); - /* Will need relocating. */ - SF_SET_PROCESS (def_symbol_in_progress); - clear_function (); - break; -#ifdef TE_PE - case 'e': - /* .ef */ - /* The MS compilers output the actual endline, not the - function-relative one... we want to match without - changing the assembler input. */ - SA_SET_SYM_LNNO (def_symbol_in_progress, - (SA_GET_SYM_LNNO (def_symbol_in_progress) - + coff_line_base)); - break; -#endif - } - } - } - break; - -#ifdef C_AUTOARG - case C_AUTOARG: -#endif /* C_AUTOARG */ - case C_AUTO: - case C_REG: - case C_ARG: - case C_REGPARM: - case C_FIELD: - SF_SET_DEBUG (def_symbol_in_progress); - S_SET_SEGMENT (def_symbol_in_progress, absolute_section); - break; - - case C_MOS: - case C_MOE: - case C_MOU: - case C_EOS: - S_SET_SEGMENT (def_symbol_in_progress, absolute_section); - break; - - case C_EXT: - case C_WEAKEXT: -#ifdef TE_PE - case C_NT_WEAK: -#endif - case C_STAT: - case C_LABEL: - /* Valid but set somewhere else (s_comm, s_lcomm, colon) */ - break; - - default: - case C_USTATIC: - case C_EXTDEF: - case C_ULABEL: - as_warn (_("unexpected storage class %d"), - S_GET_STORAGE_CLASS (def_symbol_in_progress)); - break; - } /* switch on storage class */ - - /* Now that we have built a debug symbol, try to find if we should - merge with an existing symbol or not. If a symbol is C_EFCN or - absolute_section or untagged SEG_DEBUG it never merges. We also - don't merge labels, which are in a different namespace, nor - symbols which have not yet been defined since they are typically - unique, nor do we merge tags with non-tags. */ - - /* Two cases for functions. Either debug followed by definition or - definition followed by debug. For definition first, we will - merge the debug symbol into the definition. For debug first, the - lineno entry MUST point to the definition function or else it - will point off into space when obj_crawl_symbol_chain() merges - the debug symbol into the real symbol. Therefor, let's presume - the debug symbol is a real function reference. */ - - /* FIXME-SOON If for some reason the definition label/symbol is - never seen, this will probably leave an undefined symbol at link - time. */ - - if (S_GET_STORAGE_CLASS (def_symbol_in_progress) == C_EFCN - || S_GET_STORAGE_CLASS (def_symbol_in_progress) == C_LABEL - || (!strcmp (bfd_get_section_name (stdoutput, - S_GET_SEGMENT (def_symbol_in_progress)), - "*DEBUG*") - && !SF_GET_TAG (def_symbol_in_progress)) - || S_GET_SEGMENT (def_symbol_in_progress) == absolute_section - || ! symbol_constant_p (def_symbol_in_progress) - || (symbolP = symbol_find_base (S_GET_NAME (def_symbol_in_progress), - DO_NOT_STRIP)) == NULL - || SF_GET_TAG (def_symbol_in_progress) != SF_GET_TAG (symbolP)) - { - /* If it already is at the end of the symbol list, do nothing */ - if (def_symbol_in_progress != symbol_lastP) - { - symbol_remove (def_symbol_in_progress, &symbol_rootP, &symbol_lastP); - symbol_append (def_symbol_in_progress, symbol_lastP, &symbol_rootP, - &symbol_lastP); - } - } - else - { - /* This symbol already exists, merge the newly created symbol - into the old one. This is not mandatory. The linker can - handle duplicate symbols correctly. But I guess that it save - a *lot* of space if the assembly file defines a lot of - symbols. [loic] */ - - /* The debug entry (def_symbol_in_progress) is merged into the - previous definition. */ - - c_symbol_merge (def_symbol_in_progress, symbolP); - symbol_remove (def_symbol_in_progress, &symbol_rootP, &symbol_lastP); - - def_symbol_in_progress = symbolP; - - if (SF_GET_FUNCTION (def_symbol_in_progress) - || SF_GET_TAG (def_symbol_in_progress) - || S_GET_STORAGE_CLASS (def_symbol_in_progress) == C_STAT) - { - /* For functions, and tags, and static symbols, the symbol - *must* be where the debug symbol appears. Move the - existing symbol to the current place. */ - /* If it already is at the end of the symbol list, do nothing */ - if (def_symbol_in_progress != symbol_lastP) - { - symbol_remove (def_symbol_in_progress, &symbol_rootP, &symbol_lastP); - symbol_append (def_symbol_in_progress, symbol_lastP, &symbol_rootP, &symbol_lastP); - } - } - } - - if (SF_GET_TAG (def_symbol_in_progress)) - { - symbolS *oldtag; - - oldtag = symbol_find_base (S_GET_NAME (def_symbol_in_progress), - DO_NOT_STRIP); - if (oldtag == NULL || ! SF_GET_TAG (oldtag)) - tag_insert (S_GET_NAME (def_symbol_in_progress), - def_symbol_in_progress); - } - - if (SF_GET_FUNCTION (def_symbol_in_progress)) - { - know (sizeof (def_symbol_in_progress) <= sizeof (long)); - set_function (def_symbol_in_progress); - SF_SET_PROCESS (def_symbol_in_progress); - - if (symbolP == NULL) - { - /* That is, if this is the first time we've seen the - function... */ - symbol_table_insert (def_symbol_in_progress); - } /* definition follows debug */ - } /* Create the line number entry pointing to the function being defined */ - - def_symbol_in_progress = NULL; - demand_empty_rest_of_line (); -} - -static void -obj_coff_dim (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - int dim_index; - - if (def_symbol_in_progress == NULL) - { - as_warn (_(".dim pseudo-op used outside of .def/.endef: ignored.")); - demand_empty_rest_of_line (); - return; - } /* if not inside .def/.endef */ - - S_SET_NUMBER_AUXILIARY (def_symbol_in_progress, 1); - - for (dim_index = 0; dim_index < DIMNUM; dim_index++) - { - SKIP_WHITESPACES (); - SA_SET_SYM_DIMEN (def_symbol_in_progress, dim_index, - get_absolute_expression ()); - - switch (*input_line_pointer) - { - case ',': - input_line_pointer++; - break; - - default: - as_warn (_("badly formed .dim directive ignored")); - /* intentional fallthrough */ - case '\n': - case ';': - dim_index = DIMNUM; - break; - } - } - - demand_empty_rest_of_line (); -} - -static void -obj_coff_line (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - int this_base; - - if (def_symbol_in_progress == NULL) - { - /* Probably stabs-style line? */ - obj_coff_ln (0); - return; - } - - this_base = get_absolute_expression (); - if (!strcmp (".bf", S_GET_NAME (def_symbol_in_progress))) - coff_line_base = this_base; - - S_SET_NUMBER_AUXILIARY (def_symbol_in_progress, 1); - SA_SET_SYM_LNNO (def_symbol_in_progress, this_base); - - demand_empty_rest_of_line (); - -#ifndef NO_LISTING - if (strcmp (".bf", S_GET_NAME (def_symbol_in_progress)) == 0) - { - extern int listing; - - if (listing) - listing_source_line ((unsigned int) this_base); - } -#endif -} - -static void -obj_coff_size (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - if (def_symbol_in_progress == NULL) - { - as_warn (_(".size pseudo-op used outside of .def/.endef ignored.")); - demand_empty_rest_of_line (); - return; - } /* if not inside .def/.endef */ - - S_SET_NUMBER_AUXILIARY (def_symbol_in_progress, 1); - SA_SET_SYM_SIZE (def_symbol_in_progress, get_absolute_expression ()); - demand_empty_rest_of_line (); -} - -static void -obj_coff_scl (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - if (def_symbol_in_progress == NULL) - { - as_warn (_(".scl pseudo-op used outside of .def/.endef ignored.")); - demand_empty_rest_of_line (); - return; - } /* if not inside .def/.endef */ - - S_SET_STORAGE_CLASS (def_symbol_in_progress, get_absolute_expression ()); - demand_empty_rest_of_line (); -} - -static void -obj_coff_tag (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - char *symbol_name; - char name_end; - - if (def_symbol_in_progress == NULL) - { - as_warn (_(".tag pseudo-op used outside of .def/.endef ignored.")); - demand_empty_rest_of_line (); - return; - } - - S_SET_NUMBER_AUXILIARY (def_symbol_in_progress, 1); - symbol_name = input_line_pointer; - name_end = get_symbol_end (); - -#ifdef tc_canonicalize_symbol_name - symbol_name = tc_canonicalize_symbol_name (symbol_name); -#endif - - /* Assume that the symbol referred to by .tag is always defined. - This was a bad assumption. I've added find_or_make. xoxorich. */ - SA_SET_SYM_TAGNDX (def_symbol_in_progress, - tag_find_or_make (symbol_name)); - if (SA_GET_SYM_TAGNDX (def_symbol_in_progress) == 0L) - { - as_warn (_("tag not found for .tag %s"), symbol_name); - } /* not defined */ - - SF_SET_TAGGED (def_symbol_in_progress); - *input_line_pointer = name_end; - - demand_empty_rest_of_line (); -} - -static void -obj_coff_type (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - if (def_symbol_in_progress == NULL) - { - as_warn (_(".type pseudo-op used outside of .def/.endef ignored.")); - demand_empty_rest_of_line (); - return; - } /* if not inside .def/.endef */ - - S_SET_DATA_TYPE (def_symbol_in_progress, get_absolute_expression ()); - - if (ISFCN (S_GET_DATA_TYPE (def_symbol_in_progress)) && - S_GET_STORAGE_CLASS (def_symbol_in_progress) != C_TPDEF) - { - SF_SET_FUNCTION (def_symbol_in_progress); - } /* is a function */ - - demand_empty_rest_of_line (); -} - -static void -obj_coff_val (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - if (def_symbol_in_progress == NULL) - { - as_warn (_(".val pseudo-op used outside of .def/.endef ignored.")); - demand_empty_rest_of_line (); - return; - } /* if not inside .def/.endef */ - - if (is_name_beginner (*input_line_pointer)) - { - char *symbol_name = input_line_pointer; - char name_end = get_symbol_end (); - -#ifdef tc_canonicalize_symbol_name - symbol_name = tc_canonicalize_symbol_name (symbol_name); -#endif - if (!strcmp (symbol_name, ".")) - { - symbol_set_frag (def_symbol_in_progress, frag_now); - S_SET_VALUE (def_symbol_in_progress, (valueT) frag_now_fix ()); - /* If the .val is != from the .def (e.g. statics) */ - } - else if (strcmp (S_GET_NAME (def_symbol_in_progress), symbol_name)) - { - expressionS exp; - - exp.X_op = O_symbol; - exp.X_add_symbol = symbol_find_or_make (symbol_name); - exp.X_op_symbol = NULL; - exp.X_add_number = 0; - symbol_set_value_expression (def_symbol_in_progress, &exp); - - /* If the segment is undefined when the forward reference is - resolved, then copy the segment id from the forward - symbol. */ - SF_SET_GET_SEGMENT (def_symbol_in_progress); - - /* FIXME: gcc can generate address expressions here in - unusual cases (search for "obscure" in sdbout.c). We - just ignore the offset here, thus generating incorrect - debugging information. We ignore the rest of the line - just below. */ - } - /* Otherwise, it is the name of a non debug symbol and its value - will be calculated later. */ - *input_line_pointer = name_end; - } - else - { - S_SET_VALUE (def_symbol_in_progress, get_absolute_expression ()); - } /* if symbol based */ - - demand_empty_rest_of_line (); -} - -void -coff_obj_read_begin_hook () -{ - /* These had better be the same. Usually 18 bytes. */ -#ifndef BFD_HEADERS - know (sizeof (SYMENT) == sizeof (AUXENT)); - know (SYMESZ == AUXESZ); -#endif - tag_init (); -} - - -symbolS *coff_last_function; -static symbolS *coff_last_bf; - -void -coff_frob_symbol (symp, punt) - symbolS *symp; - int *punt; -{ - static symbolS *last_tagP; - static stack *block_stack; - static symbolS *set_end; - symbolS *next_set_end = NULL; - - if (symp == &abs_symbol) - { - *punt = 1; - return; - } - - if (current_lineno_sym) - coff_add_linesym ((symbolS *) 0); - - if (!block_stack) - block_stack = stack_init (512, sizeof (symbolS*)); - - if (S_IS_WEAK (symp)) - { -#ifdef TE_PE - S_SET_STORAGE_CLASS (symp, C_NT_WEAK); -#else - S_SET_STORAGE_CLASS (symp, C_WEAKEXT); -#endif - } - - if (!S_IS_DEFINED (symp) - && !S_IS_WEAK (symp) - && S_GET_STORAGE_CLASS (symp) != C_STAT) - S_SET_STORAGE_CLASS (symp, C_EXT); - - if (!SF_GET_DEBUG (symp)) - { - symbolS *real; - if (!SF_GET_LOCAL (symp) - && !SF_GET_STATICS (symp) - && (real = symbol_find_base (S_GET_NAME (symp), DO_NOT_STRIP)) - && real != symp) - { - c_symbol_merge (symp, real); - *punt = 1; - } - if (!S_IS_DEFINED (symp) && !SF_GET_LOCAL (symp)) - { - assert (S_GET_VALUE (symp) == 0); - S_SET_EXTERNAL (symp); - } - else if (S_GET_STORAGE_CLASS (symp) == C_NULL) - { - if (S_GET_SEGMENT (symp) == text_section - && symp != seg_info (text_section)->sym) - S_SET_STORAGE_CLASS (symp, C_LABEL); - else - S_SET_STORAGE_CLASS (symp, C_STAT); - } - if (SF_GET_PROCESS (symp)) - { - if (S_GET_STORAGE_CLASS (symp) == C_BLOCK) - { - if (!strcmp (S_GET_NAME (symp), ".bb")) - stack_push (block_stack, (char *) &symp); - else - { - symbolS *begin; - begin = *(symbolS **) stack_pop (block_stack); - if (begin == 0) - as_warn (_("mismatched .eb")); - else - next_set_end = begin; - } - } - if (coff_last_function == 0 && SF_GET_FUNCTION (symp)) - { - union internal_auxent *auxp; - coff_last_function = symp; - if (S_GET_NUMBER_AUXILIARY (symp) < 1) - S_SET_NUMBER_AUXILIARY (symp, 1); - auxp = SYM_AUXENT (symp); - memset (auxp->x_sym.x_fcnary.x_ary.x_dimen, 0, - sizeof (auxp->x_sym.x_fcnary.x_ary.x_dimen)); - } - if (S_GET_STORAGE_CLASS (symp) == C_EFCN) - { - if (coff_last_function == 0) - as_fatal (_("C_EFCN symbol out of scope")); - SA_SET_SYM_FSIZE (coff_last_function, - (long) (S_GET_VALUE (symp) - - S_GET_VALUE (coff_last_function))); - next_set_end = coff_last_function; - coff_last_function = 0; - } - } - if (S_IS_EXTERNAL (symp)) - S_SET_STORAGE_CLASS (symp, C_EXT); - else if (SF_GET_LOCAL (symp)) - *punt = 1; - - if (SF_GET_FUNCTION (symp)) - symbol_get_bfdsym (symp)->flags |= BSF_FUNCTION; - - /* more ... */ - } - - /* Double check weak symbols. */ - if (S_IS_WEAK (symp) && S_IS_COMMON (symp)) - as_bad (_("Symbol `%s' can not be both weak and common"), - S_GET_NAME (symp)); - - if (SF_GET_TAG (symp)) - last_tagP = symp; - else if (S_GET_STORAGE_CLASS (symp) == C_EOS) - next_set_end = last_tagP; - -#ifdef OBJ_XCOFF - /* This is pretty horrible, but we have to set *punt correctly in - order to call SA_SET_SYM_ENDNDX correctly. */ - if (! symbol_used_in_reloc_p (symp) - && ((symbol_get_bfdsym (symp)->flags & BSF_SECTION_SYM) != 0 - || (! S_IS_EXTERNAL (symp) - && ! symbol_get_tc (symp)->output - && S_GET_STORAGE_CLASS (symp) != C_FILE))) - *punt = 1; -#endif - - if (set_end != (symbolS *) NULL - && ! *punt - && ((symbol_get_bfdsym (symp)->flags & BSF_NOT_AT_END) != 0 - || (S_IS_DEFINED (symp) - && ! S_IS_COMMON (symp) - && (! S_IS_EXTERNAL (symp) || SF_GET_FUNCTION (symp))))) - { - SA_SET_SYM_ENDNDX (set_end, symp); - set_end = NULL; - } - - if (next_set_end != NULL) - { - if (set_end != NULL) - as_warn ("Warning: internal error: forgetting to set endndx of %s", - S_GET_NAME (set_end)); - set_end = next_set_end; - } - - if (! *punt - && S_GET_STORAGE_CLASS (symp) == C_FCN - && strcmp (S_GET_NAME (symp), ".bf") == 0) - { - if (coff_last_bf != NULL) - SA_SET_SYM_ENDNDX (coff_last_bf, symp); - coff_last_bf = symp; - } - - if (coffsymbol (symbol_get_bfdsym (symp))->lineno) - { - int i; - struct line_no *lptr; - alent *l; - - lptr = (struct line_no *) coffsymbol (symbol_get_bfdsym (symp))->lineno; - for (i = 0; lptr; lptr = lptr->next) - i++; - lptr = (struct line_no *) coffsymbol (symbol_get_bfdsym (symp))->lineno; - - /* We need i entries for line numbers, plus 1 for the first - entry which BFD will override, plus 1 for the last zero - entry (a marker for BFD). */ - l = (alent *) xmalloc ((i + 2) * sizeof (alent)); - coffsymbol (symbol_get_bfdsym (symp))->lineno = l; - l[i + 1].line_number = 0; - l[i + 1].u.sym = NULL; - for (; i > 0; i--) - { - if (lptr->frag) - lptr->l.u.offset += lptr->frag->fr_address / OCTETS_PER_BYTE; - l[i] = lptr->l; - lptr = lptr->next; - } - } -} - -void -coff_adjust_section_syms (abfd, sec, x) - bfd *abfd ATTRIBUTE_UNUSED; - asection *sec; - PTR x ATTRIBUTE_UNUSED; -{ - symbolS *secsym; - segment_info_type *seginfo = seg_info (sec); - int nlnno, nrelocs = 0; - - /* RS/6000 gas creates a .debug section manually in ppc_frob_file in - tc-ppc.c. Do not get confused by it. */ - if (seginfo == NULL) - return; - - if (!strcmp (sec->name, ".text")) - nlnno = coff_n_line_nos; - else - nlnno = 0; - { - /* @@ Hope that none of the fixups expand to more than one reloc - entry... */ - fixS *fixp = seginfo->fix_root; - while (fixp) - { - if (! fixp->fx_done) - nrelocs++; - fixp = fixp->fx_next; - } - } - if (bfd_get_section_size_before_reloc (sec) == 0 - && nrelocs == 0 - && nlnno == 0 - && sec != text_section - && sec != data_section - && sec != bss_section) - return; - secsym = section_symbol (sec); - /* This is an estimate; we'll plug in the real value using - SET_SECTION_RELOCS later */ - SA_SET_SCN_NRELOC (secsym, nrelocs); - SA_SET_SCN_NLINNO (secsym, nlnno); -} - -void -coff_frob_file_after_relocs () -{ - bfd_map_over_sections (stdoutput, coff_adjust_section_syms, (char*) 0); -} - -/* - * implement the .section pseudo op: - * .section name {, "flags"} - * ^ ^ - * | +--- optional flags: 'b' for bss - * | 'i' for info - * +-- section name 'l' for lib - * 'n' for noload - * 'o' for over - * 'w' for data - * 'd' (apparently m88k for data) - * 'x' for text - * 'r' for read-only data - * 's' for shared data (PE) - * But if the argument is not a quoted string, treat it as a - * subsegment number. - */ - -void -obj_coff_section (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - /* Strip out the section name */ - char *section_name; - char c; - char *name; - unsigned int exp; - flagword flags; - asection *sec; - - if (flag_mri) - { - char type; - - s_mri_sect (&type); - return; - } - - section_name = input_line_pointer; - c = get_symbol_end (); - - name = xmalloc (input_line_pointer - section_name + 1); - strcpy (name, section_name); - - *input_line_pointer = c; - - SKIP_WHITESPACE (); - - exp = 0; - flags = SEC_LOAD; - - if (*input_line_pointer == ',') - { - ++input_line_pointer; - SKIP_WHITESPACE (); - if (*input_line_pointer != '"') - exp = get_absolute_expression (); - else - { - ++input_line_pointer; - while (*input_line_pointer != '"' - && ! is_end_of_line[(unsigned char) *input_line_pointer]) - { - switch (*input_line_pointer) - { - case 'b': flags |= SEC_ALLOC; flags &=~ SEC_LOAD; break; - case 'n': flags &=~ SEC_LOAD; break; - case 'd': flags |= SEC_DATA | SEC_LOAD; /* fall through */ - case 'w': flags &=~ SEC_READONLY; break; - case 'x': flags |= SEC_CODE | SEC_LOAD; break; - case 'r': flags |= SEC_READONLY; break; - case 's': flags |= SEC_SHARED; break; - - case 'i': /* STYP_INFO */ - case 'l': /* STYP_LIB */ - case 'o': /* STYP_OVER */ - as_warn (_("unsupported section attribute '%c'"), - *input_line_pointer); - break; - - default: - as_warn(_("unknown section attribute '%c'"), - *input_line_pointer); - break; - } - ++input_line_pointer; - } - if (*input_line_pointer == '"') - ++input_line_pointer; - } - } - - sec = subseg_new (name, (subsegT) exp); - - if (flags != SEC_NO_FLAGS) - { - flagword oldflags; - - oldflags = bfd_get_section_flags (stdoutput, sec); - oldflags &= SEC_LINK_ONCE | SEC_LINK_DUPLICATES; - flags |= oldflags; - - if (! bfd_set_section_flags (stdoutput, sec, flags)) - as_warn (_("error setting flags for \"%s\": %s"), - bfd_section_name (stdoutput, sec), - bfd_errmsg (bfd_get_error ())); - } - - demand_empty_rest_of_line (); -} - -void -coff_adjust_symtab () -{ - if (symbol_rootP == NULL - || S_GET_STORAGE_CLASS (symbol_rootP) != C_FILE) - c_dot_file_symbol ("fake"); -} - -void -coff_frob_section (sec) - segT sec; -{ - segT strsec; - char *p; - fragS *fragp; - bfd_vma size, n_entries, mask; - bfd_vma align_power = (bfd_vma)sec->alignment_power + OCTETS_PER_BYTE_POWER; - - /* The COFF back end in BFD requires that all section sizes be - rounded up to multiples of the corresponding section alignments, - supposedly because standard COFF has no other way of encoding alignment - for sections. If your COFF flavor has a different way of encoding - section alignment, then skip this step, as TICOFF does. */ - size = bfd_get_section_size_before_reloc (sec); - mask = ((bfd_vma) 1 << align_power) - 1; -#if !defined(TICOFF) - if (size & mask) - { - size = (size + mask) & ~mask; - bfd_set_section_size (stdoutput, sec, size); - } -#endif - - /* If the section size is non-zero, the section symbol needs an aux - entry associated with it, indicating the size. We don't know - all the values yet; coff_frob_symbol will fill them in later. */ -#ifndef TICOFF - if (size != 0 - || sec == text_section - || sec == data_section - || sec == bss_section) -#endif - { - symbolS *secsym = section_symbol (sec); - - S_SET_STORAGE_CLASS (secsym, C_STAT); - S_SET_NUMBER_AUXILIARY (secsym, 1); - SF_SET_STATICS (secsym); - SA_SET_SCN_SCNLEN (secsym, size); - } - - /* @@ these should be in a "stabs.h" file, or maybe as.h */ -#ifndef STAB_SECTION_NAME -#define STAB_SECTION_NAME ".stab" -#endif -#ifndef STAB_STRING_SECTION_NAME -#define STAB_STRING_SECTION_NAME ".stabstr" -#endif - if (strcmp (STAB_STRING_SECTION_NAME, sec->name)) - return; - - strsec = sec; - sec = subseg_get (STAB_SECTION_NAME, 0); - /* size is already rounded up, since other section will be listed first */ - size = bfd_get_section_size_before_reloc (strsec); - - n_entries = bfd_get_section_size_before_reloc (sec) / 12 - 1; - - /* Find first non-empty frag. It should be large enough. */ - fragp = seg_info (sec)->frchainP->frch_root; - while (fragp && fragp->fr_fix == 0) - fragp = fragp->fr_next; - assert (fragp != 0 && fragp->fr_fix >= 12); - - /* Store the values. */ - p = fragp->fr_literal; - bfd_h_put_16 (stdoutput, n_entries, (bfd_byte *) p + 6); - bfd_h_put_32 (stdoutput, size, (bfd_byte *) p + 8); -} - -void -obj_coff_init_stab_section (seg) - segT seg; -{ - char *file; - char *p; - char *stabstr_name; - unsigned int stroff; - - /* Make space for this first symbol. */ - p = frag_more (12); - /* Zero it out. */ - memset (p, 0, 12); - as_where (&file, (unsigned int *) NULL); - stabstr_name = (char *) alloca (strlen (seg->name) + 4); - strcpy (stabstr_name, seg->name); - strcat (stabstr_name, "str"); - stroff = get_stab_string_offset (file, stabstr_name); - know (stroff == 1); - md_number_to_chars (p, stroff, 4); -} - -#ifdef DEBUG -/* for debugging */ -const char * -s_get_name (s) - symbolS *s; -{ - return ((s == NULL) ? "(NULL)" : S_GET_NAME (s)); -} - -void -symbol_dump () -{ - symbolS *symbolP; - - for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP)) - { - printf(_("0x%lx: \"%s\" type = %ld, class = %d, segment = %d\n"), - (unsigned long) symbolP, - S_GET_NAME(symbolP), - (long) S_GET_DATA_TYPE(symbolP), - S_GET_STORAGE_CLASS(symbolP), - (int) S_GET_SEGMENT(symbolP)); - } -} - -#endif /* DEBUG */ - -#else /* not BFD_ASSEMBLER */ - -#include "frags.h" -/* This is needed because we include internal bfd things. */ -#include <time.h> - -#include "libbfd.h" -#include "libcoff.h" - -#ifdef TE_PE -#include "coff/pe.h" -#endif - -/* The NOP_OPCODE is for the alignment fill value. Fill with nop so - that we can stick sections together without causing trouble. */ -#ifndef NOP_OPCODE -#define NOP_OPCODE 0x00 -#endif - -/* The zeroes if symbol name is longer than 8 chars */ -#define S_SET_ZEROES(s,v) ((s)->sy_symbol.ost_entry.n_zeroes = (v)) - -#define MIN(a,b) ((a) < (b)? (a) : (b)) - -/* This vector is used to turn a gas internal segment number into a - section number suitable for insertion into a coff symbol table. - This must correspond to seg_info_off_by_4. */ - -const short seg_N_TYPE[] = -{ /* in: segT out: N_TYPE bits */ - C_ABS_SECTION, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, - 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - C_UNDEF_SECTION, /* SEG_UNKNOWN */ - C_UNDEF_SECTION, /* SEG_GOOF */ - C_UNDEF_SECTION, /* SEG_EXPR */ - C_DEBUG_SECTION, /* SEG_DEBUG */ - C_NTV_SECTION, /* SEG_NTV */ - C_PTV_SECTION, /* SEG_PTV */ - C_REGISTER_SECTION, /* SEG_REGISTER */ -}; - -int function_lineoff = -1; /* Offset in line#s where the last function - started (the odd entry for line #0) */ - -/* structure used to keep the filenames which - are too long around so that we can stick them - into the string table */ -struct filename_list -{ - char *filename; - struct filename_list *next; -}; - -static struct filename_list *filename_list_head; -static struct filename_list *filename_list_tail; - -static symbolS *last_line_symbol; - -/* Add 4 to the real value to get the index and compensate the - negatives. This vector is used by S_GET_SEGMENT to turn a coff - section number into a segment number -*/ -static symbolS *previous_file_symbol; -void c_symbol_merge (); -static int line_base; - -symbolS *c_section_symbol (); -bfd *abfd; - -static void fixup_segment PARAMS ((segment_info_type *segP, - segT this_segment_type)); - - -static void fixup_mdeps PARAMS ((fragS *, - object_headers *, - segT)); - - -static void fill_section PARAMS ((bfd * abfd, - object_headers *, - unsigned long *)); - - -static int c_line_new PARAMS ((symbolS * symbol, long paddr, - int line_number, - fragS * frag)); - - -static void w_symbols PARAMS ((bfd * abfd, char *where, - symbolS * symbol_rootP)); - -static void adjust_stab_section PARAMS ((bfd *abfd, segT seg)); - -static void obj_coff_lcomm PARAMS ((int)); -static void obj_coff_text PARAMS ((int)); -static void obj_coff_data PARAMS ((int)); -void obj_coff_section PARAMS ((int)); - -/* When not using BFD_ASSEMBLER, we permit up to 40 sections. - - This array maps a COFF section number into a gas section number. - Because COFF uses negative section numbers, you must add 4 to the - COFF section number when indexing into this array; this is done via - the SEG_INFO_FROM_SECTION_NUMBER macro. This must correspond to - seg_N_TYPE. */ - -static const segT seg_info_off_by_4[] = -{ - SEG_PTV, - SEG_NTV, - SEG_DEBUG, - SEG_ABSOLUTE, - SEG_UNKNOWN, - SEG_E0, SEG_E1, SEG_E2, SEG_E3, SEG_E4, - SEG_E5, SEG_E6, SEG_E7, SEG_E8, SEG_E9, - SEG_E10, SEG_E11, SEG_E12, SEG_E13, SEG_E14, - SEG_E15, SEG_E16, SEG_E17, SEG_E18, SEG_E19, - SEG_E20, SEG_E21, SEG_E22, SEG_E23, SEG_E24, - SEG_E25, SEG_E26, SEG_E27, SEG_E28, SEG_E29, - SEG_E30, SEG_E31, SEG_E32, SEG_E33, SEG_E34, - SEG_E35, SEG_E36, SEG_E37, SEG_E38, SEG_E39, - (segT) 40, - (segT) 41, - (segT) 42, - (segT) 43, - (segT) 44, - (segT) 45, - (segT) 0, - (segT) 0, - (segT) 0, - SEG_REGISTER -}; - -#define SEG_INFO_FROM_SECTION_NUMBER(x) (seg_info_off_by_4[(x)+4]) - -static relax_addressT -relax_align (address, alignment) - relax_addressT address; - long alignment; -{ - relax_addressT mask; - relax_addressT new_address; - - mask = ~((~0) << alignment); - new_address = (address + mask) & (~mask); - return (new_address - address); -} - - -segT -s_get_segment (x) - symbolS * x; -{ - return SEG_INFO_FROM_SECTION_NUMBER (x->sy_symbol.ost_entry.n_scnum); -} - -/* calculate the size of the frag chain and fill in the section header - to contain all of it, also fill in the addr of the sections */ -static unsigned int -size_section (abfd, idx) - bfd *abfd ATTRIBUTE_UNUSED; - unsigned int idx; -{ - - unsigned int size = 0; - fragS *frag = segment_info[idx].frchainP->frch_root; - while (frag) - { - size = frag->fr_address; - if (frag->fr_address != size) - { - fprintf (stderr, _("Out of step\n")); - size = frag->fr_address; - } - - switch (frag->fr_type) - { -#ifdef TC_COFF_SIZEMACHDEP - case rs_machine_dependent: - size += TC_COFF_SIZEMACHDEP (frag); - break; -#endif - case rs_space: - assert (frag->fr_symbol == 0); - case rs_fill: - case rs_org: - size += frag->fr_fix; - size += frag->fr_offset * frag->fr_var; - break; - case rs_align: - case rs_align_code: - { - addressT off; - - size += frag->fr_fix; - off = relax_align (size, frag->fr_offset); - if (frag->fr_subtype != 0 && off > frag->fr_subtype) - off = 0; - size += off; - } - break; - default: - BAD_CASE (frag->fr_type); - break; - } - frag = frag->fr_next; - } - segment_info[idx].scnhdr.s_size = size; - return size; -} - - -static unsigned int -count_entries_in_chain (idx) - unsigned int idx; -{ - unsigned int nrelocs; - fixS *fixup_ptr; - - /* Count the relocations */ - fixup_ptr = segment_info[idx].fix_root; - nrelocs = 0; - while (fixup_ptr != (fixS *) NULL) - { - if (fixup_ptr->fx_done == 0 && TC_COUNT_RELOC (fixup_ptr)) - { -#ifdef TC_A29K - if (fixup_ptr->fx_r_type == RELOC_CONSTH) - nrelocs += 2; - else - nrelocs++; -#else - nrelocs++; -#endif - } - - fixup_ptr = fixup_ptr->fx_next; - } - return nrelocs; -} - -#ifdef TE_AUX - -static int compare_external_relocs PARAMS ((const PTR, const PTR)); - -/* AUX's ld expects relocations to be sorted */ -static int -compare_external_relocs (x, y) - const PTR x; - const PTR y; -{ - struct external_reloc *a = (struct external_reloc *) x; - struct external_reloc *b = (struct external_reloc *) y; - bfd_vma aadr = bfd_getb32 (a->r_vaddr); - bfd_vma badr = bfd_getb32 (b->r_vaddr); - return (aadr < badr ? -1 : badr < aadr ? 1 : 0); -} - -#endif - -/* output all the relocations for a section */ -void -do_relocs_for (abfd, h, file_cursor) - bfd * abfd; - object_headers * h; - unsigned long *file_cursor; -{ - unsigned int nrelocs; - unsigned int idx; - unsigned long reloc_start = *file_cursor; - - for (idx = SEG_E0; idx < SEG_LAST; idx++) - { - if (segment_info[idx].scnhdr.s_name[0]) - { - struct external_reloc *ext_ptr; - struct external_reloc *external_reloc_vec; - unsigned int external_reloc_size; - unsigned int base = segment_info[idx].scnhdr.s_paddr; - fixS *fix_ptr = segment_info[idx].fix_root; - nrelocs = count_entries_in_chain (idx); - - if (nrelocs) - /* Bypass this stuff if no relocs. This also incidentally - avoids a SCO bug, where free(malloc(0)) tends to crash. */ - { - external_reloc_size = nrelocs * RELSZ; - external_reloc_vec = - (struct external_reloc *) malloc (external_reloc_size); - - ext_ptr = external_reloc_vec; - - /* Fill in the internal coff style reloc struct from the - internal fix list. */ - while (fix_ptr) - { - struct internal_reloc intr; - - /* Only output some of the relocations */ - if (fix_ptr->fx_done == 0 && TC_COUNT_RELOC (fix_ptr)) - { -#ifdef TC_RELOC_MANGLE - TC_RELOC_MANGLE (&segment_info[idx], fix_ptr, &intr, - base); - -#else - symbolS *dot; - symbolS *symbol_ptr = fix_ptr->fx_addsy; - - intr.r_type = TC_COFF_FIX2RTYPE (fix_ptr); - intr.r_vaddr = - base + fix_ptr->fx_frag->fr_address + fix_ptr->fx_where; - -#ifdef TC_KEEP_FX_OFFSET - intr.r_offset = fix_ptr->fx_offset; -#else - intr.r_offset = 0; -#endif - - while (symbol_ptr->sy_value.X_op == O_symbol - && (! S_IS_DEFINED (symbol_ptr) - || S_IS_COMMON (symbol_ptr))) - { - symbolS *n; - - /* We must avoid looping, as that can occur - with a badly written program. */ - n = symbol_ptr->sy_value.X_add_symbol; - if (n == symbol_ptr) - break; - symbol_ptr = n; - } - - /* Turn the segment of the symbol into an offset. */ - if (symbol_ptr) - { - resolve_symbol_value (symbol_ptr, 1); - if (! symbol_ptr->sy_resolved) - { - char *file; - unsigned int line; - - if (expr_symbol_where (symbol_ptr, &file, &line)) - as_bad_where (file, line, - _("unresolved relocation")); - else - as_bad (_("bad relocation: symbol `%s' not in symbol table"), - S_GET_NAME (symbol_ptr)); - } - dot = segment_info[S_GET_SEGMENT (symbol_ptr)].dot; - if (dot) - { - intr.r_symndx = dot->sy_number; - } - else - { - intr.r_symndx = symbol_ptr->sy_number; - } - - } - else - { - intr.r_symndx = -1; - } -#endif - - (void) bfd_coff_swap_reloc_out (abfd, &intr, ext_ptr); - ext_ptr++; - -#if defined(TC_A29K) - - /* The 29k has a special kludge for the high 16 bit - reloc. Two relocations are emited, R_IHIHALF, - and R_IHCONST. The second one doesn't contain a - symbol, but uses the value for offset. */ - - if (intr.r_type == R_IHIHALF) - { - /* now emit the second bit */ - intr.r_type = R_IHCONST; - intr.r_symndx = fix_ptr->fx_addnumber; - (void) bfd_coff_swap_reloc_out (abfd, &intr, ext_ptr); - ext_ptr++; - } -#endif - } - - fix_ptr = fix_ptr->fx_next; - } - -#ifdef TE_AUX - /* Sort the reloc table */ - qsort ((PTR) external_reloc_vec, nrelocs, - sizeof (struct external_reloc), compare_external_relocs); -#endif - - /* Write out the reloc table */ - bfd_write ((PTR) external_reloc_vec, 1, external_reloc_size, - abfd); - free (external_reloc_vec); - - /* Fill in section header info. */ - segment_info[idx].scnhdr.s_relptr = *file_cursor; - *file_cursor += external_reloc_size; - segment_info[idx].scnhdr.s_nreloc = nrelocs; - } - else - { - /* No relocs */ - segment_info[idx].scnhdr.s_relptr = 0; - } - } - } - /* Set relocation_size field in file headers */ - H_SET_RELOCATION_SIZE (h, *file_cursor - reloc_start, 0); -} - - -/* run through a frag chain and write out the data to go with it, fill - in the scnhdrs with the info on the file postions -*/ -static void -fill_section (abfd, h, file_cursor) - bfd * abfd; - object_headers *h ATTRIBUTE_UNUSED; - unsigned long *file_cursor; -{ - - unsigned int i; - unsigned int paddr = 0; - - for (i = SEG_E0; i < SEG_UNKNOWN; i++) - { - unsigned int offset = 0; - struct internal_scnhdr *s = &(segment_info[i].scnhdr); - - PROGRESS (1); - - if (s->s_name[0]) - { - fragS *frag = segment_info[i].frchainP->frch_root; - char *buffer; - - if (s->s_size == 0) - s->s_scnptr = 0; - else - { - buffer = xmalloc (s->s_size); - s->s_scnptr = *file_cursor; - } - know (s->s_paddr == paddr); - - if (strcmp (s->s_name, ".text") == 0) - s->s_flags |= STYP_TEXT; - else if (strcmp (s->s_name, ".data") == 0) - s->s_flags |= STYP_DATA; - else if (strcmp (s->s_name, ".bss") == 0) - { - s->s_scnptr = 0; - s->s_flags |= STYP_BSS; - - /* @@ Should make the i386 and a29k coff targets define - COFF_NOLOAD_PROBLEM, and have only one test here. */ -#ifndef TC_I386 -#ifndef TC_A29K -#ifndef COFF_NOLOAD_PROBLEM - /* Apparently the SVR3 linker (and exec syscall) and UDI - mondfe progrem are confused by noload sections. */ - s->s_flags |= STYP_NOLOAD; -#endif -#endif -#endif - } - else if (strcmp (s->s_name, ".lit") == 0) - s->s_flags = STYP_LIT | STYP_TEXT; - else if (strcmp (s->s_name, ".init") == 0) - s->s_flags |= STYP_TEXT; - else if (strcmp (s->s_name, ".fini") == 0) - s->s_flags |= STYP_TEXT; - else if (strncmp (s->s_name, ".comment", 8) == 0) - s->s_flags |= STYP_INFO; - - while (frag) - { - unsigned int fill_size; - switch (frag->fr_type) - { - case rs_machine_dependent: - if (frag->fr_fix) - { - memcpy (buffer + frag->fr_address, - frag->fr_literal, - (unsigned int) frag->fr_fix); - offset += frag->fr_fix; - } - - break; - case rs_space: - assert (frag->fr_symbol == 0); - case rs_fill: - case rs_align: - case rs_align_code: - case rs_org: - if (frag->fr_fix) - { - memcpy (buffer + frag->fr_address, - frag->fr_literal, - (unsigned int) frag->fr_fix); - offset += frag->fr_fix; - } - - fill_size = frag->fr_var; - if (fill_size && frag->fr_offset > 0) - { - unsigned int count; - unsigned int off = frag->fr_fix; - for (count = frag->fr_offset; count; count--) - { - if (fill_size + frag->fr_address + off <= s->s_size) - { - memcpy (buffer + frag->fr_address + off, - frag->fr_literal + frag->fr_fix, - fill_size); - off += fill_size; - offset += fill_size; - } - } - } - break; - case rs_broken_word: - break; - default: - abort (); - } - frag = frag->fr_next; - } - - if (s->s_size != 0) - { - if (s->s_scnptr != 0) - { - bfd_write (buffer, s->s_size, 1, abfd); - *file_cursor += s->s_size; - } - free (buffer); - } - paddr += s->s_size; - } - } -} - -/* Coff file generation & utilities */ - -static void -coff_header_append (abfd, h) - bfd * abfd; - object_headers * h; -{ - unsigned int i; - char buffer[1000]; - char buffero[1000]; -#ifdef COFF_LONG_SECTION_NAMES - unsigned long string_size = 4; -#endif - - bfd_seek (abfd, 0, 0); - -#ifndef OBJ_COFF_OMIT_OPTIONAL_HEADER - H_SET_MAGIC_NUMBER (h, COFF_MAGIC); - H_SET_VERSION_STAMP (h, 0); - H_SET_ENTRY_POINT (h, 0); - H_SET_TEXT_START (h, segment_info[SEG_E0].frchainP->frch_root->fr_address); - H_SET_DATA_START (h, segment_info[SEG_E1].frchainP->frch_root->fr_address); - H_SET_SIZEOF_OPTIONAL_HEADER (h, bfd_coff_swap_aouthdr_out(abfd, &h->aouthdr, - buffero)); -#else /* defined (OBJ_COFF_OMIT_OPTIONAL_HEADER) */ - H_SET_SIZEOF_OPTIONAL_HEADER (h, 0); -#endif /* defined (OBJ_COFF_OMIT_OPTIONAL_HEADER) */ - - i = bfd_coff_swap_filehdr_out (abfd, &h->filehdr, buffer); - - bfd_write (buffer, i, 1, abfd); - bfd_write (buffero, H_GET_SIZEOF_OPTIONAL_HEADER (h), 1, abfd); - - for (i = SEG_E0; i < SEG_LAST; i++) - { - if (segment_info[i].scnhdr.s_name[0]) - { - unsigned int size; - -#ifdef COFF_LONG_SECTION_NAMES - /* Support long section names as found in PE. This code - must coordinate with that in write_object_file and - w_strings. */ - if (strlen (segment_info[i].name) > SCNNMLEN) - { - memset (segment_info[i].scnhdr.s_name, 0, SCNNMLEN); - sprintf (segment_info[i].scnhdr.s_name, "/%lu", string_size); - string_size += strlen (segment_info[i].name) + 1; - } -#endif - - size = bfd_coff_swap_scnhdr_out (abfd, - &(segment_info[i].scnhdr), - buffer); - if (size == 0) - as_bad (_("bfd_coff_swap_scnhdr_out failed")); - bfd_write (buffer, size, 1, abfd); - } - } -} - - -char * -symbol_to_chars (abfd, where, symbolP) - bfd * abfd; - char *where; - symbolS * symbolP; -{ - unsigned int numaux = symbolP->sy_symbol.ost_entry.n_numaux; - unsigned int i; - valueT val; - - /* Turn any symbols with register attributes into abs symbols */ - if (S_GET_SEGMENT (symbolP) == reg_section) - { - S_SET_SEGMENT (symbolP, absolute_section); - } - /* At the same time, relocate all symbols to their output value */ - -#ifndef TE_PE - val = (segment_info[S_GET_SEGMENT (symbolP)].scnhdr.s_paddr - + S_GET_VALUE (symbolP)); -#else - val = S_GET_VALUE (symbolP); -#endif - - S_SET_VALUE (symbolP, val); - - symbolP->sy_symbol.ost_entry.n_value = val; - - where += bfd_coff_swap_sym_out (abfd, &symbolP->sy_symbol.ost_entry, - where); - - for (i = 0; i < numaux; i++) - { - where += bfd_coff_swap_aux_out (abfd, - &symbolP->sy_symbol.ost_auxent[i], - S_GET_DATA_TYPE (symbolP), - S_GET_STORAGE_CLASS (symbolP), - i, numaux, where); - } - return where; - -} - -void -coff_obj_symbol_new_hook (symbolP) - symbolS *symbolP; -{ - char underscore = 0; /* Symbol has leading _ */ - - /* Effective symbol */ - /* Store the pointer in the offset. */ - S_SET_ZEROES (symbolP, 0L); - S_SET_DATA_TYPE (symbolP, T_NULL); - S_SET_STORAGE_CLASS (symbolP, 0); - S_SET_NUMBER_AUXILIARY (symbolP, 0); - /* Additional information */ - symbolP->sy_symbol.ost_flags = 0; - /* Auxiliary entries */ - memset ((char *) &symbolP->sy_symbol.ost_auxent[0], 0, AUXESZ); - - if (S_IS_STRING (symbolP)) - SF_SET_STRING (symbolP); - if (!underscore && S_IS_LOCAL (symbolP)) - SF_SET_LOCAL (symbolP); -} - -/* - * Handle .ln directives. - */ - -static void -obj_coff_ln (appline) - int appline; -{ - int l; - - if (! appline && def_symbol_in_progress != NULL) - { - as_warn (_(".ln pseudo-op inside .def/.endef: ignored.")); - demand_empty_rest_of_line (); - return; - } /* wrong context */ - - l = get_absolute_expression (); - c_line_new (0, frag_now_fix (), l, frag_now); - - if (appline) - new_logical_line ((char *) NULL, l - 1); - -#ifndef NO_LISTING - { - extern int listing; - - if (listing) - { - if (! appline) - l += line_base - 1; - listing_source_line ((unsigned int) l); - } - - } -#endif - demand_empty_rest_of_line (); -} - -/* - * def() - * - * Handle .def directives. - * - * One might ask : why can't we symbol_new if the symbol does not - * already exist and fill it with debug information. Because of - * the C_EFCN special symbol. It would clobber the value of the - * function symbol before we have a chance to notice that it is - * a C_EFCN. And a second reason is that the code is more clear this - * way. (at least I think it is :-). - * - */ - -#define SKIP_SEMI_COLON() while (*input_line_pointer++ != ';') -#define SKIP_WHITESPACES() while (*input_line_pointer == ' ' || \ - *input_line_pointer == '\t') \ - input_line_pointer++; - -static void -obj_coff_def (what) - int what ATTRIBUTE_UNUSED; -{ - char name_end; /* Char after the end of name */ - char *symbol_name; /* Name of the debug symbol */ - char *symbol_name_copy; /* Temporary copy of the name */ - unsigned int symbol_name_length; - - if (def_symbol_in_progress != NULL) - { - as_warn (_(".def pseudo-op used inside of .def/.endef: ignored.")); - demand_empty_rest_of_line (); - return; - } /* if not inside .def/.endef */ - - SKIP_WHITESPACES (); - - def_symbol_in_progress = (symbolS *) obstack_alloc (¬es, sizeof (*def_symbol_in_progress)); - memset (def_symbol_in_progress, 0, sizeof (*def_symbol_in_progress)); - - symbol_name = input_line_pointer; - name_end = get_symbol_end (); - symbol_name_length = strlen (symbol_name); - symbol_name_copy = xmalloc (symbol_name_length + 1); - strcpy (symbol_name_copy, symbol_name); -#ifdef tc_canonicalize_symbol_name - symbol_name_copy = tc_canonicalize_symbol_name (symbol_name_copy); -#endif - - /* Initialize the new symbol */ -#ifdef STRIP_UNDERSCORE - S_SET_NAME (def_symbol_in_progress, (*symbol_name_copy == '_' - ? symbol_name_copy + 1 - : symbol_name_copy)); -#else /* STRIP_UNDERSCORE */ - S_SET_NAME (def_symbol_in_progress, symbol_name_copy); -#endif /* STRIP_UNDERSCORE */ - /* free(symbol_name_copy); */ - def_symbol_in_progress->sy_name_offset = (unsigned long) ~0; - def_symbol_in_progress->sy_number = ~0; - def_symbol_in_progress->sy_frag = &zero_address_frag; - S_SET_VALUE (def_symbol_in_progress, 0); - - if (S_IS_STRING (def_symbol_in_progress)) - SF_SET_STRING (def_symbol_in_progress); - - *input_line_pointer = name_end; - - demand_empty_rest_of_line (); -} - -unsigned int dim_index; - - -static void -obj_coff_endef (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - symbolS *symbolP = 0; - /* DIM BUG FIX sac@cygnus.com */ - dim_index = 0; - if (def_symbol_in_progress == NULL) - { - as_warn (_(".endef pseudo-op used outside of .def/.endef: ignored.")); - demand_empty_rest_of_line (); - return; - } /* if not inside .def/.endef */ - - /* Set the section number according to storage class. */ - switch (S_GET_STORAGE_CLASS (def_symbol_in_progress)) - { - case C_STRTAG: - case C_ENTAG: - case C_UNTAG: - SF_SET_TAG (def_symbol_in_progress); - /* intentional fallthrough */ - case C_FILE: - case C_TPDEF: - SF_SET_DEBUG (def_symbol_in_progress); - S_SET_SEGMENT (def_symbol_in_progress, SEG_DEBUG); - break; - - case C_EFCN: - SF_SET_LOCAL (def_symbol_in_progress); /* Do not emit this symbol. */ - /* intentional fallthrough */ - case C_BLOCK: - SF_SET_PROCESS (def_symbol_in_progress); /* Will need processing before writing */ - /* intentional fallthrough */ - case C_FCN: - S_SET_SEGMENT (def_symbol_in_progress, SEG_E0); - - if (strcmp (S_GET_NAME (def_symbol_in_progress), ".bf") == 0) - { /* .bf */ - if (function_lineoff < 0) - { - fprintf (stderr, _("`.bf' symbol without preceding function\n")); - } /* missing function symbol */ - SA_GET_SYM_LNNOPTR (last_line_symbol) = function_lineoff; - - SF_SET_PROCESS (last_line_symbol); - SF_SET_ADJ_LNNOPTR (last_line_symbol); - SF_SET_PROCESS (def_symbol_in_progress); - function_lineoff = -1; - } - /* Value is always set to . */ - def_symbol_in_progress->sy_frag = frag_now; - S_SET_VALUE (def_symbol_in_progress, (valueT) frag_now_fix ()); - break; - -#ifdef C_AUTOARG - case C_AUTOARG: -#endif /* C_AUTOARG */ - case C_AUTO: - case C_REG: - case C_MOS: - case C_MOE: - case C_MOU: - case C_ARG: - case C_REGPARM: - case C_FIELD: - case C_EOS: - SF_SET_DEBUG (def_symbol_in_progress); - S_SET_SEGMENT (def_symbol_in_progress, absolute_section); - break; - - case C_EXT: - case C_WEAKEXT: -#ifdef TE_PE - case C_NT_WEAK: -#endif - case C_STAT: - case C_LABEL: - /* Valid but set somewhere else (s_comm, s_lcomm, colon) */ - break; - - case C_USTATIC: - case C_EXTDEF: - case C_ULABEL: - as_warn (_("unexpected storage class %d"), S_GET_STORAGE_CLASS (def_symbol_in_progress)); - break; - } /* switch on storage class */ - - /* Now that we have built a debug symbol, try to find if we should - merge with an existing symbol or not. If a symbol is C_EFCN or - absolute_section or untagged SEG_DEBUG it never merges. We also - don't merge labels, which are in a different namespace, nor - symbols which have not yet been defined since they are typically - unique, nor do we merge tags with non-tags. */ - - /* Two cases for functions. Either debug followed by definition or - definition followed by debug. For definition first, we will - merge the debug symbol into the definition. For debug first, the - lineno entry MUST point to the definition function or else it - will point off into space when crawl_symbols() merges the debug - symbol into the real symbol. Therefor, let's presume the debug - symbol is a real function reference. */ - - /* FIXME-SOON If for some reason the definition label/symbol is - never seen, this will probably leave an undefined symbol at link - time. */ - - if (S_GET_STORAGE_CLASS (def_symbol_in_progress) == C_EFCN - || S_GET_STORAGE_CLASS (def_symbol_in_progress) == C_LABEL - || (S_GET_SEGMENT (def_symbol_in_progress) == SEG_DEBUG - && !SF_GET_TAG (def_symbol_in_progress)) - || S_GET_SEGMENT (def_symbol_in_progress) == absolute_section - || def_symbol_in_progress->sy_value.X_op != O_constant - || (symbolP = symbol_find_base (S_GET_NAME (def_symbol_in_progress), DO_NOT_STRIP)) == NULL - || (SF_GET_TAG (def_symbol_in_progress) != SF_GET_TAG (symbolP))) - { - symbol_append (def_symbol_in_progress, symbol_lastP, &symbol_rootP, - &symbol_lastP); - } - else - { - /* This symbol already exists, merge the newly created symbol - into the old one. This is not mandatory. The linker can - handle duplicate symbols correctly. But I guess that it save - a *lot* of space if the assembly file defines a lot of - symbols. [loic] */ - - /* The debug entry (def_symbol_in_progress) is merged into the - previous definition. */ - - c_symbol_merge (def_symbol_in_progress, symbolP); - /* FIXME-SOON Should *def_symbol_in_progress be free'd? xoxorich. */ - def_symbol_in_progress = symbolP; - - if (SF_GET_FUNCTION (def_symbol_in_progress) - || SF_GET_TAG (def_symbol_in_progress) - || S_GET_STORAGE_CLASS (def_symbol_in_progress) == C_STAT) - { - /* For functions, and tags, and static symbols, the symbol - *must* be where the debug symbol appears. Move the - existing symbol to the current place. */ - /* If it already is at the end of the symbol list, do nothing */ - if (def_symbol_in_progress != symbol_lastP) - { - symbol_remove (def_symbol_in_progress, &symbol_rootP, - &symbol_lastP); - symbol_append (def_symbol_in_progress, symbol_lastP, - &symbol_rootP, &symbol_lastP); - } /* if not already in place */ - } /* if function */ - } /* normal or mergable */ - - if (SF_GET_TAG (def_symbol_in_progress)) - { - symbolS *oldtag; - - oldtag = symbol_find_base (S_GET_NAME (def_symbol_in_progress), - DO_NOT_STRIP); - if (oldtag == NULL || ! SF_GET_TAG (oldtag)) - tag_insert (S_GET_NAME (def_symbol_in_progress), - def_symbol_in_progress); - } - - if (SF_GET_FUNCTION (def_symbol_in_progress)) - { - know (sizeof (def_symbol_in_progress) <= sizeof (long)); - function_lineoff - = c_line_new (def_symbol_in_progress, 0, 0, &zero_address_frag); - - SF_SET_PROCESS (def_symbol_in_progress); - - if (symbolP == NULL) - { - /* That is, if this is the first time we've seen the - function... */ - symbol_table_insert (def_symbol_in_progress); - } /* definition follows debug */ - } /* Create the line number entry pointing to the function being defined */ - - def_symbol_in_progress = NULL; - demand_empty_rest_of_line (); -} - -static void -obj_coff_dim (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - int dim_index; - - if (def_symbol_in_progress == NULL) - { - as_warn (_(".dim pseudo-op used outside of .def/.endef: ignored.")); - demand_empty_rest_of_line (); - return; - } /* if not inside .def/.endef */ - - S_SET_NUMBER_AUXILIARY (def_symbol_in_progress, 1); - - for (dim_index = 0; dim_index < DIMNUM; dim_index++) - { - SKIP_WHITESPACES (); - SA_SET_SYM_DIMEN (def_symbol_in_progress, dim_index, - get_absolute_expression ()); - - switch (*input_line_pointer) - { - case ',': - input_line_pointer++; - break; - - default: - as_warn (_("badly formed .dim directive ignored")); - /* intentional fallthrough */ - case '\n': - case ';': - dim_index = DIMNUM; - break; - } - } - - demand_empty_rest_of_line (); -} - -static void -obj_coff_line (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - int this_base; - const char *name; - - if (def_symbol_in_progress == NULL) - { - obj_coff_ln (0); - return; - } - - name = S_GET_NAME (def_symbol_in_progress); - this_base = get_absolute_expression (); - - /* Only .bf symbols indicate the use of a new base line number; the - line numbers associated with .ef, .bb, .eb are relative to the - start of the containing function. */ - if (!strcmp (".bf", name)) - { -#if 0 /* XXX Can we ever have line numbers going backwards? */ - if (this_base > line_base) -#endif - { - line_base = this_base; - } - -#ifndef NO_LISTING - { - extern int listing; - if (listing) - { - listing_source_line ((unsigned int) line_base); - } - } -#endif - } - - S_SET_NUMBER_AUXILIARY (def_symbol_in_progress, 1); - SA_SET_SYM_LNNO (def_symbol_in_progress, this_base); - - demand_empty_rest_of_line (); -} - -static void -obj_coff_size (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - if (def_symbol_in_progress == NULL) - { - as_warn (_(".size pseudo-op used outside of .def/.endef ignored.")); - demand_empty_rest_of_line (); - return; - } /* if not inside .def/.endef */ - - S_SET_NUMBER_AUXILIARY (def_symbol_in_progress, 1); - SA_SET_SYM_SIZE (def_symbol_in_progress, get_absolute_expression ()); - demand_empty_rest_of_line (); -} - -static void -obj_coff_scl (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - if (def_symbol_in_progress == NULL) - { - as_warn (_(".scl pseudo-op used outside of .def/.endef ignored.")); - demand_empty_rest_of_line (); - return; - } /* if not inside .def/.endef */ - - S_SET_STORAGE_CLASS (def_symbol_in_progress, get_absolute_expression ()); - demand_empty_rest_of_line (); -} - -static void -obj_coff_tag (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - char *symbol_name; - char name_end; - - if (def_symbol_in_progress == NULL) - { - as_warn (_(".tag pseudo-op used outside of .def/.endef ignored.")); - demand_empty_rest_of_line (); - return; - } - - S_SET_NUMBER_AUXILIARY (def_symbol_in_progress, 1); - symbol_name = input_line_pointer; - name_end = get_symbol_end (); -#ifdef tc_canonicalize_symbol_name - symbol_name = tc_canonicalize_symbol_name (symbol_name); -#endif - - /* Assume that the symbol referred to by .tag is always defined. - This was a bad assumption. I've added find_or_make. xoxorich. */ - SA_SET_SYM_TAGNDX (def_symbol_in_progress, - (long) tag_find_or_make (symbol_name)); - if (SA_GET_SYM_TAGNDX (def_symbol_in_progress) == 0L) - { - as_warn (_("tag not found for .tag %s"), symbol_name); - } /* not defined */ - - SF_SET_TAGGED (def_symbol_in_progress); - *input_line_pointer = name_end; - - demand_empty_rest_of_line (); -} - -static void -obj_coff_type (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - if (def_symbol_in_progress == NULL) - { - as_warn (_(".type pseudo-op used outside of .def/.endef ignored.")); - demand_empty_rest_of_line (); - return; - } /* if not inside .def/.endef */ - - S_SET_DATA_TYPE (def_symbol_in_progress, get_absolute_expression ()); - - if (ISFCN (S_GET_DATA_TYPE (def_symbol_in_progress)) && - S_GET_STORAGE_CLASS (def_symbol_in_progress) != C_TPDEF) - { - SF_SET_FUNCTION (def_symbol_in_progress); - } /* is a function */ - - demand_empty_rest_of_line (); -} - -static void -obj_coff_val (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - if (def_symbol_in_progress == NULL) - { - as_warn (_(".val pseudo-op used outside of .def/.endef ignored.")); - demand_empty_rest_of_line (); - return; - } /* if not inside .def/.endef */ - - if (is_name_beginner (*input_line_pointer)) - { - char *symbol_name = input_line_pointer; - char name_end = get_symbol_end (); - -#ifdef tc_canonicalize_symbol_name - symbol_name = tc_canonicalize_symbol_name (symbol_name); -#endif - - if (!strcmp (symbol_name, ".")) - { - def_symbol_in_progress->sy_frag = frag_now; - S_SET_VALUE (def_symbol_in_progress, (valueT) frag_now_fix ()); - /* If the .val is != from the .def (e.g. statics) */ - } - else if (strcmp (S_GET_NAME (def_symbol_in_progress), symbol_name)) - { - def_symbol_in_progress->sy_value.X_op = O_symbol; - def_symbol_in_progress->sy_value.X_add_symbol = - symbol_find_or_make (symbol_name); - def_symbol_in_progress->sy_value.X_op_symbol = NULL; - def_symbol_in_progress->sy_value.X_add_number = 0; - - /* If the segment is undefined when the forward reference is - resolved, then copy the segment id from the forward - symbol. */ - SF_SET_GET_SEGMENT (def_symbol_in_progress); - - /* FIXME: gcc can generate address expressions here in - unusual cases (search for "obscure" in sdbout.c). We - just ignore the offset here, thus generating incorrect - debugging information. We ignore the rest of the line - just below. */ - } - /* Otherwise, it is the name of a non debug symbol and - its value will be calculated later. */ - *input_line_pointer = name_end; - - /* FIXME: this is to avoid an error message in the - FIXME case mentioned just above. */ - while (! is_end_of_line[(unsigned char) *input_line_pointer]) - ++input_line_pointer; - } - else - { - S_SET_VALUE (def_symbol_in_progress, - (valueT) get_absolute_expression ()); - } /* if symbol based */ - - demand_empty_rest_of_line (); -} - -#ifdef TE_PE - -/* Handle the .linkonce pseudo-op. This is parsed by s_linkonce in - read.c, which then calls this object file format specific routine. */ - -void -obj_coff_pe_handle_link_once (type) - enum linkonce_type type; -{ - seg_info (now_seg)->scnhdr.s_flags |= IMAGE_SCN_LNK_COMDAT; - - /* We store the type in the seg_info structure, and use it to set up - the auxiliary entry for the section symbol in c_section_symbol. */ - seg_info (now_seg)->linkonce = type; -} - -#endif /* TE_PE */ - -void -coff_obj_read_begin_hook () -{ - /* These had better be the same. Usually 18 bytes. */ -#ifndef BFD_HEADERS - know (sizeof (SYMENT) == sizeof (AUXENT)); - know (SYMESZ == AUXESZ); -#endif - tag_init (); -} - -/* This function runs through the symbol table and puts all the - externals onto another chain */ - -/* The chain of globals. */ -symbolS *symbol_globalP; -symbolS *symbol_global_lastP; - -/* The chain of externals */ -symbolS *symbol_externP; -symbolS *symbol_extern_lastP; - -stack *block_stack; -symbolS *last_functionP; -static symbolS *last_bfP; -symbolS *last_tagP; - -static unsigned int -yank_symbols () -{ - symbolS *symbolP; - unsigned int symbol_number = 0; - unsigned int last_file_symno = 0; - - struct filename_list *filename_list_scan = filename_list_head; - - for (symbolP = symbol_rootP; - symbolP; - symbolP = symbolP ? symbol_next (symbolP) : symbol_rootP) - { - if (symbolP->sy_mri_common) - { - if (S_GET_STORAGE_CLASS (symbolP) == C_EXT -#ifdef TE_PE - || S_GET_STORAGE_CLASS (symbolP) == C_NT_WEAK -#endif - || S_GET_STORAGE_CLASS (symbolP) == C_WEAKEXT) - as_bad (_("%s: global symbols not supported in common sections"), - S_GET_NAME (symbolP)); - symbol_remove (symbolP, &symbol_rootP, &symbol_lastP); - continue; - } - - if (!SF_GET_DEBUG (symbolP)) - { - /* Debug symbols do not need all this rubbish */ - symbolS *real_symbolP; - - /* L* and C_EFCN symbols never merge. */ - if (!SF_GET_LOCAL (symbolP) - && !SF_GET_STATICS (symbolP) - && S_GET_STORAGE_CLASS (symbolP) != C_LABEL - && symbolP->sy_value.X_op == O_constant - && (real_symbolP = symbol_find_base (S_GET_NAME (symbolP), DO_NOT_STRIP)) - && real_symbolP != symbolP) - { - /* FIXME-SOON: where do dups come from? - Maybe tag references before definitions? xoxorich. */ - /* Move the debug data from the debug symbol to the - real symbol. Do NOT do the oposite (i.e. move from - real symbol to debug symbol and remove real symbol from the - list.) Because some pointers refer to the real symbol - whereas no pointers refer to the debug symbol. */ - c_symbol_merge (symbolP, real_symbolP); - /* Replace the current symbol by the real one */ - /* The symbols will never be the last or the first - because : 1st symbol is .file and 3 last symbols are - .text, .data, .bss */ - symbol_remove (real_symbolP, &symbol_rootP, &symbol_lastP); - symbol_insert (real_symbolP, symbolP, &symbol_rootP, &symbol_lastP); - symbol_remove (symbolP, &symbol_rootP, &symbol_lastP); - symbolP = real_symbolP; - } /* if not local but dup'd */ - - if (flag_readonly_data_in_text && (S_GET_SEGMENT (symbolP) == SEG_E1)) - { - S_SET_SEGMENT (symbolP, SEG_E0); - } /* push data into text */ - - resolve_symbol_value (symbolP, 1); - - if (S_GET_STORAGE_CLASS (symbolP) == C_NULL) - { - if (!S_IS_DEFINED (symbolP) && !SF_GET_LOCAL (symbolP)) - { - S_SET_EXTERNAL (symbolP); - } - else if (S_GET_SEGMENT (symbolP) == SEG_E0) - { - S_SET_STORAGE_CLASS (symbolP, C_LABEL); - } - else - { - S_SET_STORAGE_CLASS (symbolP, C_STAT); - } - } - - /* Mainly to speed up if not -g */ - if (SF_GET_PROCESS (symbolP)) - { - /* Handle the nested blocks auxiliary info. */ - if (S_GET_STORAGE_CLASS (symbolP) == C_BLOCK) - { - if (!strcmp (S_GET_NAME (symbolP), ".bb")) - stack_push (block_stack, (char *) &symbolP); - else - { /* .eb */ - register symbolS *begin_symbolP; - begin_symbolP = *(symbolS **) stack_pop (block_stack); - if (begin_symbolP == (symbolS *) 0) - as_warn (_("mismatched .eb")); - else - SA_SET_SYM_ENDNDX (begin_symbolP, symbol_number + 2); - } - } - /* If we are able to identify the type of a function, and we - are out of a function (last_functionP == 0) then, the - function symbol will be associated with an auxiliary - entry. */ - if (last_functionP == (symbolS *) 0 && - SF_GET_FUNCTION (symbolP)) - { - last_functionP = symbolP; - - if (S_GET_NUMBER_AUXILIARY (symbolP) < 1) - { - S_SET_NUMBER_AUXILIARY (symbolP, 1); - } /* make it at least 1 */ - - /* Clobber possible stale .dim information. */ -#if 0 - /* Iffed out by steve - this fries the lnnoptr info too */ - bzero (symbolP->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_ary.x_dimen, - sizeof (symbolP->sy_symbol.ost_auxent[0].x_sym.x_fcnary.x_ary.x_dimen)); -#endif - } - if (S_GET_STORAGE_CLASS (symbolP) == C_FCN) - { - if (strcmp (S_GET_NAME (symbolP), ".bf") == 0) - { - if (last_bfP != NULL) - SA_SET_SYM_ENDNDX (last_bfP, symbol_number); - last_bfP = symbolP; - } - } - else if (S_GET_STORAGE_CLASS (symbolP) == C_EFCN) - { - /* I don't even know if this is needed for sdb. But - the standard assembler generates it, so... */ - if (last_functionP == (symbolS *) 0) - as_fatal (_("C_EFCN symbol out of scope")); - SA_SET_SYM_FSIZE (last_functionP, - (long) (S_GET_VALUE (symbolP) - - S_GET_VALUE (last_functionP))); - SA_SET_SYM_ENDNDX (last_functionP, symbol_number); - last_functionP = (symbolS *) 0; - } - } - } - else if (SF_GET_TAG (symbolP)) - { - /* First descriptor of a structure must point to - the first slot after the structure description. */ - last_tagP = symbolP; - - } - else if (S_GET_STORAGE_CLASS (symbolP) == C_EOS) - { - /* +2 take in account the current symbol */ - SA_SET_SYM_ENDNDX (last_tagP, symbol_number + 2); - } - else if (S_GET_STORAGE_CLASS (symbolP) == C_FILE) - { - /* If the filename was too long to fit in the - auxent, put it in the string table */ - if (SA_GET_FILE_FNAME_ZEROS (symbolP) == 0 - && SA_GET_FILE_FNAME_OFFSET (symbolP) != 0) - { - SA_SET_FILE_FNAME_OFFSET (symbolP, string_byte_count); - string_byte_count += strlen (filename_list_scan->filename) + 1; - filename_list_scan = filename_list_scan->next; - } - if (S_GET_VALUE (symbolP)) - { - S_SET_VALUE (symbolP, last_file_symno); - last_file_symno = symbol_number; - } /* no one points at the first .file symbol */ - } /* if debug or tag or eos or file */ - -#ifdef tc_frob_coff_symbol - tc_frob_coff_symbol (symbolP); -#endif - - /* We must put the external symbols apart. The loader - does not bomb if we do not. But the references in - the endndx field for a .bb symbol are not corrected - if an external symbol is removed between .bb and .be. - I.e in the following case : - [20] .bb endndx = 22 - [21] foo external - [22] .be - ld will move the symbol 21 to the end of the list but - endndx will still be 22 instead of 21. */ - - - if (SF_GET_LOCAL (symbolP)) - { - /* remove C_EFCN and LOCAL (L...) symbols */ - /* next pointer remains valid */ - symbol_remove (symbolP, &symbol_rootP, &symbol_lastP); - - } - else if (symbolP->sy_value.X_op == O_symbol - && (! S_IS_DEFINED (symbolP) || S_IS_COMMON (symbolP))) - { - /* Skip symbols which were equated to undefined or common - symbols. */ - symbol_remove (symbolP, &symbol_rootP, &symbol_lastP); - } - else if (!S_IS_DEFINED (symbolP) - && !S_IS_DEBUG (symbolP) - && !SF_GET_STATICS (symbolP) - && (S_GET_STORAGE_CLASS (symbolP) == C_EXT -#ifdef TE_PE - || S_GET_STORAGE_CLASS (symbolP) == C_NT_WEAK -#endif - || S_GET_STORAGE_CLASS (symbolP) == C_WEAKEXT)) - { - /* if external, Remove from the list */ - symbolS *hold = symbol_previous (symbolP); - - symbol_remove (symbolP, &symbol_rootP, &symbol_lastP); - symbol_clear_list_pointers (symbolP); - symbol_append (symbolP, symbol_extern_lastP, &symbol_externP, &symbol_extern_lastP); - symbolP = hold; - } - else if (! S_IS_DEBUG (symbolP) - && ! SF_GET_STATICS (symbolP) - && ! SF_GET_FUNCTION (symbolP) - && (S_GET_STORAGE_CLASS (symbolP) == C_EXT -#ifdef TE_PE - || S_GET_STORAGE_CLASS (symbolP) == C_NT_WEAK -#endif - || S_GET_STORAGE_CLASS (symbolP) == C_NT_WEAK)) - { - symbolS *hold = symbol_previous (symbolP); - - /* The O'Reilly COFF book says that defined global symbols - come at the end of the symbol table, just before - undefined global symbols. */ - - symbol_remove (symbolP, &symbol_rootP, &symbol_lastP); - symbol_clear_list_pointers (symbolP); - symbol_append (symbolP, symbol_global_lastP, &symbol_globalP, - &symbol_global_lastP); - symbolP = hold; - } - else - { - if (SF_GET_STRING (symbolP)) - { - symbolP->sy_name_offset = string_byte_count; - string_byte_count += strlen (S_GET_NAME (symbolP)) + 1; - } - else - { - symbolP->sy_name_offset = 0; - } /* fix "long" names */ - - symbolP->sy_number = symbol_number; - symbol_number += 1 + S_GET_NUMBER_AUXILIARY (symbolP); - } /* if local symbol */ - } /* traverse the symbol list */ - return symbol_number; - -} - - -static unsigned int -glue_symbols (head, tail) - symbolS **head; - symbolS **tail; -{ - unsigned int symbol_number = 0; - - while (*head != NULL) - { - symbolS *tmp = *head; - - /* append */ - symbol_remove (tmp, head, tail); - symbol_append (tmp, symbol_lastP, &symbol_rootP, &symbol_lastP); - - /* and process */ - if (SF_GET_STRING (tmp)) - { - tmp->sy_name_offset = string_byte_count; - string_byte_count += strlen (S_GET_NAME (tmp)) + 1; - } - else - { - tmp->sy_name_offset = 0; - } /* fix "long" names */ - - tmp->sy_number = symbol_number; - symbol_number += 1 + S_GET_NUMBER_AUXILIARY (tmp); - } /* append the entire extern chain */ - - return symbol_number; -} - -static unsigned int -tie_tags () -{ - unsigned int symbol_number = 0; - symbolS *symbolP; - - for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP)) - { - symbolP->sy_number = symbol_number; - - if (SF_GET_TAGGED (symbolP)) - { - SA_SET_SYM_TAGNDX - (symbolP, - ((symbolS *) SA_GET_SYM_TAGNDX (symbolP))->sy_number); - } - - symbol_number += 1 + S_GET_NUMBER_AUXILIARY (symbolP); - } - - return symbol_number; -} - -static void -crawl_symbols (h, abfd) - object_headers *h; - bfd *abfd ATTRIBUTE_UNUSED; -{ - unsigned int i; - - /* Initialize the stack used to keep track of the matching .bb .be */ - - block_stack = stack_init (512, sizeof (symbolS *)); - - /* The symbol list should be ordered according to the following sequence - * order : - * . .file symbol - * . debug entries for functions - * . fake symbols for the sections, including .text .data and .bss - * . defined symbols - * . undefined symbols - * But this is not mandatory. The only important point is to put the - * undefined symbols at the end of the list. - */ - - /* Is there a .file symbol ? If not insert one at the beginning. */ - if (symbol_rootP == NULL - || S_GET_STORAGE_CLASS (symbol_rootP) != C_FILE) - { - c_dot_file_symbol ("fake"); - } - - /* - * Build up static symbols for the sections, they are filled in later - */ - - - for (i = SEG_E0; i < SEG_LAST; i++) - if (segment_info[i].scnhdr.s_name[0]) - segment_info[i].dot = c_section_symbol (segment_info[i].name, - i - SEG_E0 + 1); - - /* Take all the externals out and put them into another chain */ - H_SET_SYMBOL_TABLE_SIZE (h, yank_symbols ()); - /* Take the externals and glue them onto the end.*/ - H_SET_SYMBOL_TABLE_SIZE (h, - (H_GET_SYMBOL_COUNT (h) - + glue_symbols (&symbol_globalP, - &symbol_global_lastP) - + glue_symbols (&symbol_externP, - &symbol_extern_lastP))); - - H_SET_SYMBOL_TABLE_SIZE (h, tie_tags ()); - know (symbol_globalP == NULL); - know (symbol_global_lastP == NULL); - know (symbol_externP == NULL); - know (symbol_extern_lastP == NULL); -} - -/* - * Find strings by crawling along symbol table chain. - */ - -void -w_strings (where) - char *where; -{ - symbolS *symbolP; - struct filename_list *filename_list_scan = filename_list_head; - - /* Gotta do md_ byte-ordering stuff for string_byte_count first - KWK */ - md_number_to_chars (where, (valueT) string_byte_count, 4); - where += 4; - -#ifdef COFF_LONG_SECTION_NAMES - /* Support long section names as found in PE. This code must - coordinate with that in coff_header_append and write_object_file. */ - { - unsigned int i; - - for (i = SEG_E0; i < SEG_LAST; i++) - { - if (segment_info[i].scnhdr.s_name[0] - && strlen (segment_info[i].name) > SCNNMLEN) - { - unsigned int size; - - size = strlen (segment_info[i].name) + 1; - memcpy (where, segment_info[i].name, size); - where += size; - } - } - } -#endif /* COFF_LONG_SECTION_NAMES */ - - for (symbolP = symbol_rootP; - symbolP; - symbolP = symbol_next (symbolP)) - { - unsigned int size; - - if (SF_GET_STRING (symbolP)) - { - size = strlen (S_GET_NAME (symbolP)) + 1; - memcpy (where, S_GET_NAME (symbolP), size); - where += size; - } - if (S_GET_STORAGE_CLASS (symbolP) == C_FILE - && SA_GET_FILE_FNAME_ZEROS (symbolP) == 0 - && SA_GET_FILE_FNAME_OFFSET (symbolP) != 0) - { - size = strlen (filename_list_scan->filename) + 1; - memcpy (where, filename_list_scan->filename, size); - filename_list_scan = filename_list_scan ->next; - where += size; - } - } -} - -static void -do_linenos_for (abfd, h, file_cursor) - bfd * abfd; - object_headers * h; - unsigned long *file_cursor; -{ - unsigned int idx; - unsigned long start = *file_cursor; - - for (idx = SEG_E0; idx < SEG_LAST; idx++) - { - segment_info_type *s = segment_info + idx; - - - if (s->scnhdr.s_nlnno != 0) - { - struct lineno_list *line_ptr; - - struct external_lineno *buffer = - (struct external_lineno *) xmalloc (s->scnhdr.s_nlnno * LINESZ); - - struct external_lineno *dst = buffer; - - /* Run through the table we've built and turn it into its external - form, take this chance to remove duplicates */ - - for (line_ptr = s->lineno_list_head; - line_ptr != (struct lineno_list *) NULL; - line_ptr = line_ptr->next) - { - - if (line_ptr->line.l_lnno == 0) - { - /* Turn a pointer to a symbol into the symbols' index */ - line_ptr->line.l_addr.l_symndx = - ((symbolS *) line_ptr->line.l_addr.l_symndx)->sy_number; - } - else - { - line_ptr->line.l_addr.l_paddr += ((struct frag *) (line_ptr->frag))->fr_address; - } - - - (void) bfd_coff_swap_lineno_out (abfd, &(line_ptr->line), dst); - dst++; - - } - - s->scnhdr.s_lnnoptr = *file_cursor; - - bfd_write (buffer, 1, s->scnhdr.s_nlnno * LINESZ, abfd); - free (buffer); - - *file_cursor += s->scnhdr.s_nlnno * LINESZ; - } - } - H_SET_LINENO_SIZE (h, *file_cursor - start); -} - - -/* Now we run through the list of frag chains in a segment and - make all the subsegment frags appear at the end of the - list, as if the seg 0 was extra long */ - -static void -remove_subsegs () -{ - unsigned int i; - - for (i = SEG_E0; i < SEG_UNKNOWN; i++) - { - frchainS *head = segment_info[i].frchainP; - fragS dummy; - fragS *prev_frag = &dummy; - - while (head && head->frch_seg == i) - { - prev_frag->fr_next = head->frch_root; - prev_frag = head->frch_last; - head = head->frch_next; - } - prev_frag->fr_next = 0; - } -} - -unsigned long machine; -int coff_flags; -extern void -write_object_file () -{ - int i; - const char *name; - struct frchain *frchain_ptr; - - object_headers headers; - unsigned long file_cursor; - bfd *abfd; - unsigned int addr; - abfd = bfd_openw (out_file_name, TARGET_FORMAT); - - - if (abfd == 0) - { - as_perror (_("FATAL: Can't create %s"), out_file_name); - exit (EXIT_FAILURE); - } - bfd_set_format (abfd, bfd_object); - bfd_set_arch_mach (abfd, BFD_ARCH, machine); - - string_byte_count = 4; - - for (frchain_ptr = frchain_root; - frchain_ptr != (struct frchain *) NULL; - frchain_ptr = frchain_ptr->frch_next) - { - /* Run through all the sub-segments and align them up. Also - close any open frags. We tack a .fill onto the end of the - frag chain so that any .align's size can be worked by looking - at the next frag. */ - - subseg_set (frchain_ptr->frch_seg, frchain_ptr->frch_subseg); - -#ifndef SUB_SEGMENT_ALIGN -#define SUB_SEGMENT_ALIGN(SEG) 1 -#endif -#ifdef md_do_align - md_do_align (SUB_SEGMENT_ALIGN (now_seg), (char *) NULL, 0, 0, - alignment_done); -#endif - frag_align (SUB_SEGMENT_ALIGN (now_seg), - subseg_text_p (now_seg) ? NOP_OPCODE : 0, - 0); -#ifdef md_do_align - alignment_done: -#endif - frag_wane (frag_now); - frag_now->fr_fix = 0; - know (frag_now->fr_next == NULL); - } - - - remove_subsegs (); - - - for (i = SEG_E0; i < SEG_UNKNOWN; i++) - { - relax_segment (segment_info[i].frchainP->frch_root, i); - } - - H_SET_NUMBER_OF_SECTIONS (&headers, 0); - - /* Find out how big the sections are, and set the addresses. */ - addr = 0; - for (i = SEG_E0; i < SEG_UNKNOWN; i++) - { - long size; - - segment_info[i].scnhdr.s_paddr = addr; - segment_info[i].scnhdr.s_vaddr = addr; - - if (segment_info[i].scnhdr.s_name[0]) - { - H_SET_NUMBER_OF_SECTIONS (&headers, - H_GET_NUMBER_OF_SECTIONS (&headers) + 1); - -#ifdef COFF_LONG_SECTION_NAMES - /* Support long section names as found in PE. This code - must coordinate with that in coff_header_append and - w_strings. */ - { - unsigned int len; - - len = strlen (segment_info[i].name); - if (len > SCNNMLEN) - string_byte_count += len + 1; - } -#endif /* COFF_LONG_SECTION_NAMES */ - } - - size = size_section (abfd, (unsigned int) i); - addr += size; - - /* I think the section alignment is only used on the i960; the - i960 needs it, and it should do no harm on other targets. */ -#ifdef ALIGNMENT_IN_S_FLAGS - segment_info[i].scnhdr.s_flags |= (section_alignment[i] & 0xF) << 8; -#else - segment_info[i].scnhdr.s_align = 1 << section_alignment[i]; -#endif - - if (i == SEG_E0) - H_SET_TEXT_SIZE (&headers, size); - else if (i == SEG_E1) - H_SET_DATA_SIZE (&headers, size); - else if (i == SEG_E2) - H_SET_BSS_SIZE (&headers, size); - } - - /* Turn the gas native symbol table shape into a coff symbol table */ - crawl_symbols (&headers, abfd); - - if (string_byte_count == 4) - string_byte_count = 0; - - H_SET_STRING_SIZE (&headers, string_byte_count); - -#ifdef tc_frob_file - tc_frob_file (); -#endif - - for (i = SEG_E0; i < SEG_UNKNOWN; i++) - { - fixup_mdeps (segment_info[i].frchainP->frch_root, &headers, i); - fixup_segment (&segment_info[i], i); - } - - /* Look for ".stab" segments and fill in their initial symbols - correctly. */ - for (i = SEG_E0; i < SEG_UNKNOWN; i++) - { - name = segment_info[i].name; - - if (name != NULL - && strncmp (".stab", name, 5) == 0 - && strncmp (".stabstr", name, 8) != 0) - adjust_stab_section (abfd, i); - } - - file_cursor = H_GET_TEXT_FILE_OFFSET (&headers); - - bfd_seek (abfd, (file_ptr) file_cursor, 0); - - /* Plant the data */ - - fill_section (abfd, &headers, &file_cursor); - - do_relocs_for (abfd, &headers, &file_cursor); - - do_linenos_for (abfd, &headers, &file_cursor); - - H_SET_FILE_MAGIC_NUMBER (&headers, COFF_MAGIC); -#ifndef OBJ_COFF_OMIT_TIMESTAMP - H_SET_TIME_STAMP (&headers, (long)time((time_t *)0)); -#else - H_SET_TIME_STAMP (&headers, 0); -#endif -#ifdef TC_COFF_SET_MACHINE - TC_COFF_SET_MACHINE (&headers); -#endif - -#ifndef COFF_FLAGS -#define COFF_FLAGS 0 -#endif - -#ifdef KEEP_RELOC_INFO - H_SET_FLAGS (&headers, ((H_GET_LINENO_SIZE(&headers) ? 0 : F_LNNO) | - COFF_FLAGS | coff_flags)); -#else - H_SET_FLAGS (&headers, ((H_GET_LINENO_SIZE(&headers) ? 0 : F_LNNO) | - (H_GET_RELOCATION_SIZE(&headers) ? 0 : F_RELFLG) | - COFF_FLAGS | coff_flags)); -#endif - - { - unsigned int symtable_size = H_GET_SYMBOL_TABLE_SIZE (&headers); - char *buffer1 = xmalloc (symtable_size + string_byte_count + 1); - - H_SET_SYMBOL_TABLE_POINTER (&headers, bfd_tell (abfd)); - w_symbols (abfd, buffer1, symbol_rootP); - if (string_byte_count > 0) - w_strings (buffer1 + symtable_size); - bfd_write (buffer1, 1, symtable_size + string_byte_count, abfd); - free (buffer1); - } - - coff_header_append (abfd, &headers); -#if 0 - /* Recent changes to write need this, but where it should - go is up to Ken.. */ - if (bfd_close_all_done (abfd) == false) - as_fatal (_("Can't close %s: %s"), out_file_name, - bfd_errmsg (bfd_get_error ())); -#else - { - extern bfd *stdoutput; - stdoutput = abfd; - } -#endif - -} - -/* Add a new segment. This is called from subseg_new via the - obj_new_segment macro. */ - -segT -obj_coff_add_segment (name) - const char *name; -{ - unsigned int i; - -#ifndef COFF_LONG_SECTION_NAMES - char buf[SCNNMLEN + 1]; - - strncpy (buf, name, SCNNMLEN); - buf[SCNNMLEN] = '\0'; - name = buf; -#endif - - for (i = SEG_E0; i < SEG_LAST && segment_info[i].scnhdr.s_name[0]; i++) - if (strcmp (name, segment_info[i].name) == 0) - return (segT) i; - - if (i == SEG_LAST) - { - as_bad (_("Too many new sections; can't add \"%s\""), name); - return now_seg; - } - - /* Add a new section. */ - strncpy (segment_info[i].scnhdr.s_name, name, - sizeof (segment_info[i].scnhdr.s_name)); - segment_info[i].scnhdr.s_flags = STYP_REG; - segment_info[i].name = xstrdup (name); - - return (segT) i; -} - -/* - * implement the .section pseudo op: - * .section name {, "flags"} - * ^ ^ - * | +--- optional flags: 'b' for bss - * | 'i' for info - * +-- section name 'l' for lib - * 'n' for noload - * 'o' for over - * 'w' for data - * 'd' (apparently m88k for data) - * 'x' for text - * 'r' for read-only data - * But if the argument is not a quoted string, treat it as a - * subsegment number. - */ - -void -obj_coff_section (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - /* Strip out the section name */ - char *section_name, *name; - char c; - unsigned int exp; - long flags; - - if (flag_mri) - { - char type; - - s_mri_sect (&type); - flags = 0; - if (type == 'C') - flags = STYP_TEXT; - else if (type == 'D') - flags = STYP_DATA; - segment_info[now_seg].scnhdr.s_flags |= flags; - - return; - } - - section_name = input_line_pointer; - c = get_symbol_end (); - - name = xmalloc (input_line_pointer - section_name + 1); - strcpy (name, section_name); - - *input_line_pointer = c; - - exp = 0; - flags = 0; - - SKIP_WHITESPACE (); - if (*input_line_pointer == ',') - { - ++input_line_pointer; - SKIP_WHITESPACE (); - - if (*input_line_pointer != '"') - exp = get_absolute_expression (); - else - { - ++input_line_pointer; - while (*input_line_pointer != '"' - && ! is_end_of_line[(unsigned char) *input_line_pointer]) - { - switch (*input_line_pointer) - { - case 'b': flags |= STYP_BSS; break; - case 'i': flags |= STYP_INFO; break; - case 'l': flags |= STYP_LIB; break; - case 'n': flags |= STYP_NOLOAD; break; - case 'o': flags |= STYP_OVER; break; - case 'd': - case 'w': flags |= STYP_DATA; break; - case 'x': flags |= STYP_TEXT; break; - case 'r': flags |= STYP_LIT; break; - default: - as_warn(_("unknown section attribute '%c'"), - *input_line_pointer); - break; - } - ++input_line_pointer; - } - if (*input_line_pointer == '"') - ++input_line_pointer; - } - } - - subseg_new (name, (subsegT) exp); - - segment_info[now_seg].scnhdr.s_flags |= flags; - - demand_empty_rest_of_line (); -} - - -static void -obj_coff_text (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - subseg_new (".text", get_absolute_expression ()); -} - - -static void -obj_coff_data (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - if (flag_readonly_data_in_text) - subseg_new (".text", get_absolute_expression () + 1000); - else - subseg_new (".data", get_absolute_expression ()); -} - -static void -obj_coff_ident (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - segT current_seg = now_seg; /* save current seg */ - subsegT current_subseg = now_subseg; - subseg_new (".comment", 0); /* .comment seg */ - stringer (1); /* read string */ - subseg_set (current_seg, current_subseg); /* restore current seg */ -} - -void -c_symbol_merge (debug, normal) - symbolS *debug; - symbolS *normal; -{ - S_SET_DATA_TYPE (normal, S_GET_DATA_TYPE (debug)); - S_SET_STORAGE_CLASS (normal, S_GET_STORAGE_CLASS (debug)); - - if (S_GET_NUMBER_AUXILIARY (debug) > S_GET_NUMBER_AUXILIARY (normal)) - { - S_SET_NUMBER_AUXILIARY (normal, S_GET_NUMBER_AUXILIARY (debug)); - } /* take the most we have */ - - if (S_GET_NUMBER_AUXILIARY (debug) > 0) - { - memcpy ((char *) &normal->sy_symbol.ost_auxent[0], - (char *) &debug->sy_symbol.ost_auxent[0], - (unsigned int) (S_GET_NUMBER_AUXILIARY (debug) * AUXESZ)); - } /* Move all the auxiliary information */ - - /* Move the debug flags. */ - SF_SET_DEBUG_FIELD (normal, SF_GET_DEBUG_FIELD (debug)); -} /* c_symbol_merge() */ - -static int -c_line_new (symbol, paddr, line_number, frag) - symbolS * symbol; - long paddr; - int line_number; - fragS * frag; -{ - struct lineno_list *new_line = - (struct lineno_list *) xmalloc (sizeof (struct lineno_list)); - - segment_info_type *s = segment_info + now_seg; - new_line->line.l_lnno = line_number; - - if (line_number == 0) - { - last_line_symbol = symbol; - new_line->line.l_addr.l_symndx = (long) symbol; - } - else - { - new_line->line.l_addr.l_paddr = paddr; - } - - new_line->frag = (char *) frag; - new_line->next = (struct lineno_list *) NULL; - - - if (s->lineno_list_head == (struct lineno_list *) NULL) - { - s->lineno_list_head = new_line; - } - else - { - s->lineno_list_tail->next = new_line; - } - s->lineno_list_tail = new_line; - return LINESZ * s->scnhdr.s_nlnno++; -} - -void -c_dot_file_symbol (filename) - char *filename; -{ - symbolS *symbolP; - - symbolP = symbol_new (".file", - SEG_DEBUG, - 0, - &zero_address_frag); - - S_SET_STORAGE_CLASS (symbolP, C_FILE); - S_SET_NUMBER_AUXILIARY (symbolP, 1); - - if (strlen (filename) > FILNMLEN) - { - /* Filename is too long to fit into an auxent, - we stick it into the string table instead. We keep - a linked list of the filenames we find so we can emit - them later.*/ - struct filename_list *f = ((struct filename_list *) - xmalloc (sizeof (struct filename_list))); - - f->filename = filename; - f->next = 0; - - SA_SET_FILE_FNAME_ZEROS (symbolP, 0); - SA_SET_FILE_FNAME_OFFSET (symbolP, 1); - - if (filename_list_tail) - filename_list_tail->next = f; - else - filename_list_head = f; - filename_list_tail = f; - } - else - { - SA_SET_FILE_FNAME (symbolP, filename); - } -#ifndef NO_LISTING - { - extern int listing; - if (listing) - { - listing_source_file (filename); - } - - } - -#endif - SF_SET_DEBUG (symbolP); - S_SET_VALUE (symbolP, (valueT) previous_file_symbol); - - previous_file_symbol = symbolP; - - /* Make sure that the symbol is first on the symbol chain */ - if (symbol_rootP != symbolP) - { - symbol_remove (symbolP, &symbol_rootP, &symbol_lastP); - symbol_insert (symbolP, symbol_rootP, &symbol_rootP, &symbol_lastP); - } -} /* c_dot_file_symbol() */ - -/* - * Build a 'section static' symbol. - */ - -symbolS * -c_section_symbol (name, idx) - char *name; - int idx; -{ - symbolS *symbolP; - - symbolP = symbol_find_base (name, DO_NOT_STRIP); - if (symbolP == NULL) - symbolP = symbol_new (name, idx, 0, &zero_address_frag); - else - { - /* Mmmm. I just love violating interfaces. Makes me feel...dirty. */ - S_SET_SEGMENT (symbolP, idx); - symbolP->sy_frag = &zero_address_frag; - } - - S_SET_STORAGE_CLASS (symbolP, C_STAT); - S_SET_NUMBER_AUXILIARY (symbolP, 1); - - SF_SET_STATICS (symbolP); - -#ifdef TE_DELTA - /* manfred@s-direktnet.de: section symbols *must* have the LOCAL bit cleared, - which is set by the new definition of LOCAL_LABEL in tc-m68k.h. */ - SF_CLEAR_LOCAL (symbolP); -#endif -#ifdef TE_PE - /* If the .linkonce pseudo-op was used for this section, we must - store the information in the auxiliary entry for the section - symbol. */ - if (segment_info[idx].linkonce != LINKONCE_UNSET) - { - int type; - - switch (segment_info[idx].linkonce) - { - default: - abort (); - case LINKONCE_DISCARD: - type = IMAGE_COMDAT_SELECT_ANY; - break; - case LINKONCE_ONE_ONLY: - type = IMAGE_COMDAT_SELECT_NODUPLICATES; - break; - case LINKONCE_SAME_SIZE: - type = IMAGE_COMDAT_SELECT_SAME_SIZE; - break; - case LINKONCE_SAME_CONTENTS: - type = IMAGE_COMDAT_SELECT_EXACT_MATCH; - break; - } - - SYM_AUXENT (symbolP)->x_scn.x_comdat = type; - } -#endif /* TE_PE */ - - return symbolP; -} /* c_section_symbol() */ - -static void -w_symbols (abfd, where, symbol_rootP) - bfd * abfd; - char *where; - symbolS * symbol_rootP; -{ - symbolS *symbolP; - unsigned int i; - - /* First fill in those values we have only just worked out */ - for (i = SEG_E0; i < SEG_LAST; i++) - { - symbolP = segment_info[i].dot; - if (symbolP) - { - SA_SET_SCN_SCNLEN (symbolP, segment_info[i].scnhdr.s_size); - SA_SET_SCN_NRELOC (symbolP, segment_info[i].scnhdr.s_nreloc); - SA_SET_SCN_NLINNO (symbolP, segment_info[i].scnhdr.s_nlnno); - } - } - - /* - * Emit all symbols left in the symbol chain. - */ - for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP)) - { - /* Used to save the offset of the name. It is used to point - to the string in memory but must be a file offset. */ - register char *temp; - - /* We can't fix the lnnoptr field in yank_symbols with the other - adjustments, because we have to wait until we know where they - go in the file. */ - if (SF_GET_ADJ_LNNOPTR (symbolP)) - { - SA_GET_SYM_LNNOPTR (symbolP) += - segment_info[S_GET_SEGMENT (symbolP)].scnhdr.s_lnnoptr; - } - - tc_coff_symbol_emit_hook (symbolP); - - temp = S_GET_NAME (symbolP); - if (SF_GET_STRING (symbolP)) - { - S_SET_OFFSET (symbolP, symbolP->sy_name_offset); - S_SET_ZEROES (symbolP, 0); - } - else - { - memset (symbolP->sy_symbol.ost_entry.n_name, 0, SYMNMLEN); - strncpy (symbolP->sy_symbol.ost_entry.n_name, temp, SYMNMLEN); - } - where = symbol_to_chars (abfd, where, symbolP); - S_SET_NAME (symbolP, temp); - } - -} /* w_symbols() */ - -static void -obj_coff_lcomm (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - s_lcomm(0); - return; -#if 0 - char *name; - char c; - int temp; - char *p; - - symbolS *symbolP; - - name = input_line_pointer; - - c = get_symbol_end (); - p = input_line_pointer; - *p = c; - SKIP_WHITESPACE (); - if (*input_line_pointer != ',') - { - as_bad (_("Expected comma after name")); - ignore_rest_of_line (); - return; - } - if (*input_line_pointer == '\n') - { - as_bad (_("Missing size expression")); - return; - } - input_line_pointer++; - if ((temp = get_absolute_expression ()) < 0) - { - as_warn (_("lcomm length (%d.) <0! Ignored."), temp); - ignore_rest_of_line (); - return; - } - *p = 0; - - symbolP = symbol_find_or_make(name); - - if (S_GET_SEGMENT(symbolP) == SEG_UNKNOWN && - S_GET_VALUE(symbolP) == 0) - { - if (! need_pass_2) - { - char *p; - segT current_seg = now_seg; /* save current seg */ - subsegT current_subseg = now_subseg; - - subseg_set (SEG_E2, 1); - symbolP->sy_frag = frag_now; - p = frag_var(rs_org, 1, 1, (relax_substateT)0, symbolP, - (offsetT) temp, (char *) 0); - *p = 0; - subseg_set (current_seg, current_subseg); /* restore current seg */ - S_SET_SEGMENT(symbolP, SEG_E2); - S_SET_STORAGE_CLASS(symbolP, C_STAT); - } - } - else - as_bad(_("Symbol %s already defined"), name); - - demand_empty_rest_of_line(); -#endif -} - -static void -fixup_mdeps (frags, h, this_segment) - fragS * frags; - object_headers * h; - segT this_segment; -{ - subseg_change (this_segment, 0); - while (frags) - { - switch (frags->fr_type) - { - case rs_align: - case rs_align_code: - case rs_org: -#ifdef HANDLE_ALIGN - HANDLE_ALIGN (frags); -#endif - frags->fr_type = rs_fill; - frags->fr_offset = - ((frags->fr_next->fr_address - frags->fr_address - frags->fr_fix) - / frags->fr_var); - break; - case rs_machine_dependent: - md_convert_frag (h, this_segment, frags); - frag_wane (frags); - break; - default: - ; - } - frags = frags->fr_next; - } -} - -#if 1 - -#ifndef TC_FORCE_RELOCATION -#define TC_FORCE_RELOCATION(fix) 0 -#endif - -static void -fixup_segment (segP, this_segment_type) - segment_info_type * segP; - segT this_segment_type; -{ - register fixS * fixP; - register symbolS *add_symbolP; - register symbolS *sub_symbolP; - long add_number; - register int size; - register char *place; - register long where; - register char pcrel; - register fragS *fragP; - register segT add_symbol_segment = absolute_section; - - for (fixP = segP->fix_root; fixP; fixP = fixP->fx_next) - { - fragP = fixP->fx_frag; - know (fragP); - where = fixP->fx_where; - place = fragP->fr_literal + where; - size = fixP->fx_size; - add_symbolP = fixP->fx_addsy; - sub_symbolP = fixP->fx_subsy; - add_number = fixP->fx_offset; - pcrel = fixP->fx_pcrel; - - /* We want function-relative stabs to work on systems which - may use a relaxing linker; thus we must handle the sym1-sym2 - fixups function-relative stabs generates. - - Of course, if you actually enable relaxing in the linker, the - line and block scoping information is going to be incorrect - in some cases. The only way to really fix this is to support - a reloc involving the difference of two symbols. */ - if (linkrelax - && (!sub_symbolP || pcrel)) - continue; - -#ifdef TC_I960 - if (fixP->fx_tcbit && SF_GET_CALLNAME (add_symbolP)) - { - /* Relocation should be done via the associated 'bal' entry - point symbol. */ - - if (!SF_GET_BALNAME (tc_get_bal_of_call (add_symbolP))) - { - as_bad_where (fixP->fx_file, fixP->fx_line, - _("No 'bal' entry point for leafproc %s"), - S_GET_NAME (add_symbolP)); - continue; - } - fixP->fx_addsy = add_symbolP = tc_get_bal_of_call (add_symbolP); - } -#endif - - /* Make sure the symbols have been resolved; this may not have - happened if these are expression symbols. */ - if (add_symbolP != NULL && ! add_symbolP->sy_resolved) - resolve_symbol_value (add_symbolP, 1); - - if (add_symbolP != NULL) - { - /* If this fixup is against a symbol which has been equated - to another symbol, convert it to the other symbol. */ - if (add_symbolP->sy_value.X_op == O_symbol - && (! S_IS_DEFINED (add_symbolP) - || S_IS_COMMON (add_symbolP))) - { - while (add_symbolP->sy_value.X_op == O_symbol - && (! S_IS_DEFINED (add_symbolP) - || S_IS_COMMON (add_symbolP))) - { - symbolS *n; - - /* We must avoid looping, as that can occur with a - badly written program. */ - n = add_symbolP->sy_value.X_add_symbol; - if (n == add_symbolP) - break; - add_number += add_symbolP->sy_value.X_add_number; - add_symbolP = n; - } - fixP->fx_addsy = add_symbolP; - fixP->fx_offset = add_number; - } - } - - if (sub_symbolP != NULL && ! sub_symbolP->sy_resolved) - resolve_symbol_value (sub_symbolP, 1); - - if (add_symbolP != NULL - && add_symbolP->sy_mri_common) - { - know (add_symbolP->sy_value.X_op == O_symbol); - add_number += S_GET_VALUE (add_symbolP); - fixP->fx_offset = add_number; - add_symbolP = fixP->fx_addsy = add_symbolP->sy_value.X_add_symbol; - } - - if (add_symbolP) - { - add_symbol_segment = S_GET_SEGMENT (add_symbolP); - } /* if there is an addend */ - - if (sub_symbolP) - { - if (add_symbolP == NULL || add_symbol_segment == absolute_section) - { - if (add_symbolP != NULL) - { - add_number += S_GET_VALUE (add_symbolP); - add_symbolP = NULL; - fixP->fx_addsy = NULL; - } - - /* It's just -sym. */ - if (S_GET_SEGMENT (sub_symbolP) == absolute_section) - { - add_number -= S_GET_VALUE (sub_symbolP); - fixP->fx_subsy = 0; - fixP->fx_done = 1; - } - else - { -#ifndef TC_M68K - as_bad_where (fixP->fx_file, fixP->fx_line, - _("Negative of non-absolute symbol %s"), - S_GET_NAME (sub_symbolP)); -#endif - add_number -= S_GET_VALUE (sub_symbolP); - } /* not absolute */ - - /* if sub_symbol is in the same segment that add_symbol - and add_symbol is either in DATA, TEXT, BSS or ABSOLUTE */ - } - else if (S_GET_SEGMENT (sub_symbolP) == add_symbol_segment - && SEG_NORMAL (add_symbol_segment)) - { - /* Difference of 2 symbols from same segment. Can't - make difference of 2 undefineds: 'value' means - something different for N_UNDF. */ -#ifdef TC_I960 - /* Makes no sense to use the difference of 2 arbitrary symbols - as the target of a call instruction. */ - if (fixP->fx_tcbit) - { - as_bad_where (fixP->fx_file, fixP->fx_line, - _("callj to difference of 2 symbols")); - } -#endif /* TC_I960 */ - add_number += S_GET_VALUE (add_symbolP) - - S_GET_VALUE (sub_symbolP); - add_symbolP = NULL; - - if (!TC_FORCE_RELOCATION (fixP)) - { - fixP->fx_addsy = NULL; - fixP->fx_subsy = NULL; - fixP->fx_done = 1; -#ifdef TC_M68K /* is this right? */ - pcrel = 0; - fixP->fx_pcrel = 0; -#endif - } - } - else - { - /* Different segments in subtraction. */ - know (!(S_IS_EXTERNAL (sub_symbolP) && (S_GET_SEGMENT (sub_symbolP) == absolute_section))); - - if ((S_GET_SEGMENT (sub_symbolP) == absolute_section)) - { - add_number -= S_GET_VALUE (sub_symbolP); - } -#ifdef DIFF_EXPR_OK - else if (S_GET_SEGMENT (sub_symbolP) == this_segment_type -#if 0 /* Okay for 68k, at least... */ - && !pcrel -#endif - ) - { - /* Make it pc-relative. */ - add_number += (md_pcrel_from (fixP) - - S_GET_VALUE (sub_symbolP)); - pcrel = 1; - fixP->fx_pcrel = 1; - sub_symbolP = 0; - fixP->fx_subsy = 0; - } -#endif - else - { - as_bad_where (fixP->fx_file, fixP->fx_line, - _("Can't emit reloc {- %s-seg symbol \"%s\"} @ file address %ld."), - segment_name (S_GET_SEGMENT (sub_symbolP)), - S_GET_NAME (sub_symbolP), - (long) (fragP->fr_address + where)); - } /* if absolute */ - } - } /* if sub_symbolP */ - - if (add_symbolP) - { - if (add_symbol_segment == this_segment_type && pcrel) - { - /* - * This fixup was made when the symbol's segment was - * SEG_UNKNOWN, but it is now in the local segment. - * So we know how to do the address without relocation. - */ -#ifdef TC_I960 - /* reloc_callj() may replace a 'call' with a 'calls' or a 'bal', - * in which cases it modifies *fixP as appropriate. In the case - * of a 'calls', no further work is required, and *fixP has been - * set up to make the rest of the code below a no-op. - */ - reloc_callj (fixP); -#endif /* TC_I960 */ - - add_number += S_GET_VALUE (add_symbolP); - add_number -= md_pcrel_from (fixP); - - /* We used to do - add_number -= segP->scnhdr.s_vaddr; - if defined (TC_I386) || defined (TE_LYNX). I now - think that was an error propagated from the case when - we are going to emit the relocation. If we are not - going to emit the relocation, then we just want to - set add_number to the difference between the symbols. - This is a case that would only arise when there is a - PC relative reference from a section other than .text - to a symbol defined in the same section, and the - reference is not relaxed. Since jump instructions on - the i386 are relaxed, this could only arise with a - call instruction. */ - - pcrel = 0; /* Lie. Don't want further pcrel processing. */ - if (!TC_FORCE_RELOCATION (fixP)) - { - fixP->fx_addsy = NULL; - fixP->fx_done = 1; - } - } - else - { - switch (add_symbol_segment) - { - case absolute_section: -#ifdef TC_I960 - reloc_callj (fixP); /* See comment about reloc_callj() above*/ -#endif /* TC_I960 */ - add_number += S_GET_VALUE (add_symbolP); - add_symbolP = NULL; - - if (!TC_FORCE_RELOCATION (fixP)) - { - fixP->fx_addsy = NULL; - fixP->fx_done = 1; - } - break; - default: - - -#if defined(TC_A29K) || (defined(TE_PE) && defined(TC_I386)) || defined(TC_M88K) - /* This really should be handled in the linker, but - backward compatibility forbids. */ - add_number += S_GET_VALUE (add_symbolP); -#else - add_number += S_GET_VALUE (add_symbolP) + - segment_info[S_GET_SEGMENT (add_symbolP)].scnhdr.s_paddr; -#endif - break; - - case SEG_UNKNOWN: -#ifdef TC_I960 - if ((int) fixP->fx_bit_fixP == 13) - { - /* This is a COBR instruction. They have only a - * 13-bit displacement and are only to be used - * for local branches: flag as error, don't generate - * relocation. - */ - as_bad_where (fixP->fx_file, fixP->fx_line, - _("can't use COBR format with external label")); - fixP->fx_addsy = NULL; - fixP->fx_done = 1; - continue; - } /* COBR */ -#endif /* TC_I960 */ -#if ((defined (TC_I386) || defined (TE_LYNX) || defined (TE_AUX)) && !defined(TE_PE)) || defined (COFF_COMMON_ADDEND) - /* 386 COFF uses a peculiar format in which the - value of a common symbol is stored in the .text - segment (I've checked this on SVR3.2 and SCO - 3.2.2) Ian Taylor <ian@cygnus.com>. */ - /* This is also true for 68k COFF on sysv machines - (Checked on Motorola sysv68 R3V6 and R3V7.1, and also on - UNIX System V/M68000, Release 1.0 from ATT/Bell Labs) - Philippe De Muyter <phdm@info.ucl.ac.be>. */ - if (S_IS_COMMON (add_symbolP)) - add_number += S_GET_VALUE (add_symbolP); -#endif - break; - - - } /* switch on symbol seg */ - } /* if not in local seg */ - } /* if there was a + symbol */ - - if (pcrel) - { -#if !defined(TC_M88K) && !(defined(TE_PE) && defined(TC_I386)) && !defined(TC_A29K) - /* This adjustment is not correct on the m88k, for which the - linker does all the computation. */ - add_number -= md_pcrel_from (fixP); -#endif - if (add_symbolP == 0) - { - fixP->fx_addsy = &abs_symbol; - } /* if there's an add_symbol */ -#if defined (TC_I386) || defined (TE_LYNX) || defined (TC_I960) || defined (TC_M68K) - /* On the 386 we must adjust by the segment vaddr as well. - Ian Taylor. - - I changed the i960 to work this way as well. This is - compatible with the current GNU linker behaviour. I do - not know what other i960 COFF assemblers do. This is not - a common case: normally, only assembler code will contain - a PC relative reloc, and only branches which do not - originate in the .text section will have a non-zero - address. - - I changed the m68k to work this way as well. This will - break existing PC relative relocs from sections which do - not start at address 0, but it will make ld -r work. - Ian Taylor, 4 Oct 96. */ - - add_number -= segP->scnhdr.s_vaddr; -#endif - } /* if pcrel */ - -#ifdef MD_APPLY_FIX3 - md_apply_fix3 (fixP, (valueT *) &add_number, this_segment_type); -#else - md_apply_fix (fixP, add_number); -#endif - - if (!fixP->fx_bit_fixP && ! fixP->fx_no_overflow) - { -#ifndef TC_M88K - /* The m88k uses the offset field of the reloc to get around - this problem. */ - if ((size == 1 - && ((add_number & ~0xFF) - || (fixP->fx_signed && (add_number & 0x80))) - && ((add_number & ~0xFF) != (-1 & ~0xFF) - || (add_number & 0x80) == 0)) - || (size == 2 - && ((add_number & ~0xFFFF) - || (fixP->fx_signed && (add_number & 0x8000))) - && ((add_number & ~0xFFFF) != (-1 & ~0xFFFF) - || (add_number & 0x8000) == 0))) - { - as_bad_where (fixP->fx_file, fixP->fx_line, - _("Value of %ld too large for field of %d bytes at 0x%lx"), - (long) add_number, size, - (unsigned long) (fragP->fr_address + where)); - } -#endif -#ifdef WARN_SIGNED_OVERFLOW_WORD - /* Warn if a .word value is too large when treated as a - signed number. We already know it is not too negative. - This is to catch over-large switches generated by gcc on - the 68k. */ - if (!flag_signed_overflow_ok - && size == 2 - && add_number > 0x7fff) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("Signed .word overflow; switch may be too large; %ld at 0x%lx"), - (long) add_number, - (unsigned long) (fragP->fr_address + where)); -#endif - } /* not a bit fix */ - } /* For each fixS in this segment. */ -} /* fixup_segment() */ - -#endif - -/* The first entry in a .stab section is special. */ - -void -obj_coff_init_stab_section (seg) - segT seg; -{ - char *file; - char *p; - char *stabstr_name; - unsigned int stroff; - - /* Make space for this first symbol. */ - p = frag_more (12); - /* Zero it out. */ - memset (p, 0, 12); - as_where (&file, (unsigned int *) NULL); - stabstr_name = (char *) alloca (strlen (segment_info[seg].name) + 4); - strcpy (stabstr_name, segment_info[seg].name); - strcat (stabstr_name, "str"); - stroff = get_stab_string_offset (file, stabstr_name); - know (stroff == 1); - md_number_to_chars (p, stroff, 4); -} - -/* Fill in the counts in the first entry in a .stab section. */ - -static void -adjust_stab_section(abfd, seg) - bfd *abfd; - segT seg; -{ - segT stabstrseg = SEG_UNKNOWN; - const char *secname, *name2; - char *name; - char *p = NULL; - int i, strsz = 0, nsyms; - fragS *frag = segment_info[seg].frchainP->frch_root; - - /* Look for the associated string table section. */ - - secname = segment_info[seg].name; - name = (char *) alloca (strlen (secname) + 4); - strcpy (name, secname); - strcat (name, "str"); - - for (i = SEG_E0; i < SEG_UNKNOWN; i++) - { - name2 = segment_info[i].name; - if (name2 != NULL && strncmp(name2, name, 8) == 0) - { - stabstrseg = i; - break; - } - } - - /* If we found the section, get its size. */ - if (stabstrseg != SEG_UNKNOWN) - strsz = size_section (abfd, stabstrseg); - - nsyms = size_section (abfd, seg) / 12 - 1; - - /* Look for the first frag of sufficient size for the initial stab - symbol, and collect a pointer to it. */ - while (frag && frag->fr_fix < 12) - frag = frag->fr_next; - assert (frag != 0); - p = frag->fr_literal; - assert (p != 0); - - /* Write in the number of stab symbols and the size of the string - table. */ - bfd_h_put_16 (abfd, (bfd_vma) nsyms, (bfd_byte *) p + 6); - bfd_h_put_32 (abfd, (bfd_vma) strsz, (bfd_byte *) p + 8); -} - -#endif /* not BFD_ASSEMBLER */ - -const pseudo_typeS coff_pseudo_table[] = -{ - {"def", obj_coff_def, 0}, - {"dim", obj_coff_dim, 0}, - {"endef", obj_coff_endef, 0}, - {"line", obj_coff_line, 0}, - {"ln", obj_coff_ln, 0}, -#ifdef BFD_ASSEMBLER - {"loc", obj_coff_loc, 0}, -#endif - {"appline", obj_coff_ln, 1}, - {"scl", obj_coff_scl, 0}, - {"size", obj_coff_size, 0}, - {"tag", obj_coff_tag, 0}, - {"type", obj_coff_type, 0}, - {"val", obj_coff_val, 0}, - {"section", obj_coff_section, 0}, - {"sect", obj_coff_section, 0}, - /* FIXME: We ignore the MRI short attribute. */ - {"section.s", obj_coff_section, 0}, - {"sect.s", obj_coff_section, 0}, - /* We accept the .bss directive for backward compatibility with - earlier versions of gas. */ - {"bss", obj_coff_bss, 0}, - {"weak", obj_coff_weak, 0}, - {"ident", obj_coff_ident, 0}, -#ifndef BFD_ASSEMBLER - {"use", obj_coff_section, 0}, - {"text", obj_coff_text, 0}, - {"data", obj_coff_data, 0}, - {"lcomm", obj_coff_lcomm, 0}, -#else - {"optim", s_ignore, 0}, /* For sun386i cc (?) */ -#endif - {"version", s_ignore, 0}, - {"ABORT", s_abort, 0}, -#ifdef TC_M88K - /* The m88k uses sdef instead of def. */ - {"sdef", obj_coff_def, 0}, -#endif - {NULL, NULL, 0} /* end sentinel */ -}; /* coff_pseudo_table */ - -#ifdef BFD_ASSEMBLER - -/* Support for a COFF emulation. */ - -static void coff_pop_insert PARAMS ((void)); - -static void -coff_pop_insert () -{ - pop_insert (coff_pseudo_table); -} - -const struct format_ops coff_format_ops = -{ - bfd_target_coff_flavour, - 0, /* dfl_leading_underscore */ - 1, /* emit_section_symbols */ - coff_frob_symbol, - 0, /* frob_file */ - coff_frob_file_after_relocs, - 0, /* s_get_size */ - 0, /* s_set_size */ - 0, /* s_get_align */ - 0, /* s_set_align */ - 0, /* s_get_other */ - 0, /* s_get_desc */ - 0, /* copy_symbol_attributes */ - 0, /* generate_asm_lineno */ - 0, /* process_stab */ - 0, /* sec_sym_ok_for_reloc */ - coff_pop_insert, - 0, /* ecoff_set_ext */ - coff_obj_read_begin_hook, - coff_obj_symbol_new_hook -}; - -#endif diff --git a/contrib/binutils/gas/config/obj-coff.h b/contrib/binutils/gas/config/obj-coff.h deleted file mode 100644 index f60ae365fb919..0000000000000 --- a/contrib/binutils/gas/config/obj-coff.h +++ /dev/null @@ -1,873 +0,0 @@ -/* coff object file format - Copyright (C) 1989, 90, 91, 92, 94, 95, 96, 97, 98, 99, 2000 - Free Software Foundation, Inc. - - This file is part of GAS. - - 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 OBJ_FORMAT_H -#define OBJ_FORMAT_H - -#define OBJ_COFF 1 - -#ifndef BFD_ASSEMBLER - -#define WORKING_DOT_WORD -#define WARN_SIGNED_OVERFLOW_WORD -#define OBJ_COFF_OMIT_OPTIONAL_HEADER -#define BFD_HEADERS -#define BFD - -#endif - -#include "targ-cpu.h" - -#include "bfd.h" - -/* This internal_lineno crap is to stop namespace pollution from the - bfd internal coff headerfile. */ -#define internal_lineno bfd_internal_lineno -#include "coff/internal.h" -#undef internal_lineno - -/* CPU-specific setup: */ - -#ifdef TC_ARM -#include "coff/arm.h" -#ifndef TARGET_FORMAT -#define TARGET_FORMAT "coff-arm" -#endif -#endif - -#ifdef TC_PPC -#ifdef TE_PE -#include "coff/powerpc.h" -#else -#include "coff/rs6000.h" -#endif -#endif - -#ifdef TC_SPARC -#include "coff/sparc.h" -#endif - -#ifdef TC_I386 -#include "coff/i386.h" - -#ifdef TE_PE -#define TARGET_FORMAT "pe-i386" -#endif - -#ifndef TARGET_FORMAT -#define TARGET_FORMAT "coff-i386" -#endif -#endif - -#ifdef TC_M68K -#include "coff/m68k.h" -#ifndef TARGET_FORMAT -#define TARGET_FORMAT "coff-m68k" -#endif -#endif - -#ifdef TC_A29K -#include "coff/a29k.h" -#define TARGET_FORMAT "coff-a29k-big" -#endif - -#ifdef TC_I960 -#include "coff/i960.h" -#define TARGET_FORMAT "coff-Intel-little" -#endif - -#ifdef TC_Z8K -#include "coff/z8k.h" -#define TARGET_FORMAT "coff-z8k" -#endif - -#ifdef TC_H8300 -#include "coff/h8300.h" -#define TARGET_FORMAT "coff-h8300" -#endif - -#ifdef TC_H8500 -#include "coff/h8500.h" -#define TARGET_FORMAT "coff-h8500" -#endif - -#ifdef TC_SH - -#ifdef TE_PE -#define COFF_WITH_PE -#endif - -#include "coff/sh.h" - -#ifdef TE_PE -#define TARGET_FORMAT "pe-shl" -#else -#define TARGET_FORMAT \ - (shl \ - ? (sh_small ? "coff-shl-small" : "coff-shl") \ - : (sh_small ? "coff-sh-small" : "coff-sh")) -#endif -#endif - -#ifdef TC_MIPS -#define COFF_WITH_PE -#include "coff/mipspe.h" -#undef TARGET_FORMAT -#define TARGET_FORMAT "pe-mips" -#endif - -#ifdef TC_M88K -#include "coff/m88k.h" -#define TARGET_FORMAT "coff-m88kbcs" -#endif - -#ifdef TC_W65 -#include "coff/w65.h" -#define TARGET_FORMAT "coff-w65" -#endif - -#ifdef TC_TIC30 -#include "coff/tic30.h" -#define TARGET_FORMAT "coff-tic30" -#endif - -#ifdef TC_TIC80 -#include "coff/tic80.h" -#define TARGET_FORMAT "coff-tic80" -#define ALIGNMENT_IN_S_FLAGS 1 -#endif - -#ifdef TC_MCORE -#include "coff/mcore.h" -#ifndef TARGET_FORMAT -#define TARGET_FORMAT "pe-mcore" -#endif -#endif - -/* Targets may also set this. Also, if BFD_ASSEMBLER is defined, this - will already have been defined. */ -#undef SYMBOLS_NEED_BACKPOINTERS -#define SYMBOLS_NEED_BACKPOINTERS 1 - -#ifndef OBJ_COFF_MAX_AUXENTRIES -#define OBJ_COFF_MAX_AUXENTRIES 1 -#endif /* OBJ_COFF_MAX_AUXENTRIES */ - -extern void coff_obj_symbol_new_hook PARAMS ((symbolS *)); -#define obj_symbol_new_hook coff_obj_symbol_new_hook - -extern void coff_obj_read_begin_hook PARAMS ((void)); -#define obj_read_begin_hook coff_obj_read_begin_hook - -/* *********************************************************************** - - This file really contains two implementations of the COFF back end. - They are in the process of being merged, but this is only a - preliminary, mechanical merging. Many definitions that are - identical between the two are still found in both versions. - - The first version, with BFD_ASSEMBLER defined, uses high-level BFD - interfaces and data structures. The second version, with - BFD_ASSEMBLER not defined, also uses BFD, but mostly for swapping - data structures and for doing the actual I/O. The latter defines - the preprocessor symbols BFD and BFD_HEADERS. Try not to let this - confuse you. - - These two are in the process of being merged, and eventually the - BFD_ASSEMBLER version should take over completely. Release timing - issues and namespace problems convinced me to merge the two - together in this fashion, a little sooner than I would have liked. - The real merge should be much better done by the time the next - release comes out. - - For now, the structure of this file is: - <common> - #ifdef BFD_ASSEMBLER - <one version> - #else - <other version> - #endif - <common> - Unfortunately, the common portions are very small at the moment, - and many declarations or definitions are duplicated. The structure - of obj-coff.c is similar. - - See doc/internals.texi for a brief discussion of the history, if - you care. - - Ken Raeburn, 5 May 1994 - - *********************************************************************** */ - -#ifdef BFD_ASSEMBLER - -#include "bfd/libcoff.h" - -#define OUTPUT_FLAVOR bfd_target_coff_flavour - -/* SYMBOL TABLE */ - -/* Alter the field names, for now, until we've fixed up the other - references to use the new name. */ -#ifdef TC_I960 -#define TC_SYMFIELD_TYPE symbolS * -#define sy_tc bal -#endif - -#define OBJ_SYMFIELD_TYPE unsigned long -#define sy_obj sy_flags - -#define SYM_AUXENT(S) \ - (&coffsymbol (symbol_get_bfdsym (S))->native[1].u.auxent) -#define SYM_AUXINFO(S) \ - (&coffsymbol (symbol_get_bfdsym (S))->native[1]) - -#define DO_NOT_STRIP 0 - -extern void obj_coff_section PARAMS ((int)); - -/* The number of auxiliary entries */ -#define S_GET_NUMBER_AUXILIARY(s) \ - (coffsymbol (symbol_get_bfdsym (s))->native->u.syment.n_numaux) -/* The number of auxiliary entries */ -#define S_SET_NUMBER_AUXILIARY(s,v) (S_GET_NUMBER_AUXILIARY (s) = (v)) - -/* True if a symbol name is in the string table, i.e. its length is > 8. */ -#define S_IS_STRING(s) (strlen(S_GET_NAME(s)) > 8 ? 1 : 0) - -extern int S_SET_DATA_TYPE PARAMS ((symbolS *, int)); -extern int S_SET_STORAGE_CLASS PARAMS ((symbolS *, int)); -extern int S_GET_STORAGE_CLASS PARAMS ((symbolS *)); -extern void SA_SET_SYM_ENDNDX PARAMS ((symbolS *, symbolS *)); - -/* Auxiliary entry macros. SA_ stands for symbol auxiliary */ -/* Omit the tv related fields */ -/* Accessors */ - -#define SA_GET_SYM_TAGNDX(s) (SYM_AUXENT (s)->x_sym.x_tagndx.l) -#define SA_GET_SYM_LNNO(s) (SYM_AUXENT (s)->x_sym.x_misc.x_lnsz.x_lnno) -#define SA_GET_SYM_SIZE(s) (SYM_AUXENT (s)->x_sym.x_misc.x_lnsz.x_size) -#define SA_GET_SYM_FSIZE(s) (SYM_AUXENT (s)->x_sym.x_misc.x_fsize) -#define SA_GET_SYM_LNNOPTR(s) (SYM_AUXENT (s)->x_sym.x_fcnary.x_fcn.x_lnnoptr) -#define SA_GET_SYM_ENDNDX(s) (SYM_AUXENT (s)->x_sym.x_fcnary.x_fcn.x_endndx) -#define SA_GET_SYM_DIMEN(s,i) (SYM_AUXENT (s)->x_sym.x_fcnary.x_ary.x_dimen[(i)]) -#define SA_GET_FILE_FNAME(s) (SYM_AUXENT (s)->x_file.x_fname) -#define SA_GET_SCN_SCNLEN(s) (SYM_AUXENT (s)->x_scn.x_scnlen) -#define SA_GET_SCN_NRELOC(s) (SYM_AUXENT (s)->x_scn.x_nreloc) -#define SA_GET_SCN_NLINNO(s) (SYM_AUXENT (s)->x_scn.x_nlinno) - -#define SA_SET_SYM_LNNO(s,v) (SYM_AUXENT (s)->x_sym.x_misc.x_lnsz.x_lnno=(v)) -#define SA_SET_SYM_SIZE(s,v) (SYM_AUXENT (s)->x_sym.x_misc.x_lnsz.x_size=(v)) -#define SA_SET_SYM_FSIZE(s,v) (SYM_AUXENT (s)->x_sym.x_misc.x_fsize=(v)) -#define SA_SET_SYM_LNNOPTR(s,v) (SYM_AUXENT (s)->x_sym.x_fcnary.x_fcn.x_lnnoptr=(v)) -#define SA_SET_SYM_DIMEN(s,i,v) (SYM_AUXENT (s)->x_sym.x_fcnary.x_ary.x_dimen[(i)]=(v)) -#define SA_SET_FILE_FNAME(s,v) strncpy(SYM_AUXENT (s)->x_file.x_fname,(v),FILNMLEN) -#define SA_SET_SCN_SCNLEN(s,v) (SYM_AUXENT (s)->x_scn.x_scnlen=(v)) -#define SA_SET_SCN_NRELOC(s,v) (SYM_AUXENT (s)->x_scn.x_nreloc=(v)) -#define SA_SET_SCN_NLINNO(s,v) (SYM_AUXENT (s)->x_scn.x_nlinno=(v)) - -/* - * Internal use only definitions. SF_ stands for symbol flags. - * - * These values can be assigned to sy_symbol.ost_flags field of a symbolS. - * - * You'll break i960 if you shift the SYSPROC bits anywhere else. for - * more on the balname/callname hack, see tc-i960.h. b.out is done - * differently. - */ - -#define SF_I960_MASK (0x000001ff) /* Bits 0-8 are used by the i960 port. */ -#define SF_SYSPROC (0x0000003f) /* bits 0-5 are used to store the sysproc number */ -#define SF_IS_SYSPROC (0x00000040) /* bit 6 marks symbols that are sysprocs */ -#define SF_BALNAME (0x00000080) /* bit 7 marks BALNAME symbols */ -#define SF_CALLNAME (0x00000100) /* bit 8 marks CALLNAME symbols */ - -#define SF_NORMAL_MASK (0x0000ffff) /* bits 12-15 are general purpose. */ - -#define SF_STATICS (0x00001000) /* Mark the .text & all symbols */ -#define SF_DEFINED (0x00002000) /* Symbol is defined in this file */ -#define SF_STRING (0x00004000) /* Symbol name length > 8 */ -#define SF_LOCAL (0x00008000) /* Symbol must not be emitted */ - -#define SF_DEBUG_MASK (0xffff0000) /* bits 16-31 are debug info */ - -#define SF_FUNCTION (0x00010000) /* The symbol is a function */ -#define SF_PROCESS (0x00020000) /* Process symbol before write */ -#define SF_TAGGED (0x00040000) /* Is associated with a tag */ -#define SF_TAG (0x00080000) /* Is a tag */ -#define SF_DEBUG (0x00100000) /* Is in debug or abs section */ -#define SF_GET_SEGMENT (0x00200000) /* Get the section of the forward symbol. */ -/* All other bits are unused. */ - -/* Accessors */ -#define SF_GET(s) (*symbol_get_obj (s)) -#define SF_GET_DEBUG(s) (symbol_get_bfdsym (s)->flags & BSF_DEBUGGING) -#define SF_SET_DEBUG(s) (symbol_get_bfdsym (s)->flags |= BSF_DEBUGGING) -#define SF_GET_NORMAL_FIELD(s) (SF_GET (s) & SF_NORMAL_MASK) -#define SF_GET_DEBUG_FIELD(s) (SF_GET (s) & SF_DEBUG_MASK) -#define SF_GET_FILE(s) (SF_GET (s) & SF_FILE) -#define SF_GET_STATICS(s) (SF_GET (s) & SF_STATICS) -#define SF_GET_DEFINED(s) (SF_GET (s) & SF_DEFINED) -#define SF_GET_STRING(s) (SF_GET (s) & SF_STRING) -#define SF_GET_LOCAL(s) (SF_GET (s) & SF_LOCAL) -#define SF_GET_FUNCTION(s) (SF_GET (s) & SF_FUNCTION) -#define SF_GET_PROCESS(s) (SF_GET (s) & SF_PROCESS) -#define SF_GET_TAGGED(s) (SF_GET (s) & SF_TAGGED) -#define SF_GET_TAG(s) (SF_GET (s) & SF_TAG) -#define SF_GET_GET_SEGMENT(s) (SF_GET (s) & SF_GET_SEGMENT) -#define SF_GET_I960(s) (SF_GET (s) & SF_I960_MASK) /* used by i960 */ -#define SF_GET_BALNAME(s) (SF_GET (s) & SF_BALNAME) /* used by i960 */ -#define SF_GET_CALLNAME(s) (SF_GET (s) & SF_CALLNAME) /* used by i960 */ -#define SF_GET_IS_SYSPROC(s) (SF_GET (s) & SF_IS_SYSPROC) /* used by i960 */ -#define SF_GET_SYSPROC(s) (SF_GET (s) & SF_SYSPROC) /* used by i960 */ - -/* Modifiers */ -#define SF_SET(s,v) (SF_GET (s) = (v)) -#define SF_SET_NORMAL_FIELD(s,v)(SF_GET (s) |= ((v) & SF_NORMAL_MASK)) -#define SF_SET_DEBUG_FIELD(s,v) (SF_GET (s) |= ((v) & SF_DEBUG_MASK)) -#define SF_SET_FILE(s) (SF_GET (s) |= SF_FILE) -#define SF_SET_STATICS(s) (SF_GET (s) |= SF_STATICS) -#define SF_SET_DEFINED(s) (SF_GET (s) |= SF_DEFINED) -#define SF_SET_STRING(s) (SF_GET (s) |= SF_STRING) -#define SF_SET_LOCAL(s) (SF_GET (s) |= SF_LOCAL) -#define SF_CLEAR_LOCAL(s) (SF_GET (s) &= ~SF_LOCAL) -#define SF_SET_FUNCTION(s) (SF_GET (s) |= SF_FUNCTION) -#define SF_SET_PROCESS(s) (SF_GET (s) |= SF_PROCESS) -#define SF_SET_TAGGED(s) (SF_GET (s) |= SF_TAGGED) -#define SF_SET_TAG(s) (SF_GET (s) |= SF_TAG) -#define SF_SET_GET_SEGMENT(s) (SF_GET (s) |= SF_GET_SEGMENT) -#define SF_SET_I960(s,v) (SF_GET (s) |= ((v) & SF_I960_MASK)) /* used by i960 */ -#define SF_SET_BALNAME(s) (SF_GET (s) |= SF_BALNAME) /* used by i960 */ -#define SF_SET_CALLNAME(s) (SF_GET (s) |= SF_CALLNAME) /* used by i960 */ -#define SF_SET_IS_SYSPROC(s) (SF_GET (s) |= SF_IS_SYSPROC) /* used by i960 */ -#define SF_SET_SYSPROC(s,v) (SF_GET (s) |= ((v) & SF_SYSPROC)) /* used by i960 */ - -/* -------------- Line number handling ------- */ -extern int text_lineno_number; -extern int coff_line_base; -extern int coff_n_line_nos; - -#define obj_emit_lineno(WHERE,LINE,FILE_START) abort () -extern void coff_add_linesym PARAMS ((symbolS *)); - - -void c_dot_file_symbol PARAMS ((char *filename)); -#define obj_app_file c_dot_file_symbol - -extern void coff_frob_symbol PARAMS ((symbolS *, int *)); -extern void coff_adjust_symtab PARAMS ((void)); -extern void coff_frob_section PARAMS ((segT)); -extern void coff_adjust_section_syms PARAMS ((bfd *, asection *, PTR)); -extern void coff_frob_file_after_relocs PARAMS ((void)); -#define obj_frob_symbol(S,P) coff_frob_symbol(S,&P) -#ifndef obj_adjust_symtab -#define obj_adjust_symtab() coff_adjust_symtab() -#endif -#define obj_frob_section(S) coff_frob_section (S) -#define obj_frob_file_after_relocs() coff_frob_file_after_relocs () - -extern symbolS *coff_last_function; - -/* Forward the segment of a forwarded symbol, handle assignments that - just copy symbol values, etc. */ -#ifndef OBJ_COPY_SYMBOL_ATTRIBUTES -#ifndef TE_I386AIX -#define OBJ_COPY_SYMBOL_ATTRIBUTES(dest,src) \ - (SF_GET_GET_SEGMENT (dest) \ - ? (S_SET_SEGMENT (dest, S_GET_SEGMENT (src)), 0) \ - : 0) -#else -#define OBJ_COPY_SYMBOL_ATTRIBUTES(dest,src) \ - (SF_GET_GET_SEGMENT (dest) && S_GET_SEGMENT (dest) == SEG_UNKNOWN \ - ? (S_SET_SEGMENT (dest, S_GET_SEGMENT (src)), 0) \ - : 0) -#endif -#endif - -/* sanity check */ - -#ifdef TC_I960 -#ifndef C_LEAFSTAT -hey ! Where is the C_LEAFSTAT definition ? i960 - coff support is depending on it. -#endif /* no C_LEAFSTAT */ -#endif /* TC_I960 */ - -#else /* not BFD_ASSEMBLER */ - -#ifdef TC_A29K -/* Allow translate from aout relocs to coff relocs */ -#define NO_RELOC 20 -#define RELOC_32 1 -#define RELOC_8 2 -#define RELOC_CONST 3 -#define RELOC_CONSTH 4 -#define RELOC_JUMPTARG 5 -#define RELOC_BASE22 6 -#define RELOC_HI22 7 -#define RELOC_LO10 8 -#define RELOC_BASE13 9 -#define RELOC_WDISP22 10 -#define RELOC_WDISP30 11 -#endif - -extern const segT N_TYPE_seg[]; - -/* Magic number of paged executable. */ -#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE 0x8300 - - -/* SYMBOL TABLE */ - -/* Symbol table entry data type */ - -typedef struct -{ - /* Basic symbol */ - struct internal_syment ost_entry; - /* Auxiliary entry. */ - union internal_auxent ost_auxent[OBJ_COFF_MAX_AUXENTRIES]; - /* obj_coff internal use only flags */ - unsigned int ost_flags; -} obj_symbol_type; - -#ifndef DO_NOT_STRIP -#define DO_NOT_STRIP 0 -#endif -/* Symbol table macros and constants */ - -/* Possible and usefull section number in symbol table - * The values of TEXT, DATA and BSS may not be portable. - */ - -#define C_ABS_SECTION N_ABS -#define C_UNDEF_SECTION N_UNDEF -#define C_DEBUG_SECTION N_DEBUG -#define C_NTV_SECTION N_TV -#define C_PTV_SECTION P_TV -#define C_REGISTER_SECTION 50 - -/* - * Macros to extract information from a symbol table entry. - * This syntaxic indirection allows independence regarding a.out or coff. - * The argument (s) of all these macros is a pointer to a symbol table entry. - */ - -/* Predicates */ -/* True if the symbol is external */ -#define S_IS_EXTERNAL(s) ((s)->sy_symbol.ost_entry.n_scnum == C_UNDEF_SECTION) -/* True if symbol has been defined, ie : - section > 0 (DATA, TEXT or BSS) - section == 0 and value > 0 (external bss symbol) */ -#define S_IS_DEFINED(s) \ - ((s)->sy_symbol.ost_entry.n_scnum > C_UNDEF_SECTION \ - || ((s)->sy_symbol.ost_entry.n_scnum == C_UNDEF_SECTION \ - && S_GET_VALUE (s) > 0) \ - || ((s)->sy_symbol.ost_entry.n_scnum == C_ABS_SECTION)) -/* True if a debug special symbol entry */ -#define S_IS_DEBUG(s) ((s)->sy_symbol.ost_entry.n_scnum == C_DEBUG_SECTION) -/* True if a symbol is local symbol name */ -/* A symbol name whose name includes ^A is a gas internal pseudo symbol */ -#define S_IS_LOCAL(s) \ - ((s)->sy_symbol.ost_entry.n_scnum == C_REGISTER_SECTION \ - || (S_LOCAL_NAME(s) && ! flag_keep_locals && ! S_IS_DEBUG (s)) \ - || strchr (S_GET_NAME (s), '\001') != NULL \ - || strchr (S_GET_NAME (s), '\002') != NULL \ - || (flag_strip_local_absolute \ - && !S_IS_EXTERNAL(s) \ - && (s)->sy_symbol.ost_entry.n_scnum == C_ABS_SECTION)) -/* True if a symbol is not defined in this file */ -#define S_IS_EXTERN(s) ((s)->sy_symbol.ost_entry.n_scnum == 0 \ - && S_GET_VALUE (s) == 0) -/* - * True if a symbol can be multiply defined (bss symbols have this def - * though it is bad practice) - */ -#define S_IS_COMMON(s) ((s)->sy_symbol.ost_entry.n_scnum == 0 \ - && S_GET_VALUE (s) != 0) -/* True if a symbol name is in the string table, i.e. its length is > 8. */ -#define S_IS_STRING(s) (strlen(S_GET_NAME(s)) > 8 ? 1 : 0) - -/* True if a symbol is defined as weak. */ -#ifdef TE_PE -#define S_IS_WEAK(s) \ - ((s)->sy_symbol.ost_entry.n_sclass == C_NT_WEAK \ - || (s)->sy_symbol.ost_entry.n_sclass == C_WEAKEXT) -#else -#define S_IS_WEAK(s) \ - ((s)->sy_symbol.ost_entry.n_sclass == C_WEAKEXT) -#endif - -/* Accessors */ -/* The name of the symbol */ -#define S_GET_NAME(s) ((char*)(s)->sy_symbol.ost_entry.n_offset) -/* The pointer to the string table */ -#define S_GET_OFFSET(s) ((s)->sy_symbol.ost_entry.n_offset) -/* The numeric value of the segment */ -#define S_GET_SEGMENT(s) s_get_segment(s) -/* The data type */ -#define S_GET_DATA_TYPE(s) ((s)->sy_symbol.ost_entry.n_type) -/* The storage class */ -#define S_GET_STORAGE_CLASS(s) ((s)->sy_symbol.ost_entry.n_sclass) -/* The number of auxiliary entries */ -#define S_GET_NUMBER_AUXILIARY(s) ((s)->sy_symbol.ost_entry.n_numaux) - -/* Modifiers */ -/* Set the name of the symbol */ -#define S_SET_NAME(s,v) ((s)->sy_symbol.ost_entry.n_offset = (unsigned long)(v)) -/* Set the offset of the symbol */ -#define S_SET_OFFSET(s,v) ((s)->sy_symbol.ost_entry.n_offset = (v)) -/* The numeric value of the segment */ -#define S_SET_SEGMENT(s,v) ((s)->sy_symbol.ost_entry.n_scnum = SEGMENT_TO_SYMBOL_TYPE(v)) -/* The data type */ -#define S_SET_DATA_TYPE(s,v) ((s)->sy_symbol.ost_entry.n_type = (v)) -/* The storage class */ -#define S_SET_STORAGE_CLASS(s,v) ((s)->sy_symbol.ost_entry.n_sclass = (v)) -/* The number of auxiliary entries */ -#define S_SET_NUMBER_AUXILIARY(s,v) ((s)->sy_symbol.ost_entry.n_numaux = (v)) - -/* Additional modifiers */ -/* The symbol is external (does not mean undefined) */ -#define S_SET_EXTERNAL(s) { S_SET_STORAGE_CLASS(s, C_EXT) ; SF_CLEAR_LOCAL(s); } - -/* Auxiliary entry macros. SA_ stands for symbol auxiliary */ -/* Omit the tv related fields */ -/* Accessors */ -#define SYM_AUXENT(S) (&(S)->sy_symbol.ost_auxent[0]) - -#define SA_GET_SYM_TAGNDX(s) (SYM_AUXENT (s)->x_sym.x_tagndx.l) -#define SA_GET_SYM_LNNO(s) (SYM_AUXENT (s)->x_sym.x_misc.x_lnsz.x_lnno) -#define SA_GET_SYM_SIZE(s) (SYM_AUXENT (s)->x_sym.x_misc.x_lnsz.x_size) -#define SA_GET_SYM_FSIZE(s) (SYM_AUXENT (s)->x_sym.x_misc.x_fsize) -#define SA_GET_SYM_LNNOPTR(s) (SYM_AUXENT (s)->x_sym.x_fcnary.x_fcn.x_lnnoptr) -#define SA_GET_SYM_ENDNDX(s) (SYM_AUXENT (s)->x_sym.x_fcnary.x_fcn.x_endndx.l) -#define SA_GET_SYM_DIMEN(s,i) (SYM_AUXENT (s)->x_sym.x_fcnary.x_ary.x_dimen[(i)]) -#define SA_GET_FILE_FNAME(s) (SYM_AUXENT (s)->x_file.x_fname) -#define SA_GET_FILE_FNAME_OFFSET(s) (SYM_AUXENT (s)->x_file.x_n.x_offset) -#define SA_GET_FILE_FNAME_ZEROS(s) (SYM_AUXENT (s)->x_file.x_n.x_zeroes) -#define SA_GET_SCN_SCNLEN(s) (SYM_AUXENT (s)->x_scn.x_scnlen) -#define SA_GET_SCN_NRELOC(s) (SYM_AUXENT (s)->x_scn.x_nreloc) -#define SA_GET_SCN_NLINNO(s) (SYM_AUXENT (s)->x_scn.x_nlinno) - -/* Modifiers */ -#define SA_SET_SYM_TAGNDX(s,v) (SYM_AUXENT (s)->x_sym.x_tagndx.l=(v)) -#define SA_SET_SYM_LNNO(s,v) (SYM_AUXENT (s)->x_sym.x_misc.x_lnsz.x_lnno=(v)) -#define SA_SET_SYM_SIZE(s,v) (SYM_AUXENT (s)->x_sym.x_misc.x_lnsz.x_size=(v)) -#define SA_SET_SYM_FSIZE(s,v) (SYM_AUXENT (s)->x_sym.x_misc.x_fsize=(v)) -#define SA_SET_SYM_LNNOPTR(s,v) (SYM_AUXENT (s)->x_sym.x_fcnary.x_fcn.x_lnnoptr=(v)) -#define SA_SET_SYM_ENDNDX(s,v) (SYM_AUXENT (s)->x_sym.x_fcnary.x_fcn.x_endndx.l=(v)) -#define SA_SET_SYM_DIMEN(s,i,v) (SYM_AUXENT (s)->x_sym.x_fcnary.x_ary.x_dimen[(i)]=(v)) -#define SA_SET_FILE_FNAME(s,v) strncpy(SYM_AUXENT (s)->x_file.x_fname,(v),FILNMLEN) -#define SA_SET_FILE_FNAME_OFFSET(s,v) (SYM_AUXENT (s)->x_file.x_n.x_offset=(v)) -#define SA_SET_FILE_FNAME_ZEROS(s,v) (SYM_AUXENT (s)->x_file.x_n.x_zeroes=(v)) -#define SA_SET_SCN_SCNLEN(s,v) (SYM_AUXENT (s)->x_scn.x_scnlen=(v)) -#define SA_SET_SCN_NRELOC(s,v) (SYM_AUXENT (s)->x_scn.x_nreloc=(v)) -#define SA_SET_SCN_NLINNO(s,v) (SYM_AUXENT (s)->x_scn.x_nlinno=(v)) - -/* - * Internal use only definitions. SF_ stands for symbol flags. - * - * These values can be assigned to sy_symbol.ost_flags field of a symbolS. - * - * You'll break i960 if you shift the SYSPROC bits anywhere else. for - * more on the balname/callname hack, see tc-i960.h. b.out is done - * differently. - */ - -#define SF_I960_MASK (0x000001ff) /* Bits 0-8 are used by the i960 port. */ -#define SF_SYSPROC (0x0000003f) /* bits 0-5 are used to store the sysproc number */ -#define SF_IS_SYSPROC (0x00000040) /* bit 6 marks symbols that are sysprocs */ -#define SF_BALNAME (0x00000080) /* bit 7 marks BALNAME symbols */ -#define SF_CALLNAME (0x00000100) /* bit 8 marks CALLNAME symbols */ - -#define SF_NORMAL_MASK (0x0000ffff) /* bits 12-15 are general purpose. */ - -#define SF_STATICS (0x00001000) /* Mark the .text & all symbols */ -#define SF_DEFINED (0x00002000) /* Symbol is defined in this file */ -#define SF_STRING (0x00004000) /* Symbol name length > 8 */ -#define SF_LOCAL (0x00008000) /* Symbol must not be emitted */ - -#define SF_DEBUG_MASK (0xffff0000) /* bits 16-31 are debug info */ - -#define SF_FUNCTION (0x00010000) /* The symbol is a function */ -#define SF_PROCESS (0x00020000) /* Process symbol before write */ -#define SF_TAGGED (0x00040000) /* Is associated with a tag */ -#define SF_TAG (0x00080000) /* Is a tag */ -#define SF_DEBUG (0x00100000) /* Is in debug or abs section */ -#define SF_GET_SEGMENT (0x00200000) /* Get the section of the forward symbol. */ -#define SF_ADJ_LNNOPTR (0x00400000) /* Has a lnnoptr */ -/* All other bits are unused. */ - -/* Accessors */ -#define SF_GET(s) ((s)->sy_symbol.ost_flags) -#define SF_GET_NORMAL_FIELD(s) (SF_GET (s) & SF_NORMAL_MASK) -#define SF_GET_DEBUG_FIELD(s) (SF_GET (s) & SF_DEBUG_MASK) -#define SF_GET_FILE(s) (SF_GET (s) & SF_FILE) -#define SF_GET_STATICS(s) (SF_GET (s) & SF_STATICS) -#define SF_GET_DEFINED(s) (SF_GET (s) & SF_DEFINED) -#define SF_GET_STRING(s) (SF_GET (s) & SF_STRING) -#define SF_GET_LOCAL(s) (SF_GET (s) & SF_LOCAL) -#define SF_GET_FUNCTION(s) (SF_GET (s) & SF_FUNCTION) -#define SF_GET_PROCESS(s) (SF_GET (s) & SF_PROCESS) -#define SF_GET_DEBUG(s) (SF_GET (s) & SF_DEBUG) -#define SF_GET_TAGGED(s) (SF_GET (s) & SF_TAGGED) -#define SF_GET_TAG(s) (SF_GET (s) & SF_TAG) -#define SF_GET_GET_SEGMENT(s) (SF_GET (s) & SF_GET_SEGMENT) -#define SF_GET_ADJ_LNNOPTR(s) (SF_GET (s) & SF_ADJ_LNNOPTR) -#define SF_GET_I960(s) (SF_GET (s) & SF_I960_MASK) /* used by i960 */ -#define SF_GET_BALNAME(s) (SF_GET (s) & SF_BALNAME) /* used by i960 */ -#define SF_GET_CALLNAME(s) (SF_GET (s) & SF_CALLNAME) /* used by i960 */ -#define SF_GET_IS_SYSPROC(s) (SF_GET (s) & SF_IS_SYSPROC) /* used by i960 */ -#define SF_GET_SYSPROC(s) (SF_GET (s) & SF_SYSPROC) /* used by i960 */ - -/* Modifiers */ -#define SF_SET(s,v) (SF_GET (s) = (v)) -#define SF_SET_NORMAL_FIELD(s,v)(SF_GET (s) |= ((v) & SF_NORMAL_MASK)) -#define SF_SET_DEBUG_FIELD(s,v) (SF_GET (s) |= ((v) & SF_DEBUG_MASK)) -#define SF_SET_FILE(s) (SF_GET (s) |= SF_FILE) -#define SF_SET_STATICS(s) (SF_GET (s) |= SF_STATICS) -#define SF_SET_DEFINED(s) (SF_GET (s) |= SF_DEFINED) -#define SF_SET_STRING(s) (SF_GET (s) |= SF_STRING) -#define SF_SET_LOCAL(s) (SF_GET (s) |= SF_LOCAL) -#define SF_CLEAR_LOCAL(s) (SF_GET (s) &= ~SF_LOCAL) -#define SF_SET_FUNCTION(s) (SF_GET (s) |= SF_FUNCTION) -#define SF_SET_PROCESS(s) (SF_GET (s) |= SF_PROCESS) -#define SF_SET_DEBUG(s) (SF_GET (s) |= SF_DEBUG) -#define SF_SET_TAGGED(s) (SF_GET (s) |= SF_TAGGED) -#define SF_SET_TAG(s) (SF_GET (s) |= SF_TAG) -#define SF_SET_GET_SEGMENT(s) (SF_GET (s) |= SF_GET_SEGMENT) -#define SF_SET_ADJ_LNNOPTR(s) (SF_GET (s) |= SF_ADJ_LNNOPTR) -#define SF_SET_I960(s,v) (SF_GET (s) |= ((v) & SF_I960_MASK)) /* used by i960 */ -#define SF_SET_BALNAME(s) (SF_GET (s) |= SF_BALNAME) /* used by i960 */ -#define SF_SET_CALLNAME(s) (SF_GET (s) |= SF_CALLNAME) /* used by i960 */ -#define SF_SET_IS_SYSPROC(s) (SF_GET (s) |= SF_IS_SYSPROC) /* used by i960 */ -#define SF_SET_SYSPROC(s,v) (SF_GET (s) |= ((v) & SF_SYSPROC)) /* used by i960 */ - -/* File header macro and type definition */ - -/* - * File position calculators. Beware to use them when all the - * appropriate fields are set in the header. - */ - -#ifdef OBJ_COFF_OMIT_OPTIONAL_HEADER -#define OBJ_COFF_AOUTHDRSZ (0) -#else -#define OBJ_COFF_AOUTHDRSZ (AOUTHDRSZ) -#endif /* OBJ_COFF_OMIT_OPTIONAL_HEADER */ - -#define H_GET_FILE_SIZE(h) \ - (long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \ - H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ + \ - H_GET_TEXT_SIZE(h) + H_GET_DATA_SIZE(h) + \ - H_GET_RELOCATION_SIZE(h) + H_GET_LINENO_SIZE(h) + \ - H_GET_SYMBOL_TABLE_SIZE(h) + \ - (h)->string_table_size) -#define H_GET_TEXT_FILE_OFFSET(h) \ - (long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \ - H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ) -#define H_GET_DATA_FILE_OFFSET(h) \ - (long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \ - H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ + \ - H_GET_TEXT_SIZE(h)) -#define H_GET_BSS_FILE_OFFSET(h) 0 -#define H_GET_RELOCATION_FILE_OFFSET(h) \ - (long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \ - H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ + \ - H_GET_TEXT_SIZE(h) + H_GET_DATA_SIZE(h)) -#define H_GET_LINENO_FILE_OFFSET(h) \ - (long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \ - H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ + \ - H_GET_TEXT_SIZE(h) + H_GET_DATA_SIZE(h) + \ - H_GET_RELOCATION_SIZE(h)) -#define H_GET_SYMBOL_TABLE_FILE_OFFSET(h) \ - (long)(FILHSZ + OBJ_COFF_AOUTHDRSZ + \ - H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ + \ - H_GET_TEXT_SIZE(h) + H_GET_DATA_SIZE(h) + \ - H_GET_RELOCATION_SIZE(h) + H_GET_LINENO_SIZE(h)) - -/* Accessors */ -/* aouthdr */ -#define H_GET_MAGIC_NUMBER(h) ((h)->aouthdr.magic) -#define H_GET_VERSION_STAMP(h) ((h)->aouthdr.vstamp) -#define H_GET_TEXT_SIZE(h) ((h)->aouthdr.tsize) -#define H_GET_DATA_SIZE(h) ((h)->aouthdr.dsize) -#define H_GET_BSS_SIZE(h) ((h)->aouthdr.bsize) -#define H_GET_ENTRY_POINT(h) ((h)->aouthdr.entry) -#define H_GET_TEXT_START(h) ((h)->aouthdr.text_start) -#define H_GET_DATA_START(h) ((h)->aouthdr.data_start) -/* filehdr */ -#define H_GET_FILE_MAGIC_NUMBER(h) ((h)->filehdr.f_magic) -#define H_GET_NUMBER_OF_SECTIONS(h) ((h)->filehdr.f_nscns) -#define H_GET_TIME_STAMP(h) ((h)->filehdr.f_timdat) -#define H_GET_SYMBOL_TABLE_POINTER(h) ((h)->filehdr.f_symptr) -#define H_GET_SYMBOL_COUNT(h) ((h)->filehdr.f_nsyms) -#define H_GET_SYMBOL_TABLE_SIZE(h) (H_GET_SYMBOL_COUNT(h) * SYMESZ) -#define H_GET_SIZEOF_OPTIONAL_HEADER(h) ((h)->filehdr.f_opthdr) -#define H_GET_FLAGS(h) ((h)->filehdr.f_flags) -/* Extra fields to achieve bsd a.out compatibility and for convenience */ -#define H_GET_RELOCATION_SIZE(h) ((h)->relocation_size) -#define H_GET_STRING_SIZE(h) ((h)->string_table_size) -#define H_GET_LINENO_SIZE(h) ((h)->lineno_size) - -#ifndef OBJ_COFF_OMIT_OPTIONAL_HEADER -#define H_GET_HEADER_SIZE(h) (sizeof(FILHDR) \ - + sizeof(AOUTHDR)\ - + (H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ)) -#else /* OBJ_COFF_OMIT_OPTIONAL_HEADER */ -#define H_GET_HEADER_SIZE(h) (sizeof(FILHDR) \ - + (H_GET_NUMBER_OF_SECTIONS(h) * SCNHSZ)) -#endif /* OBJ_COFF_OMIT_OPTIONAL_HEADER */ - -#define H_GET_TEXT_RELOCATION_SIZE(h) (text_section_header.s_nreloc * RELSZ) -#define H_GET_DATA_RELOCATION_SIZE(h) (data_section_header.s_nreloc * RELSZ) - -/* Modifiers */ -/* aouthdr */ -#define H_SET_MAGIC_NUMBER(h,v) ((h)->aouthdr.magic = (v)) -#define H_SET_VERSION_STAMP(h,v) ((h)->aouthdr.vstamp = (v)) -#define H_SET_TEXT_SIZE(h,v) ((h)->aouthdr.tsize = (v)) -#define H_SET_DATA_SIZE(h,v) ((h)->aouthdr.dsize = (v)) -#define H_SET_BSS_SIZE(h,v) ((h)->aouthdr.bsize = (v)) -#define H_SET_ENTRY_POINT(h,v) ((h)->aouthdr.entry = (v)) -#define H_SET_TEXT_START(h,v) ((h)->aouthdr.text_start = (v)) -#define H_SET_DATA_START(h,v) ((h)->aouthdr.data_start = (v)) -/* filehdr */ -#define H_SET_FILE_MAGIC_NUMBER(h,v) ((h)->filehdr.f_magic = (v)) -#define H_SET_NUMBER_OF_SECTIONS(h,v) ((h)->filehdr.f_nscns = (v)) -#define H_SET_TIME_STAMP(h,v) ((h)->filehdr.f_timdat = (v)) -#define H_SET_SYMBOL_TABLE_POINTER(h,v) ((h)->filehdr.f_symptr = (v)) -#define H_SET_SYMBOL_TABLE_SIZE(h,v) ((h)->filehdr.f_nsyms = (v)) -#define H_SET_SIZEOF_OPTIONAL_HEADER(h,v) ((h)->filehdr.f_opthdr = (v)) -#define H_SET_FLAGS(h,v) ((h)->filehdr.f_flags = (v)) -/* Extra fields to achieve bsd a.out compatibility and for convinience */ -#define H_SET_RELOCATION_SIZE(h,t,d) ((h)->relocation_size = (t)+(d)) -#define H_SET_STRING_SIZE(h,v) ((h)->string_table_size = (v)) -#define H_SET_LINENO_SIZE(h,v) ((h)->lineno_size = (v)) - -/* Segment flipping */ - -typedef struct -{ - struct internal_aouthdr aouthdr; /* a.out header */ - struct internal_filehdr filehdr; /* File header, not machine dep. */ - long string_table_size; /* names + '\0' + sizeof(int) */ - long relocation_size; /* Cumulated size of relocation - information for all sections in - bytes. */ - long lineno_size; /* Size of the line number information - table in bytes */ -} object_headers; - - - -struct lineno_list -{ - struct bfd_internal_lineno line; - char *frag; /* Frag to which the line number is related */ - struct lineno_list *next; /* Forward chain pointer */ -}; - - - - -#define obj_segment_name(i) (segment_info[(int) (i)].scnhdr.s_name) - -#define obj_add_segment(s) obj_coff_add_segment (s) - -extern segT obj_coff_add_segment PARAMS ((const char *)); - -extern void obj_coff_section PARAMS ((int)); - -extern void c_dot_file_symbol PARAMS ((char *filename)); -#define obj_app_file c_dot_file_symbol -extern void obj_extra_stuff PARAMS ((object_headers * headers)); - -extern segT s_get_segment PARAMS ((symbolS *ptr)); - -extern void c_section_header PARAMS ((struct internal_scnhdr * header, - char *name, - long core_address, - long size, - long data_ptr, - long reloc_ptr, - long lineno_ptr, - long reloc_number, - long lineno_number, - long alignment)); - -#ifndef tc_coff_symbol_emit_hook -void tc_coff_symbol_emit_hook PARAMS ((symbolS *)); -#endif - -/* sanity check */ - -#ifdef TC_I960 -#ifndef C_LEAFSTAT -hey ! Where is the C_LEAFSTAT definition ? i960 - coff support is depending on it. -#endif /* no C_LEAFSTAT */ -#endif /* TC_I960 */ -extern struct internal_scnhdr data_section_header; -extern struct internal_scnhdr text_section_header; - -/* Forward the segment of a forwarded symbol. */ -#define OBJ_COPY_SYMBOL_ATTRIBUTES(dest,src) \ - (SF_GET_GET_SEGMENT (dest) \ - ? (S_SET_SEGMENT (dest, S_GET_SEGMENT (src)), 0) \ - : 0) - -#ifdef TE_PE -#define obj_handle_link_once(t) obj_coff_pe_handle_link_once (t) -extern void obj_coff_pe_handle_link_once (); -#endif - -#endif /* not BFD_ASSEMBLER */ - -extern const pseudo_typeS coff_pseudo_table[]; - -#ifndef obj_pop_insert -#define obj_pop_insert() pop_insert (coff_pseudo_table) -#endif - -/* In COFF, if a symbol is defined using .def/.val SYM/.endef, it's OK - to redefine the symbol later on. This can happen if C symbols use - a prefix, and a symbol is defined both with and without the prefix, - as in start/_start/__start in gcc/libgcc1-test.c. */ -#define RESOLVE_SYMBOL_REDEFINITION(sym) \ -(SF_GET_GET_SEGMENT (sym) \ - ? (sym->sy_frag = frag_now, \ - S_SET_VALUE (sym, frag_now_fix ()), \ - S_SET_SEGMENT (sym, now_seg), \ - 0) \ - : 0) - -/* Stabs in a coff file go into their own section. */ -#define SEPARATE_STAB_SECTIONS 1 - -/* We need 12 bytes at the start of the section to hold some initial - information. */ -extern void obj_coff_init_stab_section PARAMS ((segT)); -#define INIT_STAB_SECTION(seg) obj_coff_init_stab_section (seg) - -/* Store the number of relocations in the section aux entry. */ -#define SET_SECTION_RELOCS(sec, relocs, n) \ - SA_SET_SCN_NRELOC (section_symbol (sec), n) - -#endif /* OBJ_FORMAT_H */ diff --git a/contrib/binutils/gas/config/obj-ecoff.c b/contrib/binutils/gas/config/obj-ecoff.c deleted file mode 100644 index 767dc588c8296..0000000000000 --- a/contrib/binutils/gas/config/obj-ecoff.c +++ /dev/null @@ -1,315 +0,0 @@ -/* ECOFF object file format. - Copyright (C) 1993, 94, 95, 96, 97, 98, 99, 2000 - Free Software Foundation, Inc. - Contributed by Cygnus Support. - This file was put together by Ian Lance Taylor <ian@cygnus.com>. - - This file is part of GAS. - - 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. */ - -#define OBJ_HEADER "obj-ecoff.h" -#include "as.h" -#include "coff/internal.h" -#include "bfd/libcoff.h" -#include "bfd/libecoff.h" - -/* Almost all of the ECOFF support is actually in ecoff.c in the main - gas directory. This file mostly just arranges to call that one at - the right times. */ - -static int ecoff_sec_sym_ok_for_reloc PARAMS ((asection *)); -static void obj_ecoff_frob_symbol PARAMS ((symbolS *, int *)); -static void ecoff_pop_insert PARAMS ((void)); - -/* These are the pseudo-ops we support in this file. Only those - relating to debugging information are supported here. - - The following pseudo-ops from the Kane and Heinrich MIPS book - should be defined here, but are currently unsupported: .aent, - .bgnb, .endb, .verstamp, .vreg. - - The following pseudo-ops from the Kane and Heinrich MIPS book are - MIPS CPU specific, and should be defined by tc-mips.c: .alias, - .extern, .galive, .gjaldef, .gjrlive, .livereg, .noalias, .option, - .rdata, .sdata, .set. - - The following pseudo-ops from the Kane and Heinrich MIPS book are - not MIPS CPU specific, but are also not ECOFF specific. I have - only listed the ones which are not already in read.c. It's not - completely clear where these should be defined, but tc-mips.c is - probably the most reasonable place: .asciiz, .asm0, .endr, .err, - .half, .lab, .repeat, .struct, .weakext. */ - -const pseudo_typeS obj_pseudo_table[] = -{ - /* COFF style debugging information. .ln is not used; .loc is used - instead. */ - { "def", ecoff_directive_def, 0 }, - { "dim", ecoff_directive_dim, 0 }, - { "endef", ecoff_directive_endef, 0 }, - { "file", ecoff_directive_file, 0 }, - { "scl", ecoff_directive_scl, 0 }, - { "size", ecoff_directive_size, 0 }, - { "esize", ecoff_directive_size, 0 }, - { "tag", ecoff_directive_tag, 0 }, - { "type", ecoff_directive_type, 0 }, - { "etype", ecoff_directive_type, 0 }, - { "val", ecoff_directive_val, 0 }, - - /* ECOFF specific debugging information. */ - { "begin", ecoff_directive_begin, 0 }, - { "bend", ecoff_directive_bend, 0 }, - { "end", ecoff_directive_end, 0 }, - { "ent", ecoff_directive_ent, 0 }, - { "fmask", ecoff_directive_fmask, 0 }, - { "frame", ecoff_directive_frame, 0 }, - { "loc", ecoff_directive_loc, 0 }, - { "mask", ecoff_directive_mask, 0 }, - - /* Other ECOFF directives. */ - { "extern", ecoff_directive_extern, 0 }, - -#ifndef TC_MIPS - /* For TC_MIPS, tc-mips.c adds this. */ - { "weakext", ecoff_directive_weakext, 0 }, -#endif - - /* These are used on Irix. I don't know how to implement them. */ - { "bgnb", s_ignore, 0 }, - { "endb", s_ignore, 0 }, - { "verstamp", s_ignore, 0 }, - - /* Sentinel. */ - { NULL } -}; - -/* Swap out the symbols and debugging information for BFD. */ - -void -ecoff_frob_file () -{ - const struct ecoff_debug_swap * const debug_swap - = &ecoff_backend (stdoutput)->debug_swap; - bfd_vma addr; - asection *sec; - HDRR *hdr; - char *buf; - char *set; - - /* Set the section VMA values. We force the .sdata and .sbss - sections to the end to ensure that their VMA addresses are close - together so that the GP register can address both of them. We - put the .bss section after the .sbss section. - - Also, for the Alpha, we must sort the sections, to make sure they - appear in the output file in the correct order. (Actually, maybe - this is a job for BFD. But the VMAs computed would be out of - whack if we computed them given our initial, random ordering. - It's possible that that wouldn't break things; I could do some - experimenting sometime and find out. - - This output ordering of sections is magic, on the Alpha, at - least. The .lita section must come before .lit8 and .lit4, - otherwise the OSF/1 linker may silently trash the .lit{4,8} - section contents. Also, .text must preceed .rdata. These differ - from the order described in some parts of the DEC OSF/1 Assembly - Language Programmer's Guide, but that order doesn't seem to work - with their linker. - - I don't know if section ordering on the MIPS is important. */ - - static const char *const names[] = { - /* text segment */ - ".text", ".rdata", ".init", ".fini", - /* data segment */ - ".data", ".lita", ".lit8", ".lit4", ".sdata", ".got", - /* bss segment */ - ".sbss", ".bss", - }; -#define n_names (sizeof (names) / sizeof (names[0])) - - addr = 0; - { - /* Sections that match names, order to be straightened out later. */ - asection *secs[n_names]; - /* Linked list of sections with non-matching names. Random ordering. */ - asection *other_sections = 0; - /* Pointer to next section, since we're destroying the original - ordering. */ - asection *next; - - int i; - - for (i = 0; i < n_names; i++) - secs[i] = 0; - for (sec = stdoutput->sections; sec != (asection *) NULL; sec = next) - { - next = sec->next; - for (i = 0; i < n_names; i++) - if (!strcmp (sec->name, names[i])) - { - secs[i] = sec; - break; - } - if (i == n_names) - { - bfd_set_section_vma (stdoutput, sec, addr); - addr += bfd_section_size (stdoutput, sec); - sec->next = other_sections; - other_sections = sec; - } - } - for (i = 0; i < n_names; i++) - if (secs[i]) - { - sec = secs[i]; - bfd_set_section_vma (stdoutput, sec, addr); - addr += bfd_section_size (stdoutput, sec); - } - for (i = n_names - 1; i >= 0; i--) - if (secs[i]) - { - sec = secs[i]; - sec->next = other_sections; - other_sections = sec; - } - stdoutput->sections = other_sections; - } - - /* Build the ECOFF debugging information. */ - assert (ecoff_data (stdoutput) != 0); - hdr = &ecoff_data (stdoutput)->debug_info.symbolic_header; - ecoff_build_debug (hdr, &buf, debug_swap); - - /* Finish up the ecoff_tdata structure. */ - set = buf; -#define SET(ptr, count, type, size) \ - if (hdr->count == 0) \ - ecoff_data (stdoutput)->debug_info.ptr = (type) NULL; \ - else \ - { \ - ecoff_data (stdoutput)->debug_info.ptr = (type) set; \ - set += hdr->count * size; \ - } - - SET (line, cbLine, unsigned char *, sizeof (unsigned char)); - SET (external_dnr, idnMax, PTR, debug_swap->external_dnr_size); - SET (external_pdr, ipdMax, PTR, debug_swap->external_pdr_size); - SET (external_sym, isymMax, PTR, debug_swap->external_sym_size); - SET (external_opt, ioptMax, PTR, debug_swap->external_opt_size); - SET (external_aux, iauxMax, union aux_ext *, sizeof (union aux_ext)); - SET (ss, issMax, char *, sizeof (char)); - SET (ssext, issExtMax, char *, sizeof (char)); - SET (external_rfd, crfd, PTR, debug_swap->external_rfd_size); - SET (external_fdr, ifdMax, PTR, debug_swap->external_fdr_size); - SET (external_ext, iextMax, PTR, debug_swap->external_ext_size); - -#undef SET - - /* Fill in the register masks. */ - { - unsigned long gprmask = 0; - unsigned long fprmask = 0; - unsigned long *cprmask = NULL; - -#ifdef TC_MIPS - /* Fill in the MIPS register masks. It's probably not worth - setting up a generic interface for this. */ - gprmask = mips_gprmask; - cprmask = mips_cprmask; -#endif - -#ifdef TC_ALPHA - alpha_frob_ecoff_data (); - - if (! bfd_ecoff_set_gp_value (stdoutput, alpha_gp_value)) - as_fatal (_("Can't set GP value")); - - gprmask = alpha_gprmask; - fprmask = alpha_fprmask; -#endif - - if (! bfd_ecoff_set_regmasks (stdoutput, gprmask, fprmask, cprmask)) - as_fatal (_("Can't set register masks")); - } -} - -/* This is called by the ECOFF code to set the external information - for a symbol. We just pass it on to BFD, which expects the swapped - information to be stored in the native field of the symbol. */ - -void -obj_ecoff_set_ext (sym, ext) - symbolS *sym; - EXTR *ext; -{ - const struct ecoff_debug_swap * const debug_swap - = &ecoff_backend (stdoutput)->debug_swap; - ecoff_symbol_type *esym; - - know (bfd_asymbol_flavour (symbol_get_bfdsym (sym)) - == bfd_target_ecoff_flavour); - esym = ecoffsymbol (symbol_get_bfdsym (sym)); - esym->local = false; - esym->native = xmalloc (debug_swap->external_ext_size); - (*debug_swap->swap_ext_out) (stdoutput, ext, esym->native); -} - -static int -ecoff_sec_sym_ok_for_reloc (sec) - asection *sec; -{ - return 1; -} - -static void -obj_ecoff_frob_symbol (sym, puntp) - symbolS *sym; - int *puntp; -{ - ecoff_frob_symbol (sym); -} - -static void -ecoff_pop_insert () -{ - pop_insert (obj_pseudo_table); -} - -const struct format_ops ecoff_format_ops = -{ - bfd_target_ecoff_flavour, - 0, /* dfl_leading_underscore */ - 1, /* emit_section_symbols */ - obj_ecoff_frob_symbol, - ecoff_frob_file, - 0, /* frob_file_after_relocs */ - 0, /* s_get_size */ - 0, /* s_set_size */ - 0, /* s_get_align */ - 0, /* s_set_align */ - 0, /* s_get_other */ - 0, /* s_get_desc */ - 0, /* copy_symbol_attributes */ - ecoff_generate_asm_lineno, - ecoff_stab, - ecoff_sec_sym_ok_for_reloc, - ecoff_pop_insert, - ecoff_set_ext, - ecoff_read_begin_hook, - ecoff_symbol_new_hook, -}; diff --git a/contrib/binutils/gas/config/obj-ecoff.h b/contrib/binutils/gas/config/obj-ecoff.h deleted file mode 100644 index 8bca254c0ce02..0000000000000 --- a/contrib/binutils/gas/config/obj-ecoff.h +++ /dev/null @@ -1,71 +0,0 @@ -/* ECOFF object file format header file. - Copyright (C) 1993, 94, 95, 96, 97, 1999 Free Software Foundation, Inc. - Contributed by Cygnus Support. - Written by Ian Lance Taylor <ian@cygnus.com>. - - This file is part of GAS. - - 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. */ - -#define OBJ_ECOFF 1 - -/* Use the generic ECOFF debugging code. */ -#define ECOFF_DEBUGGING 1 - -#define OUTPUT_FLAVOR bfd_target_ecoff_flavour - -#include "targ-cpu.h" - -#include "ecoff.h" - -/* For each gas symbol we keep track of which file it came from, of - whether we have generated an ECOFF symbol for it, and whether the - symbols is undefined (this last is needed to distinguish a .extern - symbols from a .comm symbol). */ - -struct ecoff_sy_obj -{ - struct efdr *ecoff_file; - struct localsym *ecoff_symbol; - valueT ecoff_extern_size; -}; - -#define OBJ_SYMFIELD_TYPE struct ecoff_sy_obj - -/* Modify the ECOFF symbol. */ -#define obj_frob_symbol(symp, punt) ecoff_frob_symbol (symp) - -/* This is used to write the symbolic data in the format that BFD - expects it. */ -extern void ecoff_frob_file PARAMS ((void)); -#define obj_frob_file() ecoff_frob_file () - -/* We use the ECOFF functions as our hooks. */ -#define obj_read_begin_hook ecoff_read_begin_hook -#define obj_symbol_new_hook ecoff_symbol_new_hook - -/* Record file switches in the ECOFF symbol table. */ -#define obj_app_file(name) ecoff_new_file (name) - -/* At the moment we don't want to do any stabs processing in read.c. */ -#define OBJ_PROCESS_STAB(seg, what, string, type, other, desc) \ - ecoff_stab ((seg), (what), (string), (type), (other), (desc)) - -#define EMIT_SECTION_SYMBOLS 0 -#define obj_sec_sym_ok_for_reloc(SEC) 1 - -#define obj_ecoff_set_ext ecoff_set_ext -extern void obj_ecoff_set_ext PARAMS ((symbolS *, EXTR *)); diff --git a/contrib/binutils/gas/config/obj-elf.c b/contrib/binutils/gas/config/obj-elf.c deleted file mode 100644 index 21fd0fa22411c..0000000000000 --- a/contrib/binutils/gas/config/obj-elf.c +++ /dev/null @@ -1,1922 +0,0 @@ -/* ELF object file format - Copyright (C) 1992, 93, 94, 95, 96, 97, 98, 99, 2000 - 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. */ - -#define OBJ_HEADER "obj-elf.h" -#include "as.h" -#include "subsegs.h" -#include "obstack.h" - -#ifndef ECOFF_DEBUGGING -#define ECOFF_DEBUGGING 0 -#else -#define NEED_ECOFF_DEBUG -#endif - -#ifdef NEED_ECOFF_DEBUG -#include "ecoff.h" -#endif - -#ifdef TC_ALPHA -#include "elf/alpha.h" -#endif - -#ifdef TC_MIPS -#include "elf/mips.h" -#endif - -#ifdef TC_PPC -#include "elf/ppc.h" -#endif - -#ifdef TC_I370 -#include "elf/i370.h" -#endif - -static bfd_vma elf_s_get_size PARAMS ((symbolS *)); -static void elf_s_set_size PARAMS ((symbolS *, bfd_vma)); -static bfd_vma elf_s_get_align PARAMS ((symbolS *)); -static void elf_s_set_align PARAMS ((symbolS *, bfd_vma)); -static void elf_copy_symbol_attributes PARAMS ((symbolS *, symbolS *)); -static int elf_sec_sym_ok_for_reloc PARAMS ((asection *)); -static void adjust_stab_sections PARAMS ((bfd *, asection *, PTR)); - -#ifdef NEED_ECOFF_DEBUG -static boolean elf_get_extr PARAMS ((asymbol *, EXTR *)); -static void elf_set_index PARAMS ((asymbol *, bfd_size_type)); -#endif - -static void obj_elf_line PARAMS ((int)); -void obj_elf_version PARAMS ((int)); -static void obj_elf_size PARAMS ((int)); -static void obj_elf_type PARAMS ((int)); -static void obj_elf_ident PARAMS ((int)); -static void obj_elf_weak PARAMS ((int)); -static void obj_elf_local PARAMS ((int)); -static void obj_elf_visibility PARAMS ((int)); -static void obj_elf_symver PARAMS ((int)); -static void obj_elf_vtable_inherit PARAMS ((int)); -static void obj_elf_vtable_entry PARAMS ((int)); -static void obj_elf_subsection PARAMS ((int)); -static void obj_elf_popsection PARAMS ((int)); - -static const pseudo_typeS elf_pseudo_table[] = -{ - {"comm", obj_elf_common, 0}, - {"common", obj_elf_common, 1}, - {"ident", obj_elf_ident, 0}, - {"local", obj_elf_local, 0}, - {"previous", obj_elf_previous, 0}, - {"section", obj_elf_section, 0}, - {"section.s", obj_elf_section, 0}, - {"sect", obj_elf_section, 0}, - {"sect.s", obj_elf_section, 0}, - {"pushsection", obj_elf_section, 1}, - {"popsection", obj_elf_popsection, 0}, - {"size", obj_elf_size, 0}, - {"type", obj_elf_type, 0}, - {"version", obj_elf_version, 0}, - {"weak", obj_elf_weak, 0}, - - /* These define symbol visibility. */ - {"internal", obj_elf_visibility, STV_INTERNAL}, - {"hidden", obj_elf_visibility, STV_HIDDEN}, - {"protected", obj_elf_visibility, STV_PROTECTED}, - - /* These are used for stabs-in-elf configurations. */ - {"line", obj_elf_line, 0}, - - /* This is a GNU extension to handle symbol versions. */ - {"symver", obj_elf_symver, 0}, - - /* A GNU extension to change subsection only. */ - {"subsection", obj_elf_subsection, 0}, - - /* These are GNU extensions to aid in garbage collecting C++ vtables. */ - {"vtable_inherit", obj_elf_vtable_inherit, 0}, - {"vtable_entry", obj_elf_vtable_entry, 0}, - - /* These are used for dwarf. */ - {"2byte", cons, 2}, - {"4byte", cons, 4}, - {"8byte", cons, 8}, - - /* We need to trap the section changing calls to handle .previous. */ - {"data", obj_elf_data, 0}, - {"text", obj_elf_text, 0}, - - /* End sentinel. */ - {NULL, NULL, 0}, -}; - -static const pseudo_typeS ecoff_debug_pseudo_table[] = -{ -#ifdef NEED_ECOFF_DEBUG - /* COFF style debugging information for ECOFF. .ln is not used; .loc - is used instead. */ - { "def", ecoff_directive_def, 0 }, - { "dim", ecoff_directive_dim, 0 }, - { "endef", ecoff_directive_endef, 0 }, - { "file", ecoff_directive_file, 0 }, - { "scl", ecoff_directive_scl, 0 }, - { "tag", ecoff_directive_tag, 0 }, - { "val", ecoff_directive_val, 0 }, - - /* COFF debugging requires pseudo-ops .size and .type, but ELF - already has meanings for those. We use .esize and .etype - instead. These are only generated by gcc anyhow. */ - { "esize", ecoff_directive_size, 0 }, - { "etype", ecoff_directive_type, 0 }, - - /* ECOFF specific debugging information. */ - { "begin", ecoff_directive_begin, 0 }, - { "bend", ecoff_directive_bend, 0 }, - { "end", ecoff_directive_end, 0 }, - { "ent", ecoff_directive_ent, 0 }, - { "fmask", ecoff_directive_fmask, 0 }, - { "frame", ecoff_directive_frame, 0 }, - { "loc", ecoff_directive_loc, 0 }, - { "mask", ecoff_directive_mask, 0 }, - - /* Other ECOFF directives. */ - { "extern", ecoff_directive_extern, 0 }, - - /* These are used on Irix. I don't know how to implement them. */ - { "alias", s_ignore, 0 }, - { "bgnb", s_ignore, 0 }, - { "endb", s_ignore, 0 }, - { "lab", s_ignore, 0 }, - { "noalias", s_ignore, 0 }, - { "verstamp", s_ignore, 0 }, - { "vreg", s_ignore, 0 }, -#endif - - {NULL, NULL, 0} /* end sentinel */ -}; - -#undef NO_RELOC -#include "aout/aout64.h" - -/* This is called when the assembler starts. */ - -void -elf_begin () -{ - /* Add symbols for the known sections to the symbol table. */ - symbol_table_insert (section_symbol (bfd_get_section_by_name (stdoutput, - TEXT_SECTION_NAME))); - symbol_table_insert (section_symbol (bfd_get_section_by_name (stdoutput, - DATA_SECTION_NAME))); - symbol_table_insert (section_symbol (bfd_get_section_by_name (stdoutput, - BSS_SECTION_NAME))); -} - -void -elf_pop_insert () -{ - pop_insert (elf_pseudo_table); - if (ECOFF_DEBUGGING) - pop_insert (ecoff_debug_pseudo_table); -} - -static bfd_vma -elf_s_get_size (sym) - symbolS *sym; -{ - return S_GET_SIZE (sym); -} - -static void -elf_s_set_size (sym, sz) - symbolS *sym; - bfd_vma sz; -{ - S_SET_SIZE (sym, sz); -} - -static bfd_vma -elf_s_get_align (sym) - symbolS *sym; -{ - return S_GET_ALIGN (sym); -} - -static void -elf_s_set_align (sym, align) - symbolS *sym; - bfd_vma align; -{ - S_SET_ALIGN (sym, align); -} - -int -elf_s_get_other (sym) - symbolS *sym; -{ - return elf_symbol (symbol_get_bfdsym (sym))->internal_elf_sym.st_other; -} - -static void -elf_copy_symbol_attributes (dest, src) - symbolS *dest, *src; -{ - OBJ_COPY_SYMBOL_ATTRIBUTES (dest, src); -} - -static int -elf_sec_sym_ok_for_reloc (sec) - asection *sec; -{ - return obj_sec_sym_ok_for_reloc (sec); -} - -void -elf_file_symbol (s) - char *s; -{ - symbolS *sym; - - sym = symbol_new (s, absolute_section, (valueT) 0, (struct frag *) 0); - symbol_set_frag (sym, &zero_address_frag); - symbol_get_bfdsym (sym)->flags |= BSF_FILE; - - if (symbol_rootP != sym) - { - symbol_remove (sym, &symbol_rootP, &symbol_lastP); - symbol_insert (sym, symbol_rootP, &symbol_rootP, &symbol_lastP); -#ifdef DEBUG - verify_symbol_chain (symbol_rootP, symbol_lastP); -#endif - } - -#ifdef NEED_ECOFF_DEBUG - ecoff_new_file (s); -#endif -} - -void -obj_elf_common (is_common) - int is_common; -{ - char *name; - char c; - char *p; - int temp, size; - symbolS *symbolP; - int have_align; - - if (flag_mri && is_common) - { - s_mri_common (0); - return; - } - - name = input_line_pointer; - c = get_symbol_end (); - /* just after name is now '\0' */ - p = input_line_pointer; - *p = c; - SKIP_WHITESPACE (); - if (*input_line_pointer != ',') - { - as_bad (_("Expected comma after symbol-name")); - ignore_rest_of_line (); - return; - } - input_line_pointer++; /* skip ',' */ - if ((temp = get_absolute_expression ()) < 0) - { - as_bad (_(".COMMon length (%d.) <0! Ignored."), temp); - ignore_rest_of_line (); - return; - } - size = temp; - *p = 0; - symbolP = symbol_find_or_make (name); - *p = c; - if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP)) - { - as_bad (_("Ignoring attempt to re-define symbol")); - ignore_rest_of_line (); - return; - } - if (S_GET_VALUE (symbolP) != 0) - { - if (S_GET_VALUE (symbolP) != (valueT) size) - { - as_warn (_("Length of .comm \"%s\" is already %ld. Not changed to %d."), - S_GET_NAME (symbolP), (long) S_GET_VALUE (symbolP), size); - } - } - know (symbolP->sy_frag == &zero_address_frag); - if (*input_line_pointer != ',') - have_align = 0; - else - { - have_align = 1; - input_line_pointer++; - SKIP_WHITESPACE (); - } - if (! have_align || *input_line_pointer != '"') - { - if (! have_align) - temp = 0; - else - { - temp = get_absolute_expression (); - if (temp < 0) - { - temp = 0; - as_warn (_("Common alignment negative; 0 assumed")); - } - } - if (symbol_get_obj (symbolP)->local) - { - segT old_sec; - int old_subsec; - char *pfrag; - int align; - - /* allocate_bss: */ - old_sec = now_seg; - old_subsec = now_subseg; - if (temp) - { - /* convert to a power of 2 alignment */ - for (align = 0; (temp & 1) == 0; temp >>= 1, ++align); - if (temp != 1) - { - as_bad (_("Common alignment not a power of 2")); - ignore_rest_of_line (); - return; - } - } - else - align = 0; - record_alignment (bss_section, align); - subseg_set (bss_section, 0); - if (align) - frag_align (align, 0, 0); - if (S_GET_SEGMENT (symbolP) == bss_section) - symbol_get_frag (symbolP)->fr_symbol = 0; - symbol_set_frag (symbolP, frag_now); - pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP, - (offsetT) size, (char *) 0); - *pfrag = 0; - S_SET_SIZE (symbolP, size); - S_SET_SEGMENT (symbolP, bss_section); - S_CLEAR_EXTERNAL (symbolP); - subseg_set (old_sec, old_subsec); - } - else - { - allocate_common: - S_SET_VALUE (symbolP, (valueT) size); - S_SET_ALIGN (symbolP, temp); - S_SET_EXTERNAL (symbolP); - S_SET_SEGMENT (symbolP, bfd_com_section_ptr); - } - } - else - { - input_line_pointer++; - /* @@ Some use the dot, some don't. Can we get some consistency?? */ - if (*input_line_pointer == '.') - input_line_pointer++; - /* @@ Some say data, some say bss. */ - if (strncmp (input_line_pointer, "bss\"", 4) - && strncmp (input_line_pointer, "data\"", 5)) - { - while (*--input_line_pointer != '"') - ; - input_line_pointer--; - goto bad_common_segment; - } - while (*input_line_pointer++ != '"') - ; - goto allocate_common; - } - - symbol_get_bfdsym (symbolP)->flags |= BSF_OBJECT; - - demand_empty_rest_of_line (); - return; - - { - bad_common_segment: - p = input_line_pointer; - while (*p && *p != '\n') - p++; - c = *p; - *p = '\0'; - as_bad (_("bad .common segment %s"), input_line_pointer + 1); - *p = c; - input_line_pointer = p; - ignore_rest_of_line (); - return; - } -} - -static void -obj_elf_local (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - char *name; - int c; - symbolS *symbolP; - - do - { - name = input_line_pointer; - c = get_symbol_end (); - symbolP = symbol_find_or_make (name); - *input_line_pointer = c; - SKIP_WHITESPACE (); - S_CLEAR_EXTERNAL (symbolP); - symbol_get_obj (symbolP)->local = 1; - if (c == ',') - { - input_line_pointer++; - SKIP_WHITESPACE (); - if (*input_line_pointer == '\n') - c = '\n'; - } - } - while (c == ','); - demand_empty_rest_of_line (); -} - -static void -obj_elf_weak (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - char *name; - int c; - symbolS *symbolP; - - do - { - name = input_line_pointer; - c = get_symbol_end (); - symbolP = symbol_find_or_make (name); - *input_line_pointer = c; - SKIP_WHITESPACE (); - S_SET_WEAK (symbolP); - symbol_get_obj (symbolP)->local = 1; - if (c == ',') - { - input_line_pointer++; - SKIP_WHITESPACE (); - if (*input_line_pointer == '\n') - c = '\n'; - } - } - while (c == ','); - demand_empty_rest_of_line (); -} - -static void -obj_elf_visibility (visibility) - int visibility; -{ - char *name; - int c; - symbolS *symbolP; - asymbol *bfdsym; - elf_symbol_type *elfsym; - - do - { - name = input_line_pointer; - c = get_symbol_end (); - symbolP = symbol_find_or_make (name); - *input_line_pointer = c; - - SKIP_WHITESPACE (); - - bfdsym = symbol_get_bfdsym (symbolP); - elfsym = elf_symbol_from (bfd_asymbol_bfd (bfdsym), bfdsym); - - assert (elfsym); - - elfsym->internal_elf_sym.st_other = visibility; - - if (c == ',') - { - input_line_pointer ++; - - SKIP_WHITESPACE (); - - if (*input_line_pointer == '\n') - c = '\n'; - } - } - while (c == ','); - - demand_empty_rest_of_line (); -} - - -static segT previous_section; -static int previous_subsection; - -struct section_stack -{ - struct section_stack *next; - segT seg, prev_seg; - int subseg, prev_subseg; -}; - -static struct section_stack *section_stack; - - -/* Handle the .section pseudo-op. This code supports two different - syntaxes. - - The first is found on Solaris, and looks like - .section ".sec1",#alloc,#execinstr,#write - Here the names after '#' are the SHF_* flags to turn on for the - section. I'm not sure how it determines the SHT_* type (BFD - doesn't really give us control over the type, anyhow). - - The second format is found on UnixWare, and probably most SVR4 - machines, and looks like - .section .sec1,"a",@progbits - The quoted string may contain any combination of a, w, x, and - represents the SHF_* flags to turn on for the section. The string - beginning with '@' can be progbits or nobits. There should be - other possibilities, but I don't know what they are. In any case, - BFD doesn't really let us set the section type. */ - -/* Certain named sections have particular defined types, listed on p. - 4-19 of the ABI. */ -struct special_section -{ - const char *name; - int type; - int attributes; -}; - -static struct special_section const special_sections[] = -{ - { ".bss", SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, - { ".comment", SHT_PROGBITS, 0 }, - { ".data", SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, - { ".data1", SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, - { ".debug", SHT_PROGBITS, 0 }, - { ".fini", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, - { ".init", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, - { ".line", SHT_PROGBITS, 0 }, - { ".note", SHT_NOTE, 0 }, - { ".rodata", SHT_PROGBITS, SHF_ALLOC }, - { ".rodata1", SHT_PROGBITS, SHF_ALLOC }, - { ".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, - -#ifdef ELF_TC_SPECIAL_SECTIONS - ELF_TC_SPECIAL_SECTIONS -#endif - -#if 0 - /* The following section names are special, but they can not - reasonably appear in assembler code. Some of the attributes are - processor dependent. */ - { ".dynamic", SHT_DYNAMIC, SHF_ALLOC /* + SHF_WRITE */ }, - { ".dynstr", SHT_STRTAB, SHF_ALLOC }, - { ".dynsym", SHT_DYNSYM, SHF_ALLOC }, - { ".got", SHT_PROGBITS, 0 }, - { ".hash", SHT_HASH, SHF_ALLOC }, - { ".interp", SHT_PROGBITS, /* SHF_ALLOC */ }, - { ".plt", SHT_PROGBITS, 0 }, - { ".shstrtab",SHT_STRTAB, 0 }, - { ".strtab", SHT_STRTAB, /* SHF_ALLOC */ }, - { ".symtab", SHT_SYMTAB, /* SHF_ALLOC */ }, -#endif - - { NULL, 0, 0 } -}; - -void -obj_elf_change_section (name, type, attr, push) - char *name; - int type, attr, push; -{ - int new_sec; - segT sec; - -#ifdef md_flush_pending_output - md_flush_pending_output (); -#endif - - /* Switch to the section, creating it if necessary. */ - if (push) - { - struct section_stack *elt; - elt = xmalloc (sizeof (struct section_stack)); - elt->next = section_stack; - elt->seg = now_seg; - elt->prev_seg = previous_section; - elt->subseg = now_subseg; - elt->prev_subseg = previous_subsection; - section_stack = elt; - } - previous_section = now_seg; - previous_subsection = now_subseg; - - new_sec = bfd_get_section_by_name (stdoutput, name) == NULL; - sec = subseg_new (name, 0); - - if (new_sec) - { - flagword flags; - symbolS *secsym; - int i; - - /* See if this is one of the special sections. */ - for (i = 0; special_sections[i].name != NULL; i++) - if (strcmp (name, special_sections[i].name) == 0) - { - if (type == SHT_NULL) - type = special_sections[i].type; - else if (type != special_sections[i].type) - as_warn (_("Setting incorrect section type for %s"), name); - - if ((attr &~ special_sections[i].attributes) != 0) - { - /* As a GNU extension, we permit a .note section to be - allocatable. If the linker sees an allocateable .note - section, it will create a PT_NOTE segment in the output - file. */ - if (strcmp (name, ".note") != 0 - || attr != SHF_ALLOC) - as_warn (_("Setting incorrect section attributes for %s"), - name); - } - attr |= special_sections[i].attributes; - break; - } - - /* Convert ELF type and flags to BFD flags. */ - flags = (SEC_RELOC - | ((attr & SHF_WRITE) ? 0 : SEC_READONLY) - | ((attr & SHF_ALLOC) ? SEC_ALLOC : 0) - | (((attr & SHF_ALLOC) && type != SHT_NOBITS) ? SEC_LOAD : 0) - | ((attr & SHF_EXECINSTR) ? SEC_CODE : 0)); -#ifdef md_elf_section_flags - flags = md_elf_section_flags (flags, attr, type); -#endif - - /* Prevent SEC_HAS_CONTENTS from being inadvertently set. */ - if (type == SHT_NOBITS) - seg_info (sec)->bss = 1; - - bfd_set_section_flags (stdoutput, sec, flags); - - /* Add a symbol for this section to the symbol table. */ - secsym = symbol_find (name); - if (secsym != NULL) - symbol_set_bfdsym (secsym, sec->symbol); - else - symbol_table_insert (section_symbol (sec)); - } - -#ifdef md_elf_section_change_hook - md_elf_section_change_hook (); -#endif -} - -int -obj_elf_parse_section_letters (str, len) - char *str; - size_t len; -{ - int attr = 0; - - while (len > 0) - { - switch (*str) - { - case 'a': - attr |= SHF_ALLOC; - break; - case 'w': - attr |= SHF_WRITE; - break; - case 'x': - attr |= SHF_EXECINSTR; - break; - default: - { - char *bad_msg = _("Unrecognized .section attribute: want a,w,x"); -#ifdef md_elf_section_letter - int md_attr = md_elf_section_letter (*str, &bad_msg); - if (md_attr >= 0) - attr |= md_attr; - else -#endif - { - as_warn ("%s", bad_msg); - attr = -1; - } - } - break; - } - str++, len--; - } - - return attr; -} - -int -obj_elf_section_word (str, len) - char *str; - size_t len; -{ - if (len == 5 && strncmp (str, "write", 5) == 0) - return SHF_WRITE; - if (len == 5 && strncmp (str, "alloc", 5) == 0) - return SHF_ALLOC; - if (len == 9 && strncmp (str, "execinstr", 9) == 0) - return SHF_EXECINSTR; - -#ifdef md_elf_section_word - { - int md_attr = md_elf_section_word (str, len); - if (md_attr >= 0) - return md_attr; - } -#endif - - as_warn (_("Unrecognized section attribute")); - return 0; -} - -int -obj_elf_section_type (str, len) - char *str; - size_t len; -{ - if (len == 8 && strncmp (str, "progbits", 8) == 0) - return SHT_PROGBITS; - if (len == 6 && strncmp (str, "nobits", 6) == 0) - return SHT_NOBITS; - -#ifdef md_elf_section_type - { - int md_type = md_elf_section_type (str, len); - if (md_type >= 0) - return md_type; - } -#endif - - as_warn (_("Unrecognized section type")); - return 0; -} - -void -obj_elf_section (push) - int push; -{ - char *name, *beg, *end; - int type, attr, dummy; - -#ifndef TC_I370 - if (flag_mri) - { - char mri_type; - -#ifdef md_flush_pending_output - md_flush_pending_output (); -#endif - - previous_section = now_seg; - previous_subsection = now_subseg; - - s_mri_sect (&mri_type); - -#ifdef md_elf_section_change_hook - md_elf_section_change_hook (); -#endif - - return; - } -#endif /* ! defined (TC_I370) */ - - /* Get name of section. */ - SKIP_WHITESPACE (); - if (*input_line_pointer == '"') - { - name = demand_copy_C_string (&dummy); - if (name == NULL) - { - ignore_rest_of_line (); - return; - } - } - else - { - end = input_line_pointer; - while (0 == strchr ("\n\t,; ", *end)) - end++; - if (end == input_line_pointer) - { - as_warn (_("Missing section name")); - ignore_rest_of_line (); - return; - } - - name = xmalloc (end - input_line_pointer + 1); - memcpy (name, input_line_pointer, end - input_line_pointer); - name[end - input_line_pointer] = '\0'; - input_line_pointer = end; - } - SKIP_WHITESPACE (); - - type = SHT_NULL; - attr = 0; - - if (*input_line_pointer == ',') - { - /* Skip the comma. */ - ++input_line_pointer; - SKIP_WHITESPACE (); - - if (*input_line_pointer == '"') - { - beg = demand_copy_C_string (&dummy); - if (beg == NULL) - { - ignore_rest_of_line (); - return; - } - attr |= obj_elf_parse_section_letters (beg, strlen (beg)); - - SKIP_WHITESPACE (); - if (*input_line_pointer == ',') - { - char c; - ++input_line_pointer; - SKIP_WHITESPACE (); - c = *input_line_pointer; - if (c == '"') - { - beg = demand_copy_C_string (&dummy); - if (beg == NULL) - { - ignore_rest_of_line (); - return; - } - type = obj_elf_section_type (beg, strlen (beg)); - } - else if (c == '@' || c == '%') - { - beg = ++input_line_pointer; - c = get_symbol_end (); - *input_line_pointer = c; - type = obj_elf_section_type (beg, input_line_pointer - beg); - } - } - } - else - { - do - { - char c; - - SKIP_WHITESPACE (); - if (*input_line_pointer != '#') - { - as_warn (_("Bad .section directive - character following name is not '#'")); - ignore_rest_of_line (); - return; - } - beg = ++input_line_pointer; - c = get_symbol_end (); - *input_line_pointer = c; - - attr |= obj_elf_section_word (beg, input_line_pointer - beg); - - SKIP_WHITESPACE (); - } - while (*input_line_pointer++ == ','); - --input_line_pointer; - } - } - - demand_empty_rest_of_line (); - - obj_elf_change_section (name, type, attr, push); -} - -/* Change to the .data section. */ - -void -obj_elf_data (i) - int i; -{ -#ifdef md_flush_pending_output - md_flush_pending_output (); -#endif - - previous_section = now_seg; - previous_subsection = now_subseg; - s_data (i); - -#ifdef md_elf_section_change_hook - md_elf_section_change_hook (); -#endif -} - -/* Change to the .text section. */ - -void -obj_elf_text (i) - int i; -{ -#ifdef md_flush_pending_output - md_flush_pending_output (); -#endif - - previous_section = now_seg; - previous_subsection = now_subseg; - s_text (i); - -#ifdef md_elf_section_change_hook - md_elf_section_change_hook (); -#endif -} - -static void -obj_elf_subsection (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - register int temp; - -#ifdef md_flush_pending_output - md_flush_pending_output (); -#endif - - previous_section = now_seg; - previous_subsection = now_subseg; - - temp = get_absolute_expression (); - subseg_set (now_seg, (subsegT) temp); - demand_empty_rest_of_line (); - -#ifdef md_elf_section_change_hook - md_elf_section_change_hook (); -#endif -} - -/* This can be called from the processor backends if they change - sections. */ - -void -obj_elf_section_change_hook () -{ - previous_section = now_seg; - previous_subsection = now_subseg; -} - -void -obj_elf_previous (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - segT new_section; - int new_subsection; - - if (previous_section == 0) - { - as_bad (_(".previous without corresponding .section; ignored")); - return; - } - -#ifdef md_flush_pending_output - md_flush_pending_output (); -#endif - - new_section = previous_section; - new_subsection = previous_subsection; - previous_section = now_seg; - previous_subsection = now_subseg; - subseg_set (new_section, new_subsection); - -#ifdef md_elf_section_change_hook - md_elf_section_change_hook (); -#endif -} - -static void -obj_elf_popsection (xxx) - int xxx ATTRIBUTE_UNUSED; -{ - struct section_stack *top = section_stack; - - if (top == NULL) - { - as_bad (_(".popsection without corresponding .pushsection; ignored")); - return; - } - -#ifdef md_flush_pending_output - md_flush_pending_output (); -#endif - - section_stack = top->next; - previous_section = top->prev_seg; - previous_subsection = top->prev_subseg; - subseg_set (top->seg, top->subseg); - free (top); - -#ifdef md_elf_section_change_hook - md_elf_section_change_hook (); -#endif -} - -static void -obj_elf_line (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - /* Assume delimiter is part of expression. BSD4.2 as fails with - delightful bug, so we are not being incompatible here. */ - new_logical_line ((char *) NULL, (int) (get_absolute_expression ())); - demand_empty_rest_of_line (); -} - -/* This handles the .symver pseudo-op, which is used to specify a - symbol version. The syntax is ``.symver NAME,SYMVERNAME''. - SYMVERNAME may contain ELF_VER_CHR ('@') characters. This - pseudo-op causes the assembler to emit a symbol named SYMVERNAME - with the same value as the symbol NAME. */ - -static void -obj_elf_symver (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - char *name; - char c; - symbolS *sym; - - name = input_line_pointer; - c = get_symbol_end (); - - sym = symbol_find_or_make (name); - - *input_line_pointer = c; - - if (symbol_get_obj (sym)->versioned_name != NULL) - { - as_bad (_("multiple .symver directives for symbol `%s'"), - S_GET_NAME (sym)); - ignore_rest_of_line (); - return; - } - - SKIP_WHITESPACE (); - if (*input_line_pointer != ',') - { - as_bad (_("expected comma after name in .symver")); - ignore_rest_of_line (); - return; - } - - ++input_line_pointer; - name = input_line_pointer; - while (1) - { - c = get_symbol_end (); - if (c != ELF_VER_CHR) - break; - *input_line_pointer++ = c; - } - - symbol_get_obj (sym)->versioned_name = xstrdup (name); - - *input_line_pointer = c; - - if (strchr (symbol_get_obj (sym)->versioned_name, ELF_VER_CHR) == NULL) - { - as_bad (_("missing version name in `%s' for symbol `%s'"), - symbol_get_obj (sym)->versioned_name, S_GET_NAME (sym)); - ignore_rest_of_line (); - return; - } - - demand_empty_rest_of_line (); -} - -/* This handles the .vtable_inherit pseudo-op, which is used to indicate - to the linker the hierarchy in which a particular table resides. The - syntax is ".vtable_inherit CHILDNAME, PARENTNAME". */ - -static void -obj_elf_vtable_inherit (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - char *cname, *pname; - symbolS *csym, *psym; - char c, bad = 0; - - if (*input_line_pointer == '#') - ++input_line_pointer; - - cname = input_line_pointer; - c = get_symbol_end (); - csym = symbol_find (cname); - - /* GCFIXME: should check that we don't have two .vtable_inherits for - the same child symbol. Also, we can currently only do this if the - child symbol is already exists and is placed in a fragment. */ - - if (csym == NULL || symbol_get_frag (csym) == NULL) - { - as_bad ("expected `%s' to have already been set for .vtable_inherit", - cname); - bad = 1; - } - - *input_line_pointer = c; - - SKIP_WHITESPACE (); - if (*input_line_pointer != ',') - { - as_bad ("expected comma after name in .vtable_inherit"); - ignore_rest_of_line (); - return; - } - - ++input_line_pointer; - SKIP_WHITESPACE (); - - if (*input_line_pointer == '#') - ++input_line_pointer; - - if (input_line_pointer[0] == '0' - && (input_line_pointer[1] == '\0' - || isspace ((unsigned char) input_line_pointer[1]))) - { - psym = section_symbol (absolute_section); - ++input_line_pointer; - } - else - { - pname = input_line_pointer; - c = get_symbol_end (); - psym = symbol_find_or_make (pname); - *input_line_pointer = c; - } - - demand_empty_rest_of_line (); - - if (bad) - return; - - assert (symbol_get_value_expression (csym)->X_op == O_constant); - fix_new (symbol_get_frag (csym), - symbol_get_value_expression (csym)->X_add_number, 0, psym, 0, 0, - BFD_RELOC_VTABLE_INHERIT); -} - -/* This handles the .vtable_entry pseudo-op, which is used to indicate - to the linker that a vtable slot was used. The syntax is - ".vtable_entry tablename, offset". */ - -static void -obj_elf_vtable_entry (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - char *name; - symbolS *sym; - offsetT offset; - char c; - - if (*input_line_pointer == '#') - ++input_line_pointer; - - name = input_line_pointer; - c = get_symbol_end (); - sym = symbol_find_or_make (name); - *input_line_pointer = c; - - SKIP_WHITESPACE (); - if (*input_line_pointer != ',') - { - as_bad ("expected comma after name in .vtable_entry"); - ignore_rest_of_line (); - return; - } - - ++input_line_pointer; - if (*input_line_pointer == '#') - ++input_line_pointer; - - offset = get_absolute_expression (); - - fix_new (frag_now, frag_now_fix (), 0, sym, offset, 0, - BFD_RELOC_VTABLE_ENTRY); - - demand_empty_rest_of_line (); -} - -void -elf_obj_read_begin_hook () -{ -#ifdef NEED_ECOFF_DEBUG - if (ECOFF_DEBUGGING) - ecoff_read_begin_hook (); -#endif -} - -void -elf_obj_symbol_new_hook (symbolP) - symbolS *symbolP; -{ - struct elf_obj_sy *sy_obj; - - sy_obj = symbol_get_obj (symbolP); - sy_obj->size = NULL; - sy_obj->versioned_name = NULL; - -#ifdef NEED_ECOFF_DEBUG - if (ECOFF_DEBUGGING) - ecoff_symbol_new_hook (symbolP); -#endif -} - -void -obj_elf_version (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - char *name; - unsigned int c; - char ch; - char *p; - asection *seg = now_seg; - subsegT subseg = now_subseg; - Elf_Internal_Note i_note; - Elf_External_Note e_note; - asection *note_secp = (asection *) NULL; - int i, len; - - SKIP_WHITESPACE (); - if (*input_line_pointer == '\"') - { - ++input_line_pointer; /* -> 1st char of string. */ - name = input_line_pointer; - - while (is_a_char (c = next_char_of_string ())) - ; - c = *input_line_pointer; - *input_line_pointer = '\0'; - *(input_line_pointer - 1) = '\0'; - *input_line_pointer = c; - - /* create the .note section */ - - note_secp = subseg_new (".note", 0); - bfd_set_section_flags (stdoutput, - note_secp, - SEC_HAS_CONTENTS | SEC_READONLY); - - /* process the version string */ - - len = strlen (name); - - i_note.namesz = ((len + 1) + 3) & ~3; /* round this to word boundary */ - i_note.descsz = 0; /* no description */ - i_note.type = NT_VERSION; - p = frag_more (sizeof (e_note.namesz)); - md_number_to_chars (p, (valueT) i_note.namesz, 4); - p = frag_more (sizeof (e_note.descsz)); - md_number_to_chars (p, (valueT) i_note.descsz, 4); - p = frag_more (sizeof (e_note.type)); - md_number_to_chars (p, (valueT) i_note.type, 4); - - for (i = 0; i < len; i++) - { - ch = *(name + i); - { - FRAG_APPEND_1_CHAR (ch); - } - } - frag_align (2, 0, 0); - - subseg_set (seg, subseg); - } - else - { - as_bad (_("Expected quoted string")); - } - demand_empty_rest_of_line (); -} - -static void -obj_elf_size (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - char *name = input_line_pointer; - char c = get_symbol_end (); - char *p; - expressionS exp; - symbolS *sym; - - p = input_line_pointer; - *p = c; - SKIP_WHITESPACE (); - if (*input_line_pointer != ',') - { - *p = 0; - as_bad (_("expected comma after name `%s' in .size directive"), name); - *p = c; - ignore_rest_of_line (); - return; - } - input_line_pointer++; - expression (&exp); - if (exp.X_op == O_absent) - { - as_bad (_("missing expression in .size directive")); - exp.X_op = O_constant; - exp.X_add_number = 0; - } - *p = 0; - sym = symbol_find_or_make (name); - *p = c; - if (exp.X_op == O_constant) - S_SET_SIZE (sym, exp.X_add_number); - else - { - symbol_get_obj (sym)->size = - (expressionS *) xmalloc (sizeof (expressionS)); - *symbol_get_obj (sym)->size = exp; - } - demand_empty_rest_of_line (); -} - -/* Handle the ELF .type pseudo-op. This sets the type of a symbol. - There are four syntaxes: - - The first (used on Solaris) is - .type SYM,#function - The second (used on UnixWare) is - .type SYM,@function - The third (reportedly to be used on Irix 6.0) is - .type SYM STT_FUNC - The fourth (used on NetBSD/Arm and Linux/ARM) is - .type SYM,%function - */ - -static void -obj_elf_type (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - char *name; - char c; - int type; - const char *typename; - symbolS *sym; - - name = input_line_pointer; - c = get_symbol_end (); - sym = symbol_find_or_make (name); - *input_line_pointer = c; - - SKIP_WHITESPACE (); - if (*input_line_pointer == ',') - ++input_line_pointer; - - SKIP_WHITESPACE (); - if ( *input_line_pointer == '#' - || *input_line_pointer == '@' - || *input_line_pointer == '%') - ++input_line_pointer; - - typename = input_line_pointer; - c = get_symbol_end (); - - type = 0; - if (strcmp (typename, "function") == 0 - || strcmp (typename, "STT_FUNC") == 0) - type = BSF_FUNCTION; - else if (strcmp (typename, "object") == 0 - || strcmp (typename, "STT_OBJECT") == 0) - type = BSF_OBJECT; - else - as_bad (_("ignoring unrecognized symbol type \"%s\""), typename); - - *input_line_pointer = c; - - symbol_get_bfdsym (sym)->flags |= type; - - demand_empty_rest_of_line (); -} - -static void -obj_elf_ident (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - static segT comment_section; - segT old_section = now_seg; - int old_subsection = now_subseg; - -#ifdef md_flush_pending_output - md_flush_pending_output (); -#endif - - if (!comment_section) - { - char *p; - comment_section = subseg_new (".comment", 0); - bfd_set_section_flags (stdoutput, comment_section, - SEC_READONLY | SEC_HAS_CONTENTS); - p = frag_more (1); - *p = 0; - } - else - subseg_set (comment_section, 0); - stringer (1); - subseg_set (old_section, old_subsection); -} - -#ifdef INIT_STAB_SECTION - -/* The first entry in a .stabs section is special. */ - -void -obj_elf_init_stab_section (seg) - segT seg; -{ - char *file; - char *p; - char *stabstr_name; - unsigned int stroff; - - /* Force the section to align to a longword boundary. Without this, - UnixWare ar crashes. */ - bfd_set_section_alignment (stdoutput, seg, 2); - - /* Make space for this first symbol. */ - p = frag_more (12); - /* Zero it out. */ - memset (p, 0, 12); - as_where (&file, (unsigned int *) NULL); - stabstr_name = (char *) alloca (strlen (segment_name (seg)) + 4); - strcpy (stabstr_name, segment_name (seg)); - strcat (stabstr_name, "str"); - stroff = get_stab_string_offset (file, stabstr_name); - know (stroff == 1); - md_number_to_chars (p, stroff, 4); - seg_info (seg)->stabu.p = p; -} - -#endif - -/* Fill in the counts in the first entry in a .stabs section. */ - -static void -adjust_stab_sections (abfd, sec, xxx) - bfd *abfd; - asection *sec; - PTR xxx ATTRIBUTE_UNUSED; -{ - char *name; - asection *strsec; - char *p; - int strsz, nsyms; - - if (strncmp (".stab", sec->name, 5)) - return; - if (!strcmp ("str", sec->name + strlen (sec->name) - 3)) - return; - - name = (char *) alloca (strlen (sec->name) + 4); - strcpy (name, sec->name); - strcat (name, "str"); - strsec = bfd_get_section_by_name (abfd, name); - if (strsec) - strsz = bfd_section_size (abfd, strsec); - else - strsz = 0; - nsyms = bfd_section_size (abfd, sec) / 12 - 1; - - p = seg_info (sec)->stabu.p; - assert (p != 0); - - bfd_h_put_16 (abfd, (bfd_vma) nsyms, (bfd_byte *) p + 6); - bfd_h_put_32 (abfd, (bfd_vma) strsz, (bfd_byte *) p + 8); -} - -#ifdef NEED_ECOFF_DEBUG - -/* This function is called by the ECOFF code. It is supposed to - record the external symbol information so that the backend can - write it out correctly. The ELF backend doesn't actually handle - this at the moment, so we do it ourselves. We save the information - in the symbol. */ - -void -elf_ecoff_set_ext (sym, ext) - symbolS *sym; - struct ecoff_extr *ext; -{ - symbol_get_bfdsym (sym)->udata.p = (PTR) ext; -} - -/* This function is called by bfd_ecoff_debug_externals. It is - supposed to *EXT to the external symbol information, and return - whether the symbol should be used at all. */ - -static boolean -elf_get_extr (sym, ext) - asymbol *sym; - EXTR *ext; -{ - if (sym->udata.p == NULL) - return false; - *ext = *(EXTR *) sym->udata.p; - return true; -} - -/* This function is called by bfd_ecoff_debug_externals. It has - nothing to do for ELF. */ - -/*ARGSUSED*/ -static void -elf_set_index (sym, indx) - asymbol *sym ATTRIBUTE_UNUSED; - bfd_size_type indx ATTRIBUTE_UNUSED; -{ -} - -#endif /* NEED_ECOFF_DEBUG */ - -void -elf_frob_symbol (symp, puntp) - symbolS *symp; - int *puntp; -{ - struct elf_obj_sy *sy_obj; - -#ifdef NEED_ECOFF_DEBUG - if (ECOFF_DEBUGGING) - ecoff_frob_symbol (symp); -#endif - - sy_obj = symbol_get_obj (symp); - - if (sy_obj->size != NULL) - { - switch (sy_obj->size->X_op) - { - case O_subtract: - S_SET_SIZE (symp, - (S_GET_VALUE (sy_obj->size->X_add_symbol) - + sy_obj->size->X_add_number - - S_GET_VALUE (sy_obj->size->X_op_symbol))); - break; - case O_constant: - S_SET_SIZE (symp, - (S_GET_VALUE (sy_obj->size->X_add_symbol) - + sy_obj->size->X_add_number)); - break; - default: - as_bad (_(".size expression too complicated to fix up")); - break; - } - free (sy_obj->size); - sy_obj->size = NULL; - } - - if (sy_obj->versioned_name != NULL) - { - /* This symbol was given a new name with the .symver directive. - - If this is an external reference, just rename the symbol to - include the version string. This will make the relocs be - against the correct versioned symbol. - - If this is a definition, add an alias. FIXME: Using an alias - will permit the debugging information to refer to the right - symbol. However, it's not clear whether it is the best - approach. */ - - if (! S_IS_DEFINED (symp)) - { - char *p; - - /* Verify that the name isn't using the @@ syntax--this is - reserved for definitions of the default version to link - against. */ - p = strchr (sy_obj->versioned_name, ELF_VER_CHR); - know (p != NULL); - if (p[1] == ELF_VER_CHR) - { - as_bad (_("invalid attempt to declare external version name as default in symbol `%s'"), - sy_obj->versioned_name); - *puntp = true; - } - S_SET_NAME (symp, sy_obj->versioned_name); - } - else - { - symbolS *symp2; - - /* FIXME: Creating a new symbol here is risky. We're in the - final loop over the symbol table. We can get away with - it only because the symbol goes to the end of the list, - where the loop will still see it. It would probably be - better to do this in obj_frob_file_before_adjust. */ - - symp2 = symbol_find_or_make (sy_obj->versioned_name); - - /* Now we act as though we saw symp2 = sym. */ - - S_SET_SEGMENT (symp2, S_GET_SEGMENT (symp)); - - /* Subtracting out the frag address here is a hack because - we are in the middle of the final loop. */ - S_SET_VALUE (symp2, - (S_GET_VALUE (symp) - - symbol_get_frag (symp)->fr_address)); - - symbol_set_frag (symp2, symbol_get_frag (symp)); - - /* This will copy over the size information. */ - copy_symbol_attributes (symp2, symp); - - if (S_IS_WEAK (symp)) - S_SET_WEAK (symp2); - - if (S_IS_EXTERNAL (symp)) - S_SET_EXTERNAL (symp2); - } - } - - /* Double check weak symbols. */ - if (S_IS_WEAK (symp)) - { - if (S_IS_COMMON (symp)) - as_bad (_("Symbol `%s' can not be both weak and common"), - S_GET_NAME (symp)); - } - -#ifdef TC_MIPS - /* The Irix 5 and 6 assemblers set the type of any common symbol and - any undefined non-function symbol to STT_OBJECT. We try to be - compatible, since newer Irix 5 and 6 linkers care. However, we - only set undefined symbols to be STT_OBJECT if we are on Irix, - because that is the only time gcc will generate the necessary - .global directives to mark functions. */ - - if (S_IS_COMMON (symp)) - symbol_get_bfdsym (symp)->flags |= BSF_OBJECT; - - if (strstr (TARGET_OS, "irix") != NULL - && ! S_IS_DEFINED (symp) - && (symbol_get_bfdsym (symp)->flags & BSF_FUNCTION) == 0) - symbol_get_bfdsym (symp)->flags |= BSF_OBJECT; -#endif - -#if 0 /* TC_PPC */ - /* If TC_PPC is defined, we used to force the type of a symbol to be - BSF_OBJECT if it was otherwise unset. This was required by some - version of VxWorks. Thomas de Lellis <tdel@windriver.com> says - that this is no longer needed, so it is now commented out. */ - if ((symbol_get_bfdsym (symp)->flags - & (BSF_FUNCTION | BSF_FILE | BSF_SECTION_SYM)) == 0 - && S_IS_DEFINED (symp)) - symbol_get_bfdsym (symp)->flags |= BSF_OBJECT; -#endif -} - -void -elf_frob_file () -{ - bfd_map_over_sections (stdoutput, adjust_stab_sections, (PTR) 0); - -#ifdef elf_tc_final_processing - elf_tc_final_processing (); -#endif -} - -/* It is required that we let write_relocs have the opportunity to - optimize away fixups before output has begun, since it is possible - to eliminate all fixups for a section and thus we never should - have generated the relocation section. */ - -void -elf_frob_file_after_relocs () -{ -#ifdef NEED_ECOFF_DEBUG - if (ECOFF_DEBUGGING) - /* Generate the ECOFF debugging information. */ - { - const struct ecoff_debug_swap *debug_swap; - struct ecoff_debug_info debug; - char *buf; - asection *sec; - - debug_swap - = get_elf_backend_data (stdoutput)->elf_backend_ecoff_debug_swap; - know (debug_swap != (const struct ecoff_debug_swap *) NULL); - ecoff_build_debug (&debug.symbolic_header, &buf, debug_swap); - - /* Set up the pointers in debug. */ -#define SET(ptr, offset, type) \ - debug.ptr = (type) (buf + debug.symbolic_header.offset) - - SET (line, cbLineOffset, unsigned char *); - SET (external_dnr, cbDnOffset, PTR); - SET (external_pdr, cbPdOffset, PTR); - SET (external_sym, cbSymOffset, PTR); - SET (external_opt, cbOptOffset, PTR); - SET (external_aux, cbAuxOffset, union aux_ext *); - SET (ss, cbSsOffset, char *); - SET (external_fdr, cbFdOffset, PTR); - SET (external_rfd, cbRfdOffset, PTR); - /* ssext and external_ext are set up just below. */ - -#undef SET - - /* Set up the external symbols. */ - debug.ssext = debug.ssext_end = NULL; - debug.external_ext = debug.external_ext_end = NULL; - if (! bfd_ecoff_debug_externals (stdoutput, &debug, debug_swap, true, - elf_get_extr, elf_set_index)) - as_fatal (_("Failed to set up debugging information: %s"), - bfd_errmsg (bfd_get_error ())); - - sec = bfd_get_section_by_name (stdoutput, ".mdebug"); - assert (sec != NULL); - - know (stdoutput->output_has_begun == false); - - /* We set the size of the section, call bfd_set_section_contents - to force the ELF backend to allocate a file position, and then - write out the data. FIXME: Is this really the best way to do - this? */ - sec->_raw_size = bfd_ecoff_debug_size (stdoutput, &debug, debug_swap); - - /* Pass BUF to bfd_set_section_contents because this will - eventually become a call to fwrite, and ISO C prohibits - passing a NULL pointer to a stdio function even if the - pointer will not be used. */ - if (! bfd_set_section_contents (stdoutput, sec, (PTR) buf, - (file_ptr) 0, (bfd_size_type) 0)) - as_fatal (_("Can't start writing .mdebug section: %s"), - bfd_errmsg (bfd_get_error ())); - - know (stdoutput->output_has_begun == true); - know (sec->filepos != 0); - - if (! bfd_ecoff_write_debug (stdoutput, &debug, debug_swap, - sec->filepos)) - as_fatal (_("Could not write .mdebug section: %s"), - bfd_errmsg (bfd_get_error ())); - } -#endif /* NEED_ECOFF_DEBUG */ -} - -#ifdef SCO_ELF - -/* Heavily plagarized from obj_elf_version. The idea is to emit the - SCO specific identifier in the .notes section to satisfy the SCO - linker. - - This looks more complicated than it really is. As opposed to the - "obvious" solution, this should handle the cross dev cases - correctly. (i.e, hosting on a 64 bit big endian processor, but - generating SCO Elf code) Efficiency isn't a concern, as there - should be exactly one of these sections per object module. - - SCO OpenServer 5 identifies it's ELF modules with a standard ELF - .note section. - - int_32 namesz = 4 ; Name size - int_32 descsz = 12 ; Descriptive information - int_32 type = 1 ; - char name[4] = "SCO" ; Originator name ALWAYS SCO + NULL - int_32 version = (major ver # << 16) | version of tools ; - int_32 source = (tool_id << 16 ) | 1 ; - int_32 info = 0 ; These are set by the SCO tools, but we - don't know enough about the source - environment to set them. SCO ld currently - ignores them, and recommends we set them - to zero. */ - -#define SCO_MAJOR_VERSION 0x1 -#define SCO_MINOR_VERSION 0x1 - -void -sco_id () -{ - - char *name; - unsigned int c; - char ch; - char *p; - asection *seg = now_seg; - subsegT subseg = now_subseg; - Elf_Internal_Note i_note; - Elf_External_Note e_note; - asection *note_secp = (asection *) NULL; - int i, len; - - /* create the .note section */ - - note_secp = subseg_new (".note", 0); - bfd_set_section_flags (stdoutput, - note_secp, - SEC_HAS_CONTENTS | SEC_READONLY); - - /* process the version string */ - - i_note.namesz = 4; - i_note.descsz = 12; /* 12 descriptive bytes */ - i_note.type = NT_VERSION; /* Contains a version string */ - - p = frag_more (sizeof (i_note.namesz)); - md_number_to_chars (p, (valueT) i_note.namesz, 4); - - p = frag_more (sizeof (i_note.descsz)); - md_number_to_chars (p, (valueT) i_note.descsz, 4); - - p = frag_more (sizeof (i_note.type)); - md_number_to_chars (p, (valueT) i_note.type, 4); - - p = frag_more (4); - strcpy (p, "SCO"); - - /* Note: this is the version number of the ELF we're representing */ - p = frag_more (4); - md_number_to_chars (p, (SCO_MAJOR_VERSION << 16) | (SCO_MINOR_VERSION), 4); - - /* Here, we pick a magic number for ourselves (yes, I "registered" - it with SCO. The bottom bit shows that we are compat with the - SCO ABI. */ - p = frag_more (4); - md_number_to_chars (p, 0x4c520000 | 0x0001, 4); - - /* If we knew (or cared) what the source language options were, we'd - fill them in here. SCO has given us permission to ignore these - and just set them to zero. */ - p = frag_more (4); - md_number_to_chars (p, 0x0000, 4); - - frag_align (2, 0, 0); - - /* We probably can't restore the current segment, for there likely - isn't one yet... */ - if (seg && subseg) - subseg_set (seg, subseg); - -} - -#endif /* SCO_ELF */ - -const struct format_ops elf_format_ops = -{ - bfd_target_elf_flavour, - 0, /* dfl_leading_underscore */ - 1, /* emit_section_symbols */ - elf_frob_symbol, - elf_frob_file, - elf_frob_file_after_relocs, - elf_s_get_size, elf_s_set_size, - elf_s_get_align, elf_s_set_align, - elf_s_get_other, - 0, /* s_get_desc */ - elf_copy_symbol_attributes, -#ifdef NEED_ECOFF_DEBUG - ecoff_generate_asm_lineno, - ecoff_stab, -#else - 0, /* generate_asm_lineno */ - 0, /* process_stab */ -#endif - elf_sec_sym_ok_for_reloc, - elf_pop_insert, -#ifdef NEED_ECOFF_DEBUG - elf_ecoff_set_ext, -#else - 0, /* ecoff_set_ext */ -#endif - elf_obj_read_begin_hook, - elf_obj_symbol_new_hook, -}; diff --git a/contrib/binutils/gas/config/obj-elf.h b/contrib/binutils/gas/config/obj-elf.h deleted file mode 100644 index 722c5fdf94ded..0000000000000 --- a/contrib/binutils/gas/config/obj-elf.h +++ /dev/null @@ -1,235 +0,0 @@ -/* ELF object file format. - Copyright (C) 1992, 93, 94, 95, 96, 97, 98, 99, 2000 - 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 1, 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. */ - - -/* HP PA-RISC support was contributed by the Center for Software Science - at the University of Utah. */ - -#ifndef _OBJ_ELF_H -#define _OBJ_ELF_H - -#define OBJ_ELF 1 - -#ifndef OUTPUT_FLAVOR -#define OUTPUT_FLAVOR bfd_target_elf_flavour -#endif - -#include <bfd.h> - -#define BYTES_IN_WORD 4 /* for now */ -#include "bfd/elf-bfd.h" - -#include "targ-cpu.h" - -#ifdef TC_ALPHA -#define ECOFF_DEBUGGING alpha_flag_mdebug -extern int alpha_flag_mdebug; -#endif - -/* For now, always set ECOFF_DEBUGGING for a MIPS target. */ -#ifdef TC_MIPS -#ifdef MIPS_STABS_ELF -#define ECOFF_DEBUGGING 0 -#else -#define ECOFF_DEBUGGING 1 -#endif /* MIPS_STABS_ELF */ -#endif /* TC_MIPS */ - -#ifdef OBJ_MAYBE_ECOFF -#ifndef ECOFF_DEBUGGING -#define ECOFF_DEBUGGING 1 -#endif -#endif - -/* Additional information we keep for each symbol. */ -struct elf_obj_sy -{ - /* Whether the symbol has been marked as local. */ - int local; - - /* Use this to keep track of .size expressions that involve - differences that we can't compute yet. */ - expressionS *size; - - /* The name specified by the .symver directive. */ - char *versioned_name; - -#ifdef ECOFF_DEBUGGING - /* If we are generating ECOFF debugging information, we need some - additional fields for each symbol. */ - struct efdr *ecoff_file; - struct localsym *ecoff_symbol; - valueT ecoff_extern_size; -#endif -}; - -#define OBJ_SYMFIELD_TYPE struct elf_obj_sy - -#ifndef FALSE -#define FALSE 0 -#define TRUE !FALSE -#endif - -#define obj_begin() elf_begin () -extern void elf_begin PARAMS ((void)); - -/* should be conditional on address size! */ -#define elf_symbol(asymbol) ((elf_symbol_type *)(&(asymbol)->the_bfd)) - -#ifndef S_GET_SIZE -#define S_GET_SIZE(S) \ - (elf_symbol (symbol_get_bfdsym (S))->internal_elf_sym.st_size) -#endif -#ifndef S_SET_SIZE -#define S_SET_SIZE(S,V) \ - (elf_symbol (symbol_get_bfdsym (S))->internal_elf_sym.st_size = (V)) -#endif - -#ifndef S_GET_ALIGN -#define S_GET_ALIGN(S) \ - (elf_symbol (symbol_get_bfdsym (S))->internal_elf_sym.st_value) -#endif -#ifndef S_SET_ALIGN -#define S_SET_ALIGN(S,V) \ - (elf_symbol (symbol_get_bfdsym (S))->internal_elf_sym.st_value = (V)) -#endif - -int elf_s_get_other PARAMS ((symbolS *)); -#ifndef S_GET_OTHER -#define S_GET_OTHER(S) (elf_s_get_other (S)) -#endif -#ifndef S_SET_OTHER -#define S_SET_OTHER(S,V) \ - (elf_symbol (symbol_get_bfdsym (S))->internal_elf_sym.st_other = (V)) -#endif - -extern asection *gdb_section; - -#ifndef obj_frob_file -#define obj_frob_file elf_frob_file -#endif -extern void elf_frob_file PARAMS ((void)); - -#ifndef obj_frob_file_after_relocs -#define obj_frob_file_after_relocs elf_frob_file_after_relocs -#endif -extern void elf_frob_file_after_relocs PARAMS ((void)); - -#define obj_app_file elf_file_symbol -extern void elf_file_symbol PARAMS ((char *)); - -extern void obj_elf_section_change_hook PARAMS ((void)); - -extern void obj_elf_section PARAMS ((int)); -extern void obj_elf_previous PARAMS ((int)); -extern void obj_elf_version PARAMS ((int)); -extern void obj_elf_common PARAMS ((int)); -extern void obj_elf_data PARAMS ((int)); -extern void obj_elf_text PARAMS ((int)); - -/* BFD wants to write the udata field, which is a no-no for the - globally defined sections. */ -#ifndef obj_sec_sym_ok_for_reloc -#define obj_sec_sym_ok_for_reloc(SEC) ((SEC)->owner != 0) -#endif - -void elf_obj_read_begin_hook PARAMS ((void)); -#ifndef obj_read_begin_hook -#define obj_read_begin_hook elf_obj_read_begin_hook -#endif - -void elf_obj_symbol_new_hook PARAMS ((symbolS *)); -#ifndef obj_symbol_new_hook -#define obj_symbol_new_hook elf_obj_symbol_new_hook -#endif - -/* When setting one symbol equal to another, by default we probably - want them to have the same "size", whatever it means in the current - context. */ -#ifndef OBJ_COPY_SYMBOL_ATTRIBUTES -#define OBJ_COPY_SYMBOL_ATTRIBUTES(DEST,SRC) \ -do \ - { \ - struct elf_obj_sy *srcelf = symbol_get_obj (SRC); \ - struct elf_obj_sy *destelf = symbol_get_obj (DEST); \ - if (srcelf->size) \ - { \ - if (destelf->size == NULL) \ - destelf->size = \ - (expressionS *) xmalloc (sizeof (expressionS)); \ - *destelf->size = *srcelf->size; \ - } \ - else \ - { \ - if (destelf->size != NULL) \ - free (destelf->size); \ - destelf->size = NULL; \ - } \ - S_SET_SIZE ((DEST), S_GET_SIZE (SRC)); \ - S_SET_OTHER ((DEST), S_GET_OTHER (SRC)); \ - } \ -while (0) -#endif - -/* Stabs go in a separate section. */ -#define SEPARATE_STAB_SECTIONS 1 - -/* We need 12 bytes at the start of the section to hold some initial - information. */ -extern void obj_elf_init_stab_section PARAMS ((segT)); -#define INIT_STAB_SECTION(seg) obj_elf_init_stab_section (seg) - -#ifdef ECOFF_DEBUGGING -/* We smuggle stabs in ECOFF rather than using a separate section. - The Irix linker can not handle a separate stabs section. */ - -#undef SEPARATE_STAB_SECTIONS -#define SEPARATE_STAB_SECTIONS (!ECOFF_DEBUGGING) - -#undef INIT_STAB_SECTION -#define INIT_STAB_SECTION(seg) \ - ((void)(ECOFF_DEBUGGING ? 0 : (obj_elf_init_stab_section (seg), 0))) - -#undef OBJ_PROCESS_STAB -#define OBJ_PROCESS_STAB(seg, what, string, type, other, desc) \ - if (ECOFF_DEBUGGING) \ - ecoff_stab ((seg), (what), (string), (type), (other), (desc)) -#endif /* ECOFF_DEBUGGING */ - -extern void elf_frob_symbol PARAMS ((symbolS *, int *)); -#ifndef obj_frob_symbol -#define obj_frob_symbol(symp, punt) elf_frob_symbol (symp, &punt) -#endif - -extern void elf_pop_insert PARAMS ((void)); -#ifndef obj_pop_insert -#define obj_pop_insert() elf_pop_insert() -#endif - -#ifndef OBJ_MAYBE_ELF -#define obj_ecoff_set_ext elf_ecoff_set_ext -#ifdef ANSI_PROTOTYPES -struct ecoff_extr; -#endif -extern void elf_ecoff_set_ext PARAMS ((symbolS *, struct ecoff_extr *)); -#endif - -#endif /* _OBJ_ELF_H */ diff --git a/contrib/binutils/gas/config/obj-generic.c b/contrib/binutils/gas/config/obj-generic.c deleted file mode 100644 index 69fc3d1dbf963..0000000000000 --- a/contrib/binutils/gas/config/obj-generic.c +++ /dev/null @@ -1,41 +0,0 @@ -/* This file is obj-generic.c and is intended to be a template for - object format specific source files. - - Copyright (C) 1987-1992 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. */ - -/* Chars that can be used to separate mant from exp in floating point nums */ -char EXP_CHARS[] = "eE"; - -/* Chars that mean this number is a floating point constant */ -/* As in 0f12.456 */ -/* or 0d1.2345e12 */ -char FLT_CHARS[] = "rRsSfFdDxXpP"; - -/* These chars start a comment anywhere in a source file (except inside - another comment */ -const char comment_chars[] = "#"; - -/* - * Local Variables: - * comment-column: 0 - * fill-column: 131 - * End: - */ - -/* end of obj-generic.c */ diff --git a/contrib/binutils/gas/config/obj-generic.h b/contrib/binutils/gas/config/obj-generic.h deleted file mode 100644 index dc18e4397034d..0000000000000 --- a/contrib/binutils/gas/config/obj-generic.h +++ /dev/null @@ -1,80 +0,0 @@ -/* This file is obj-generic.h - Copyright (C) 1987-1992 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. */ - -/* - * This file is obj-generic.h and is intended to be a template for - * object format specific header files. - */ - -/* define an obj specific macro off which target cpu back ends may key. */ -#define OBJ_GENERIC 1 - -/* include whatever target cpu is appropriate. */ -#include "targ-cpu.h" - -/* - * SYMBOLS - */ - -/* - * If your object format needs to reorder symbols, define this. When - * defined, symbols are kept on a doubly linked list and functions are - * made available for push, insert, append, and delete. If not defined, - * symbols are kept on a singly linked list, only the append and clear - * facilities are available, and they are macros. - */ - -/* #define SYMBOLS_NEED_PACKPOINTERS */ - -/* */ -typedef struct - { - void *nothing; - } - -obj_symbol_type; /* should be the format's symbol structure */ - -typedef void *object_headers; - -/* symbols have names */ -#define S_GET_NAME(s) ("foo") /* get the name of a symbolP */ -#define S_SET_NAME(s,v) ; -/* symbols have segments */ -#define S_GET_SEGMENT(s) (SEG_UNKNOWN) -#define S_SET_SEGMENT(s,v) ; -/* symbols may be external */ -#define S_IS_EXTERNAL(s) (0) -#define S_SET_EXTERNAL(s) ; - -/* symbols may or may not be defined */ -#define S_IS_DEFINED(s) (0) - - -#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE (0) /* your magic number */ - -#define OBJ_EMIT_LINENO(a,b,c) /* must be *something*. This no-op's it out. */ - -/* - * Local Variables: - * comment-column: 0 - * fill-column: 131 - * End: - */ - -/* end of obj-generic.h */ diff --git a/contrib/binutils/gas/config/obj-ieee.c b/contrib/binutils/gas/config/obj-ieee.c deleted file mode 100644 index 30a0798e29520..0000000000000 --- a/contrib/binutils/gas/config/obj-ieee.c +++ /dev/null @@ -1,627 +0,0 @@ -/* obj-format for ieee-695 records. - Copyright (C) 1991, 92, 93, 94, 95, 1997, 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. */ - - -/* - created by - - steve chamberlain steve@cygnus.com - */ - -/* - this will hopefully become the port through which bfd and gas talk, - for the moment, only ieee is known to work well. - */ - -#include "bfd.h" -#include "as.h" -#include "subsegs.h" -#include "output-file.h" -#include "frags.h" - -bfd *abfd; - -/* How many addresses does the .align take? */ -static relax_addressT -relax_align (address, alignment) - register relax_addressT address; /* Address now. */ - register long alignment; /* Alignment (binary). */ -{ - relax_addressT mask; - relax_addressT new_address; - - mask = ~((~0) << alignment); - new_address = (address + mask) & (~mask); - return (new_address - address); -} /* relax_align() */ - -/* calculate the size of the frag chain and create a bfd section - to contain all of it */ -static void -DEFUN (size_section, (abfd, idx), - bfd * abfd AND - unsigned int idx) -{ - asection *sec; - unsigned int size = 0; - fragS *frag = segment_info[idx].frag_root; - while (frag) - { - if (frag->fr_address != size) - { - printf (_("Out of step\n")); - size = frag->fr_address; - } - size += frag->fr_fix; - switch (frag->fr_type) - { - case rs_fill: - case rs_org: - size += frag->fr_offset * frag->fr_var; - break; - case rs_align: - case rs_align_code: - { - addressT off; - - off = relax_align (size, frag->fr_offset); - if (frag->fr_subtype != 0 && off > frag->fr_subtype) - off = 0; - size += off; - } - } - frag = frag->fr_next; - } - if (size) - { - char *name = segment_info[idx].name; - if (name == (char *) NULL) - { - name = ".data"; - } - segment_info[idx].user_stuff = (char *) (sec = bfd_make_section (abfd, name)); - /* Make it output through itself */ - sec->output_section = sec; - sec->flags |= SEC_HAS_CONTENTS; - bfd_set_section_size (abfd, sec, size); - } -} - -/* run through a frag chain and write out the data to go with it */ -static void -DEFUN (fill_section, (abfd, idx), - bfd * abfd AND - unsigned int idx) -{ - asection *sec = segment_info[idx].user_stuff; - if (sec) - { - fragS *frag = segment_info[idx].frag_root; - unsigned int offset = 0; - while (frag) - { - unsigned int fill_size; - unsigned int count; - switch (frag->fr_type) - { - case rs_fill: - case rs_align: - case rs_org: - if (frag->fr_fix) - { - bfd_set_section_contents (abfd, - sec, - frag->fr_literal, - frag->fr_address, - frag->fr_fix); - } - offset += frag->fr_fix; - fill_size = frag->fr_var; - if (fill_size) - { - unsigned int off = frag->fr_fix; - for (count = frag->fr_offset; count; count--) - { - bfd_set_section_contents (abfd, sec, - frag->fr_literal + - frag->fr_fix, - frag->fr_address + off, - fill_size); - off += fill_size; - } - } - break; - default: - abort (); - } - frag = frag->fr_next; - } - } -} - -/* Count the relocations in a chain */ - -static unsigned int -DEFUN (count_entries_in_chain, (idx), - unsigned int idx) -{ - unsigned int nrelocs; - fixS *fixup_ptr; - - /* Count the relocations */ - fixup_ptr = segment_info[idx].fix_root; - nrelocs = 0; - while (fixup_ptr != (fixS *) NULL) - { - fixup_ptr = fixup_ptr->fx_next; - nrelocs++; - } - return nrelocs; -} - -/* output all the relocations for a section */ -void -DEFUN (do_relocs_for, (idx), - unsigned int idx) -{ - unsigned int nrelocs; - arelent **reloc_ptr_vector; - arelent *reloc_vector; - asymbol **ptrs; - asection *section = (asection *) (segment_info[idx].user_stuff); - unsigned int i; - fixS *from; - if (section) - { - nrelocs = count_entries_in_chain (idx); - - reloc_ptr_vector = (arelent **) malloc ((nrelocs + 1) * sizeof (arelent *)); - reloc_vector = (arelent *) malloc (nrelocs * sizeof (arelent)); - ptrs = (asymbol **) malloc (nrelocs * sizeof (asymbol *)); - from = segment_info[idx].fix_root; - for (i = 0; i < nrelocs; i++) - { - arelent *to = reloc_vector + i; - asymbol *s; - reloc_ptr_vector[i] = to; - to->howto = (reloc_howto_type *) (from->fx_r_type); - -#if 0 /* We can't represent complicated things in a reloc yet */ - if (from->fx_addsy == 0 || from->fx_subsy != 0) abort(); -#endif - - s = &(from->fx_addsy->sy_symbol.sy); - to->address = ((char *) (from->fx_frag->fr_address + - from->fx_where)) - - ((char *) (&(from->fx_frag->fr_literal))); - to->addend = from->fx_offset; - /* If we know the symbol which we want to relocate to, turn - this reloaction into a section relative. - - If this relocation is pcrelative, and we know the - destination, we still want to keep the relocation - since - the linker might relax some of the bytes, but it stops - being pc relative and turns into an absolute relocation. */ - if (s) - { - if ((s->flags & BSF_UNDEFINED) == 0) - { - to->section = s->section; - - /* We can refer directly to the value field here, - rather than using S_GET_VALUE, because this is - only called after do_symbols, which sets up the - value field. */ - to->addend += s->value; - - to->sym_ptr_ptr = 0; - if (to->howto->pcrel_offset) - { - /* This is a pcrel relocation, the addend should be adjusted */ - to->addend -= to->address + 1; - } - } - else - { - to->section = 0; - *ptrs = &(from->fx_addsy->sy_symbol.sy); - to->sym_ptr_ptr = ptrs; - - if (to->howto->pcrel_offset) - { - /* This is a pcrel relocation, the addend should be adjusted */ - to->addend -= to->address - 1; - } - } - - } - else - { - to->section = 0; - } - - ptrs++; - from = from->fx_next; - } - - /* attatch to the section */ - section->orelocation = reloc_ptr_vector; - section->reloc_count = nrelocs; - section->flags |= SEC_LOAD; - } -} - -/* do the symbols.. */ -static void -DEFUN (do_symbols, (abfd), - bfd * abfd) -{ - extern symbolS *symbol_rootP; - symbolS *ptr; - asymbol **symbol_ptr_vec; - asymbol *symbol_vec; - unsigned int count = 0; - unsigned int index; - - - for (ptr = symbol_rootP; - ptr != (symbolS *) NULL; - ptr = ptr->sy_next) - { - if (SEG_NORMAL (ptr->sy_symbol.seg)) - { - ptr->sy_symbol.sy.section = - (asection *) (segment_info[ptr->sy_symbol.seg].user_stuff); - S_SET_VALUE (ptr, S_GET_VALUE (ptr) + ptr->sy_frag->fr_address); - if (ptr->sy_symbol.sy.flags == 0) - { - ptr->sy_symbol.sy.flags = BSF_LOCAL; - } - } - else - { - switch (ptr->sy_symbol.seg) - { - case SEG_ABSOLUTE: - ptr->sy_symbol.sy.flags |= BSF_ABSOLUTE; - ptr->sy_symbol.sy.section = 0; - break; - case SEG_UNKNOWN: - ptr->sy_symbol.sy.flags = BSF_UNDEFINED; - ptr->sy_symbol.sy.section = 0; - break; - default: - abort (); - } - } - ptr->sy_symbol.sy.value = S_GET_VALUE (ptr); - count++; - } - symbol_ptr_vec = (asymbol **) malloc ((count + 1) * sizeof (asymbol *)); - - index = 0; - for (ptr = symbol_rootP; - ptr != (symbolS *) NULL; - ptr = ptr->sy_next) - { - symbol_ptr_vec[index] = &(ptr->sy_symbol.sy); - index++; - } - symbol_ptr_vec[index] = 0; - abfd->outsymbols = symbol_ptr_vec; - abfd->symcount = count; -} - -/* The generic as->bfd converter. Other backends may have special case - code */ - -void -DEFUN_VOID (bfd_as_write_hook) -{ - int i; - - for (i = SEG_E0; i < SEG_UNKNOWN; i++) - { - size_section (abfd, i); - } - - - for (i = SEG_E0; i < SEG_UNKNOWN; i++) - fill_section (abfd, i); - - do_symbols (abfd); - - for (i = SEG_E0; i < SEG_UNKNOWN; i++) - do_relocs_for (i); - -} - -S_SET_SEGMENT (x, y) - symbolS *x; - int y; -{ - x->sy_symbol.seg = y; -} - -S_IS_DEFINED (x) - symbolS *x; -{ - if (SEG_NORMAL (x->sy_symbol.seg)) - { - return 1; - } - switch (x->sy_symbol.seg) - { - case SEG_UNKNOWN: - return 0; - default: - abort (); - } -} - -S_IS_EXTERNAL (x) -{ - abort (); -} - -S_GET_DESC (x) -{ - abort (); -} - -S_GET_SEGMENT (x) - symbolS *x; -{ - return x->sy_symbol.seg; -} - -S_SET_EXTERNAL (x) - symbolS *x; -{ - x->sy_symbol.sy.flags |= BSF_GLOBAL | BSF_EXPORT; -} - -S_SET_NAME (x, y) - symbolS *x; - char *y; -{ - x->sy_symbol.sy.name = y; -} - -S_GET_OTHER (x) -{ - abort (); -} - -S_IS_DEBUG (x) -{ - abort (); -} - -#ifndef segment_name -char * -segment_name () -{ - abort (); -} -#endif - -void -obj_read_begin_hook () -{ -} - -static void -obj_ieee_section (ignore) - int ignore; -{ - extern char *input_line_pointer; - extern char is_end_of_line[]; - char *p = input_line_pointer; - char *s = p; - int i; - /* Look up the name, if it doesn't exist, make it */ - while (*p && *p != ' ' && *p != ',' && !is_end_of_line[*p]) - { - p++; - } - for (i = SEG_E0; i < SEG_UNKNOWN; i++) - { - if (segment_info[i].hadone) - { - if (strncmp (segment_info[i].name, s, p - s) == 0) - { - goto ok; - - } - } - else - break; - } - if (i == SEG_UNKNOWN) - { - as_bad (_("too many sections")); - return; - } - - segment_info[i].hadone = 1; - segment_info[i].name = malloc (p - s + 1); - memcpy (segment_info[i].name, s, p - s); - segment_info[i].name[p - s] = 0; -ok: - subseg_set (i, 0); - while (!is_end_of_line[*p]) - p++; - input_line_pointer = p; - -} - - -void cons (); -void s_ignore (); - - -void s_globl (); -const pseudo_typeS obj_pseudo_table[] = -{ - {"section", obj_ieee_section, 0}, - {"data.b", cons, 1}, - {"data.w", cons, 2}, - {"data.l", cons, 4}, - {"export", s_globl, 0}, - {"option", s_ignore, 0}, - {"end", s_ignore, 0}, - {"import", s_ignore, 0}, - {"sdata", stringer, 0}, - 0, - -}; - - - -void -obj_symbol_new_hook (symbolP) - symbolS *symbolP; -{ - symbolP->sy_symbol.sy.the_bfd = abfd; -} - - - - - -#if 1 -extern void -DEFUN_VOID (write_object_file) -{ - int i; - struct frchain *frchain_ptr; - struct frag *frag_ptr; - - abfd = bfd_openw (out_file_name, "ieee"); - - if (abfd == 0) - { - as_perror (_("FATAL: Can't create %s"), out_file_name); - exit (EXIT_FAILURE); - } - bfd_set_format (abfd, bfd_object); - bfd_set_arch_mach (abfd, bfd_arch_h8300, 0); - subseg_set (1, 0); - subseg_set (2, 0); - subseg_set (3, 0); - for (frchain_ptr = frchain_root; - frchain_ptr != (struct frchain *) NULL; - frchain_ptr = frchain_ptr->frch_next) - { - /* Run through all the sub-segments and align them up. Also close any - open frags. We tack a .fill onto the end of the frag chain so - that any .align's size can be worked by looking at the next - frag. */ - - subseg_set (frchain_ptr->frch_seg, frchain_ptr->frch_subseg); -#ifndef SUB_SEGMENT_ALIGN -#define SUB_SEGMENT_ALIGN(SEG) 2 -#endif - frag_align (SUB_SEGMENT_ALIGN (now_seg), 0, 0); - frag_wane (frag_now); - frag_now->fr_fix = 0; - know (frag_now->fr_next == NULL); - } - - /* Now build one big frag chain for each segment, linked through - fr_next. */ - for (i = SEG_E0; i < SEG_UNKNOWN; i++) - { - - fragS **prev_frag_ptr_ptr; - struct frchain *next_frchain_ptr; - - /* struct frag **head_ptr = segment_info[i].frag_root;*/ - - segment_info[i].frag_root = segment_info[i].frchainP->frch_root; -#if 0 - /* Im not sure what this is for */ - for (frchain_ptr = segment_info[i].frchainP->frch_root; - frchain_ptr != (struct frchain *) NULL; - frchain_ptr = frchain_ptr->frch_next) - { - *head_ptr = frchain_ptr; - head_ptr = &frchain_ptr->next; - } - - -#endif - } - - for (i = SEG_E0; i < SEG_UNKNOWN; i++) - { - relax_segment (segment_info[i].frag_root, i); - } - - /* Now the addresses of the frags are correct within the segment */ - - bfd_as_write_hook (); - bfd_close (abfd); -} - -#endif - -H_SET_TEXT_SIZE (a, b) -{ - abort (); -} - -H_GET_TEXT_SIZE () -{ - abort (); -} - -H_SET_BSS_SIZE () -{ - abort (); -} - -H_SET_STRING_SIZE () -{ - abort (); -} - -H_SET_RELOCATION_SIZE () -{ - abort (); -} - -H_SET_MAGIC_NUMBER () -{ - abort (); -} - -H_GET_FILE_SIZE () -{ - abort (); -} - -H_GET_TEXT_RELOCATION_SIZE () -{ - abort (); -} - -/* end of obj-ieee.c */ diff --git a/contrib/binutils/gas/config/obj-ieee.h b/contrib/binutils/gas/config/obj-ieee.h deleted file mode 100644 index 4a0f126ebe433..0000000000000 --- a/contrib/binutils/gas/config/obj-ieee.h +++ /dev/null @@ -1,50 +0,0 @@ -/* This file is obj-ieee.h - - Copyright (C) 1987-1992 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. */ - -#define BFD 1 - -#include <bfd.h> - -typedef struct -{ - asymbol sy; - int seg; -} - -obj_symbol_type; - -#define S_GET_NAME(s) (((s)->sy_symbol.sy.name)) - -typedef struct - { - int x; - } - -object_headers; - -#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE 1 - - -int lineno_rootP; - - -#define IEEE_STYLE - -/* end of obj-ieee.h */ diff --git a/contrib/binutils/gas/config/obj-multi.c b/contrib/binutils/gas/config/obj-multi.c deleted file mode 100644 index d115093aff38c..0000000000000 --- a/contrib/binutils/gas/config/obj-multi.c +++ /dev/null @@ -1,4 +0,0 @@ -/* foo */ - -#include "as.h" - diff --git a/contrib/binutils/gas/config/obj-multi.h b/contrib/binutils/gas/config/obj-multi.h deleted file mode 100644 index 42b7eb33e3c4e..0000000000000 --- a/contrib/binutils/gas/config/obj-multi.h +++ /dev/null @@ -1,104 +0,0 @@ -/* Multiple object format emulation. - Copyright (C) 1995, 96, 97, 99, 2000 - 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 1, 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 _OBJ_MULTI_H -#define _OBJ_MULTI_H - -#ifdef OBJ_HEADER -#include OBJ_HEADER -#else - -#include "emul.h" -#include "targ-cpu.h" - -#define OUTPUT_FLAVOR \ - (this_format->flavor) - -#define obj_frob_symbol(S,P) \ - (*this_format->frob_symbol) (S, &(P)) - -#define obj_frob_file() \ - (this_format->frob_file \ - ? (*this_format->frob_file) () \ - : (void) 0) - -#define obj_frob_file_after_relocs() \ - (this_format->frob_file_after_relocs \ - ? (*this_format->frob_file_after_relocs) () \ - : (void) 0) - -#define obj_ecoff_set_ext \ - (*this_format->ecoff_set_ext) - -#define obj_pop_insert \ - (*this_format->pop_insert) - -#define obj_read_begin_hook() \ - (this_format->read_begin_hook \ - ? (*this_format->read_begin_hook) () \ - : (void) 0) - -#define obj_symbol_new_hook(S) \ - (this_format->symbol_new_hook \ - ? (*this_format->symbol_new_hook) (S) \ - : (void) 0) - -#define obj_sec_sym_ok_for_reloc(A) \ - (this_format->sec_sym_ok_for_reloc \ - ? (*this_format->sec_sym_ok_for_reloc) (A) \ - : 0) - -#define S_GET_SIZE \ - (*this_format->s_get_size) - -#define S_SET_SIZE \ - (*this_format->s_set_size) - -#define S_GET_ALIGN \ - (*this_format->s_get_align) - -#define S_SET_ALIGN \ - (*this_format->s_set_align) - -#define S_GET_OTHER \ - (*this_format->s_get_other) - -#define S_GET_DESC \ - (*this_format->s_get_desc) - -#define OBJ_COPY_SYMBOL_ATTRIBUTES(d,s) \ - (this_format->copy_symbol_attributes \ - ? (*this_format->copy_symbol_attributes) (d, s) \ - : (void) 0) - -#define OBJ_PROCESS_STAB(SEG,W,S,T,O,D) \ - (this_format->process_stab \ - ? (*this_format->process_stab) (SEG,W,S,T,O,D) \ - : (void) 0) - -#ifdef OBJ_MAYBE_ELF -/* We need OBJ_SYMFIELD_TYPE so that symbol_get_obj is defined in symbol.c - We also need various STAB defines for stab.c */ -#include "obj-elf.h" -#endif - -#endif /* !OBJ_HEADER */ -#endif /* _OBJ_MULTI_H */ diff --git a/contrib/binutils/gas/config/sco5.mt b/contrib/binutils/gas/config/sco5.mt deleted file mode 100644 index 8879320c4e1e5..0000000000000 --- a/contrib/binutils/gas/config/sco5.mt +++ /dev/null @@ -1 +0,0 @@ -TDEFINES=-DSCO_ELF diff --git a/contrib/binutils/gas/config/tc-alpha.c b/contrib/binutils/gas/config/tc-alpha.c deleted file mode 100644 index 61dba4b8a4f50..0000000000000 --- a/contrib/binutils/gas/config/tc-alpha.c +++ /dev/null @@ -1,5655 +0,0 @@ -/* tc-alpha.c - Processor-specific code for the DEC Alpha AXP CPU. - Copyright (C) 1989, 93-98, 1999 Free Software Foundation, Inc. - Contributed by Carnegie Mellon University, 1993. - Written by Alessandro Forin, based on earlier gas-1.38 target CPU files. - Modified by Ken Raeburn for gas-2.x and ECOFF support. - Modified by Richard Henderson for ELF support. - Modified by Klaus K"ampf for EVAX (OpenVMS/Alpha) support. - - 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. */ - -/* - * Mach Operating System - * Copyright (c) 1993 Carnegie Mellon University - * All Rights Reserved. - * - * Permission to use, copy, modify and distribute this software and its - * documentation is hereby granted, provided that both the copyright - * notice and this permission notice appear in all copies of the - * software, derivative works or modified versions, and any portions - * thereof, and that both notices appear in supporting documentation. - * - * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS - * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR - * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * - * Carnegie Mellon requests users of this software to return to - * - * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU - * School of Computer Science - * Carnegie Mellon University - * Pittsburgh PA 15213-3890 - * - * any improvements or extensions that they make and grant Carnegie the - * rights to redistribute these changes. - */ - -#include "as.h" -#include "subsegs.h" -#include "struc-symbol.h" -#include "ecoff.h" - -#include "opcode/alpha.h" - -#ifdef OBJ_ELF -#include "elf/alpha.h" -#endif - -#include <ctype.h> - - -/* Local types */ - -#define TOKENIZE_ERROR -1 -#define TOKENIZE_ERROR_REPORT -2 - -#define MAX_INSN_FIXUPS 2 -#define MAX_INSN_ARGS 5 - -struct alpha_fixup -{ - expressionS exp; - bfd_reloc_code_real_type reloc; -}; - -struct alpha_insn -{ - unsigned insn; - int nfixups; - struct alpha_fixup fixups[MAX_INSN_FIXUPS]; - unsigned sequence[MAX_INSN_FIXUPS]; -}; - -enum alpha_macro_arg -{ - MACRO_EOA = 1, - MACRO_IR, - MACRO_PIR, - MACRO_OPIR, - MACRO_CPIR, - MACRO_FPR, - MACRO_EXP, - MACRO_LITERAL, - MACRO_BASE, - MACRO_BYTOFF, - MACRO_JSR -}; - -struct alpha_macro -{ - const char *name; - void (*emit) PARAMS ((const expressionS *, int, const PTR)); - const PTR arg; - enum alpha_macro_arg argsets[16]; -}; - -/* Extra expression types. */ - -#define O_pregister O_md1 /* O_register, in parentheses */ -#define O_cpregister O_md2 /* + a leading comma */ - -#ifdef RELOC_OP_P -/* Note, the alpha_reloc_op table below depends on the ordering - of O_literal .. O_gprelow. */ -#define O_literal O_md3 /* !literal relocation */ -#define O_lituse_base O_md4 /* !lituse_base relocation */ -#define O_lituse_bytoff O_md5 /* !lituse_bytoff relocation */ -#define O_lituse_jsr O_md6 /* !lituse_jsr relocation */ -#define O_gpdisp O_md7 /* !gpdisp relocation */ -#define O_gprelhigh O_md8 /* !gprelhigh relocation */ -#define O_gprellow O_md9 /* !gprellow relocation */ - -#define USER_RELOC_P(R) ((R) >= O_literal && (R) <= O_gprellow) -#endif - - -/* Macros for extracting the type and number of encoded register tokens */ - -#define is_ir_num(x) (((x) & 32) == 0) -#define is_fpr_num(x) (((x) & 32) != 0) -#define regno(x) ((x) & 31) - -/* Something odd inherited from the old assembler */ - -#define note_gpreg(R) (alpha_gprmask |= (1 << (R))) -#define note_fpreg(R) (alpha_fprmask |= (1 << (R))) - -/* Predicates for 16- and 32-bit ranges */ -/* XXX: The non-shift version appears to trigger a compiler bug when - cross-assembling from x86 w/ gcc 2.7.2. */ - -#if 1 -#define range_signed_16(x) \ - (((offsetT)(x) >> 15) == 0 || ((offsetT)(x) >> 15) == -1) -#define range_signed_32(x) \ - (((offsetT)(x) >> 31) == 0 || ((offsetT)(x) >> 31) == -1) -#else -#define range_signed_16(x) ((offsetT)(x) >= -(offsetT)0x8000 && \ - (offsetT)(x) <= (offsetT)0x7FFF) -#define range_signed_32(x) ((offsetT)(x) >= -(offsetT)0x80000000 && \ - (offsetT)(x) <= (offsetT)0x7FFFFFFF) -#endif - -/* Macros for sign extending from 16- and 32-bits. */ -/* XXX: The cast macros will work on all the systems that I care about, - but really a predicate should be found to use the non-cast forms. */ - -#if 1 -#define sign_extend_16(x) ((short)(x)) -#define sign_extend_32(x) ((int)(x)) -#else -#define sign_extend_16(x) ((offsetT)(((x) & 0xFFFF) ^ 0x8000) - 0x8000) -#define sign_extend_32(x) ((offsetT)(((x) & 0xFFFFFFFF) \ - ^ 0x80000000) - 0x80000000) -#endif - -/* Macros to build tokens */ - -#define set_tok_reg(t, r) (memset(&(t), 0, sizeof(t)), \ - (t).X_op = O_register, \ - (t).X_add_number = (r)) -#define set_tok_preg(t, r) (memset(&(t), 0, sizeof(t)), \ - (t).X_op = O_pregister, \ - (t).X_add_number = (r)) -#define set_tok_cpreg(t, r) (memset(&(t), 0, sizeof(t)), \ - (t).X_op = O_cpregister, \ - (t).X_add_number = (r)) -#define set_tok_freg(t, r) (memset(&(t), 0, sizeof(t)), \ - (t).X_op = O_register, \ - (t).X_add_number = (r)+32) -#define set_tok_sym(t, s, a) (memset(&(t), 0, sizeof(t)), \ - (t).X_op = O_symbol, \ - (t).X_add_symbol = (s), \ - (t).X_add_number = (a)) -#define set_tok_const(t, n) (memset(&(t), 0, sizeof(t)), \ - (t).X_op = O_constant, \ - (t).X_add_number = (n)) - - -/* Prototypes for all local functions */ - -static int tokenize_arguments PARAMS ((char *, expressionS *, int)); -static const struct alpha_opcode *find_opcode_match - PARAMS ((const struct alpha_opcode *, const expressionS *, int *, int *)); -static const struct alpha_macro *find_macro_match - PARAMS ((const struct alpha_macro *, const expressionS *, int *)); -static unsigned insert_operand - PARAMS ((unsigned, const struct alpha_operand *, offsetT, char *, unsigned)); -static void assemble_insn - PARAMS ((const struct alpha_opcode *, const expressionS *, int, - struct alpha_insn *)); -static void emit_insn PARAMS ((struct alpha_insn *)); -static void assemble_tokens_to_insn - PARAMS ((const char *, const expressionS *, int, struct alpha_insn *)); -static void assemble_tokens - PARAMS ((const char *, const expressionS *, int, int)); - -static int load_expression - PARAMS ((int, const expressionS *, int *, expressionS *, - const expressionS *)); - -static void emit_ldgp PARAMS ((const expressionS *, int, const PTR)); -static void emit_division PARAMS ((const expressionS *, int, const PTR)); -static void emit_lda PARAMS ((const expressionS *, int, const PTR)); -static void emit_ldah PARAMS ((const expressionS *, int, const PTR)); -static void emit_ir_load PARAMS ((const expressionS *, int, const PTR)); -static void emit_loadstore PARAMS ((const expressionS *, int, const PTR)); -static void emit_jsrjmp PARAMS ((const expressionS *, int, const PTR)); -static void emit_ldX PARAMS ((const expressionS *, int, const PTR)); -static void emit_ldXu PARAMS ((const expressionS *, int, const PTR)); -static void emit_uldX PARAMS ((const expressionS *, int, const PTR)); -static void emit_uldXu PARAMS ((const expressionS *, int, const PTR)); -static void emit_ldil PARAMS ((const expressionS *, int, const PTR)); -static void emit_stX PARAMS ((const expressionS *, int, const PTR)); -static void emit_ustX PARAMS ((const expressionS *, int, const PTR)); -static void emit_sextX PARAMS ((const expressionS *, int, const PTR)); -static void emit_retjcr PARAMS ((const expressionS *, int, const PTR)); - -static void s_alpha_text PARAMS ((int)); -static void s_alpha_data PARAMS ((int)); -#ifndef OBJ_ELF -static void s_alpha_comm PARAMS ((int)); -static void s_alpha_rdata PARAMS ((int)); -#endif -#ifdef OBJ_ECOFF -static void s_alpha_sdata PARAMS ((int)); -#endif -#ifdef OBJ_ELF -static void s_alpha_section PARAMS ((int)); -static void s_alpha_ent PARAMS ((int)); -static void s_alpha_end PARAMS ((int)); -static void s_alpha_mask PARAMS ((int)); -static void s_alpha_frame PARAMS ((int)); -static void s_alpha_prologue PARAMS ((int)); -static void s_alpha_coff_wrapper PARAMS ((int)); -#endif -#ifdef OBJ_EVAX -static void s_alpha_section PARAMS ((int)); -#endif -static void s_alpha_gprel32 PARAMS ((int)); -static void s_alpha_float_cons PARAMS ((int)); -static void s_alpha_proc PARAMS ((int)); -static void s_alpha_set PARAMS ((int)); -static void s_alpha_base PARAMS ((int)); -static void s_alpha_align PARAMS ((int)); -static void s_alpha_stringer PARAMS ((int)); -static void s_alpha_space PARAMS ((int)); - -static void create_literal_section PARAMS ((const char *, segT *, symbolS **)); -#ifndef OBJ_ELF -static void select_gp_value PARAMS ((void)); -#endif -static void alpha_align PARAMS ((int, char *, symbolS *, int)); - -#ifdef RELOC_OP_P -static void alpha_adjust_symtab_relocs PARAMS ((bfd *, asection *, PTR)); -#endif - - -/* Generic assembler global variables which must be defined by all - targets. */ - -/* Characters which always start a comment. */ -const char comment_chars[] = "#"; - -/* Characters which start a comment at the beginning of a line. */ -const char line_comment_chars[] = "#"; - -/* Characters which may be used to separate multiple commands on a - single line. */ -const char line_separator_chars[] = ";"; - -/* Characters which are used to indicate an exponent in a floating - point number. */ -const char EXP_CHARS[] = "eE"; - -/* Characters which mean that a number is a floating point constant, - as in 0d1.0. */ -#if 0 -const char FLT_CHARS[] = "dD"; -#else -/* XXX: Do all of these really get used on the alpha?? */ -char FLT_CHARS[] = "rRsSfFdDxXpP"; -#endif - -#ifdef OBJ_EVAX -const char *md_shortopts = "Fm:g+1h:HG:"; -#else -const char *md_shortopts = "Fm:gG:"; -#endif - -struct option md_longopts[] = { -#define OPTION_32ADDR (OPTION_MD_BASE) - { "32addr", no_argument, NULL, OPTION_32ADDR }, -#define OPTION_RELAX (OPTION_32ADDR+1) - { "relax", no_argument, NULL, OPTION_RELAX }, -#ifdef OBJ_ELF -#define OPTION_MDEBUG (OPTION_RELAX+1) -#define OPTION_NO_MDEBUG (OPTION_MDEBUG+1) - { "mdebug", no_argument, NULL, OPTION_MDEBUG }, - { "no-mdebug", no_argument, NULL, OPTION_NO_MDEBUG }, -#endif - { NULL, no_argument, NULL, 0 } -}; - -size_t md_longopts_size = sizeof(md_longopts); - - -#ifdef OBJ_EVAX -#define AXP_REG_R0 0 -#define AXP_REG_R16 16 -#define AXP_REG_R17 17 -#undef AXP_REG_T9 -#define AXP_REG_T9 22 -#undef AXP_REG_T10 -#define AXP_REG_T10 23 -#undef AXP_REG_T11 -#define AXP_REG_T11 24 -#undef AXP_REG_T12 -#define AXP_REG_T12 25 -#define AXP_REG_AI 25 -#undef AXP_REG_FP -#define AXP_REG_FP 29 - -#undef AXP_REG_GP -#define AXP_REG_GP AXP_REG_PV -#endif /* OBJ_EVAX */ - -/* The cpu for which we are generating code */ -static unsigned alpha_target = AXP_OPCODE_BASE; -static const char *alpha_target_name = "<all>"; - -/* The hash table of instruction opcodes */ -static struct hash_control *alpha_opcode_hash; - -/* The hash table of macro opcodes */ -static struct hash_control *alpha_macro_hash; - -#ifdef OBJ_ECOFF -/* The $gp relocation symbol */ -static symbolS *alpha_gp_symbol; - -/* XXX: what is this, and why is it exported? */ -valueT alpha_gp_value; -#endif - -/* The current $gp register */ -static int alpha_gp_register = AXP_REG_GP; - -/* A table of the register symbols */ -static symbolS *alpha_register_table[64]; - -/* Constant sections, or sections of constants */ -#ifdef OBJ_ECOFF -static segT alpha_lita_section; -static segT alpha_lit4_section; -#endif -#ifdef OBJ_EVAX -static segT alpha_link_section; -static segT alpha_ctors_section; -static segT alpha_dtors_section; -#endif -static segT alpha_lit8_section; - -/* Symbols referring to said sections. */ -#ifdef OBJ_ECOFF -static symbolS *alpha_lita_symbol; -static symbolS *alpha_lit4_symbol; -#endif -#ifdef OBJ_EVAX -static symbolS *alpha_link_symbol; -static symbolS *alpha_ctors_symbol; -static symbolS *alpha_dtors_symbol; -#endif -static symbolS *alpha_lit8_symbol; - -/* Literal for .litX+0x8000 within .lita */ -#ifdef OBJ_ECOFF -static offsetT alpha_lit4_literal; -static offsetT alpha_lit8_literal; -#endif - -/* The active .ent symbol. */ -#ifdef OBJ_ELF -static symbolS *alpha_cur_ent_sym; -#endif - -/* Is the assembler not allowed to use $at? */ -static int alpha_noat_on = 0; - -/* Are macros enabled? */ -static int alpha_macros_on = 1; - -/* Are floats disabled? */ -static int alpha_nofloats_on = 0; - -/* Are addresses 32 bit? */ -static int alpha_addr32_on = 0; - -/* Symbol labelling the current insn. When the Alpha gas sees - foo: - .quad 0 - and the section happens to not be on an eight byte boundary, it - will align both the symbol and the .quad to an eight byte boundary. */ -static symbolS *alpha_insn_label; - -/* Whether we should automatically align data generation pseudo-ops. - .align 0 will turn this off. */ -static int alpha_auto_align_on = 1; - -/* The known current alignment of the current section. */ -static int alpha_current_align; - -/* These are exported to ECOFF code. */ -unsigned long alpha_gprmask, alpha_fprmask; - -/* Whether the debugging option was seen. */ -static int alpha_debug; - -#ifdef OBJ_ELF -/* Whether we are emitting an mdebug section. */ -int alpha_flag_mdebug = 1; -#endif - -/* Don't fully resolve relocations, allowing code movement in the linker. */ -static int alpha_flag_relax; - -/* What value to give to bfd_set_gp_size. */ -static int g_switch_value = 8; - -#ifdef OBJ_EVAX -/* Collect information about current procedure here. */ -static struct { - symbolS *symbol; /* proc pdesc symbol */ - int pdsckind; - int framereg; /* register for frame pointer */ - int framesize; /* size of frame */ - int rsa_offset; - int ra_save; - int fp_save; - long imask; - long fmask; - int type; - int prologue; -} alpha_evax_proc; - -static int alpha_flag_hash_long_names = 0; /* -+ */ -static int alpha_flag_show_after_trunc = 0; /* -H */ - -/* If the -+ switch is given, then a hash is appended to any name that is - * longer than 64 characters, else longer symbol names are truncated. - */ - -#endif - -#ifdef RELOC_OP_P -/* A table to map the spelling of a relocation operand into an appropriate - bfd_reloc_code_real_type type. The table is assumed to be ordered such - that op-O_literal indexes into it. */ - -#define ALPHA_RELOC_TABLE(op) \ -&alpha_reloc_op[ ((!USER_RELOC_P (op)) \ - ? (abort (), 0) \ - : (int)(op) - (int)O_literal) ] - -#define LITUSE_BASE 1 -#define LITUSE_BYTOFF 2 -#define LITUSE_JSR 3 - -static const struct alpha_reloc_op_tag { - const char *name; /* string to lookup */ - size_t length; /* size of the string */ - bfd_reloc_code_real_type reloc; /* relocation before frob */ - operatorT op; /* which operator to use */ - int lituse; /* addened to specify lituse */ -} alpha_reloc_op[] = { - - { - "literal", /* name */ - sizeof ("literal")-1, /* length */ - BFD_RELOC_ALPHA_USER_LITERAL, /* reloc */ - O_literal, /* op */ - 0, /* lituse */ - }, - - { - "lituse_base", /* name */ - sizeof ("lituse_base")-1, /* length */ - BFD_RELOC_ALPHA_USER_LITUSE_BASE, /* reloc */ - O_lituse_base, /* op */ - LITUSE_BASE, /* lituse */ - }, - - { - "lituse_bytoff", /* name */ - sizeof ("lituse_bytoff")-1, /* length */ - BFD_RELOC_ALPHA_USER_LITUSE_BYTOFF, /* reloc */ - O_lituse_bytoff, /* op */ - LITUSE_BYTOFF, /* lituse */ - }, - - { - "lituse_jsr", /* name */ - sizeof ("lituse_jsr")-1, /* length */ - BFD_RELOC_ALPHA_USER_LITUSE_JSR, /* reloc */ - O_lituse_jsr, /* op */ - LITUSE_JSR, /* lituse */ - }, - - { - "gpdisp", /* name */ - sizeof ("gpdisp")-1, /* length */ - BFD_RELOC_ALPHA_USER_GPDISP, /* reloc */ - O_gpdisp, /* op */ - 0, /* lituse */ - }, - - { - "gprelhigh", /* name */ - sizeof ("gprelhigh")-1, /* length */ - BFD_RELOC_ALPHA_USER_GPRELHIGH, /* reloc */ - O_gprelhigh, /* op */ - 0, /* lituse */ - }, - - { - "gprellow", /* name */ - sizeof ("gprellow")-1, /* length */ - BFD_RELOC_ALPHA_USER_GPRELLOW, /* reloc */ - O_gprellow, /* op */ - 0, /* lituse */ - }, -}; - -static const int alpha_num_reloc_op - = sizeof(alpha_reloc_op) / sizeof(*alpha_reloc_op); - -/* Maximum # digits needed to hold the largest sequence # */ -#define ALPHA_RELOC_DIGITS 25 - -/* Whether a sequence number is valid. */ -#define ALPHA_RELOC_SEQUENCE_OK(X) ((X) > 0 && ((unsigned)(X)) == (X)) - -/* Structure to hold explict sequence information. */ -struct alpha_literal_tag -{ - fixS *lituse; /* head of linked list of !literals */ - segT segment; /* segment relocs are in or undefined_section*/ - int multi_section_p; /* True if more than one section was used */ - unsigned sequence; /* sequence # */ - unsigned n_literals; /* # of literals */ - unsigned n_lituses; /* # of lituses */ - char string[1]; /* printable form of sequence to hash with */ -}; - -/* Hash table to link up literals with the appropriate lituse */ -static struct hash_control *alpha_literal_hash; -#endif - -/* A table of CPU names and opcode sets. */ - -static const struct cpu_type -{ - const char *name; - unsigned flags; -} cpu_types[] = -{ - /* Ad hoc convention: cpu number gets palcode, process code doesn't. - This supports usage under DU 4.0b that does ".arch ev4", and - usage in MILO that does -m21064. Probably something more - specific like -m21064-pal should be used, but oh well. */ - - { "21064", AXP_OPCODE_BASE|AXP_OPCODE_EV4 }, - { "21064a", AXP_OPCODE_BASE|AXP_OPCODE_EV4 }, - { "21066", AXP_OPCODE_BASE|AXP_OPCODE_EV4 }, - { "21068", AXP_OPCODE_BASE|AXP_OPCODE_EV4 }, - { "21164", AXP_OPCODE_BASE|AXP_OPCODE_EV5 }, - { "21164a", AXP_OPCODE_BASE|AXP_OPCODE_EV5|AXP_OPCODE_BWX }, - { "21164pc", (AXP_OPCODE_BASE|AXP_OPCODE_EV5|AXP_OPCODE_BWX - |AXP_OPCODE_MAX) }, - { "21264", (AXP_OPCODE_BASE|AXP_OPCODE_EV6|AXP_OPCODE_BWX - |AXP_OPCODE_MAX|AXP_OPCODE_CIX) }, - - { "ev4", AXP_OPCODE_BASE }, - { "ev45", AXP_OPCODE_BASE }, - { "lca45", AXP_OPCODE_BASE }, - { "ev5", AXP_OPCODE_BASE }, - { "ev56", AXP_OPCODE_BASE|AXP_OPCODE_BWX }, - { "pca56", AXP_OPCODE_BASE|AXP_OPCODE_BWX|AXP_OPCODE_MAX }, - { "ev6", AXP_OPCODE_BASE|AXP_OPCODE_BWX|AXP_OPCODE_MAX|AXP_OPCODE_CIX }, - - { "all", AXP_OPCODE_BASE }, - { 0, 0 } -}; - -/* The macro table */ - -static const struct alpha_macro alpha_macros[] = { -/* Load/Store macros */ - { "lda", emit_lda, NULL, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_LITERAL, MACRO_BASE, MACRO_EOA } }, - { "ldah", emit_ldah, NULL, - { MACRO_IR, MACRO_EXP, MACRO_EOA } }, - - { "ldl", emit_ir_load, "ldl", - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, - { "ldl_l", emit_ir_load, "ldl_l", - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, - { "ldq", emit_ir_load, "ldq", - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_LITERAL, MACRO_EOA } }, - { "ldq_l", emit_ir_load, "ldq_l", - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, - { "ldq_u", emit_ir_load, "ldq_u", - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, - { "ldf", emit_loadstore, "ldf", - { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, - { "ldg", emit_loadstore, "ldg", - { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, - { "lds", emit_loadstore, "lds", - { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, - { "ldt", emit_loadstore, "ldt", - { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, - - { "ldb", emit_ldX, (PTR)0, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, - { "ldbu", emit_ldXu, (PTR)0, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, - { "ldw", emit_ldX, (PTR)1, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, - { "ldwu", emit_ldXu, (PTR)1, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, - - { "uldw", emit_uldX, (PTR)1, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, - { "uldwu", emit_uldXu, (PTR)1, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, - { "uldl", emit_uldX, (PTR)2, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, - { "uldlu", emit_uldXu, (PTR)2, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, - { "uldq", emit_uldXu, (PTR)3, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, - - { "ldgp", emit_ldgp, NULL, - { MACRO_IR, MACRO_EXP, MACRO_PIR, MACRO_EOA } }, - - { "ldi", emit_lda, NULL, - { MACRO_IR, MACRO_EXP, MACRO_EOA } }, - { "ldil", emit_ldil, NULL, - { MACRO_IR, MACRO_EXP, MACRO_EOA } }, - { "ldiq", emit_lda, NULL, - { MACRO_IR, MACRO_EXP, MACRO_EOA } }, -#if 0 - { "ldif" emit_ldiq, NULL, - { MACRO_FPR, MACRO_EXP, MACRO_EOA } }, - { "ldid" emit_ldiq, NULL, - { MACRO_FPR, MACRO_EXP, MACRO_EOA } }, - { "ldig" emit_ldiq, NULL, - { MACRO_FPR, MACRO_EXP, MACRO_EOA } }, - { "ldis" emit_ldiq, NULL, - { MACRO_FPR, MACRO_EXP, MACRO_EOA } }, - { "ldit" emit_ldiq, NULL, - { MACRO_FPR, MACRO_EXP, MACRO_EOA } }, -#endif - - { "stl", emit_loadstore, "stl", - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, - { "stl_c", emit_loadstore, "stl_c", - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, - { "stq", emit_loadstore, "stq", - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, - { "stq_c", emit_loadstore, "stq_c", - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, - { "stq_u", emit_loadstore, "stq_u", - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, - { "stf", emit_loadstore, "stf", - { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, - { "stg", emit_loadstore, "stg", - { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, - { "sts", emit_loadstore, "sts", - { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, - { "stt", emit_loadstore, "stt", - { MACRO_FPR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, - - { "stb", emit_stX, (PTR)0, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, - { "stw", emit_stX, (PTR)1, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, - { "ustw", emit_ustX, (PTR)1, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, - { "ustl", emit_ustX, (PTR)2, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, - { "ustq", emit_ustX, (PTR)3, - { MACRO_IR, MACRO_EXP, MACRO_OPIR, MACRO_BASE, MACRO_EOA } }, - -/* Arithmetic macros */ -#if 0 - { "absl" emit_absl, 1, { IR } }, - { "absl" emit_absl, 2, { IR, IR } }, - { "absl" emit_absl, 2, { EXP, IR } }, - { "absq" emit_absq, 1, { IR } }, - { "absq" emit_absq, 2, { IR, IR } }, - { "absq" emit_absq, 2, { EXP, IR } }, -#endif - - { "sextb", emit_sextX, (PTR)0, - { MACRO_IR, MACRO_IR, MACRO_EOA, - MACRO_IR, MACRO_EOA, - /* MACRO_EXP, MACRO_IR, MACRO_EOA */ } }, - { "sextw", emit_sextX, (PTR)1, - { MACRO_IR, MACRO_IR, MACRO_EOA, - MACRO_IR, MACRO_EOA, - /* MACRO_EXP, MACRO_IR, MACRO_EOA */ } }, - - { "divl", emit_division, "__divl", - { MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA, - MACRO_IR, MACRO_IR, MACRO_EOA, - /* MACRO_IR, MACRO_EXP, MACRO_IR, MACRO_EOA, - MACRO_IR, MACRO_EXP, MACRO_EOA */ } }, - { "divlu", emit_division, "__divlu", - { MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA, - MACRO_IR, MACRO_IR, MACRO_EOA, - /* MACRO_IR, MACRO_EXP, MACRO_IR, MACRO_EOA, - MACRO_IR, MACRO_EXP, MACRO_EOA */ } }, - { "divq", emit_division, "__divq", - { MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA, - MACRO_IR, MACRO_IR, MACRO_EOA, - /* MACRO_IR, MACRO_EXP, MACRO_IR, MACRO_EOA, - MACRO_IR, MACRO_EXP, MACRO_EOA */ } }, - { "divqu", emit_division, "__divqu", - { MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA, - MACRO_IR, MACRO_IR, MACRO_EOA, - /* MACRO_IR, MACRO_EXP, MACRO_IR, MACRO_EOA, - MACRO_IR, MACRO_EXP, MACRO_EOA */ } }, - { "reml", emit_division, "__reml", - { MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA, - MACRO_IR, MACRO_IR, MACRO_EOA, - /* MACRO_IR, MACRO_EXP, MACRO_IR, MACRO_EOA, - MACRO_IR, MACRO_EXP, MACRO_EOA */ } }, - { "remlu", emit_division, "__remlu", - { MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA, - MACRO_IR, MACRO_IR, MACRO_EOA, - /* MACRO_IR, MACRO_EXP, MACRO_IR, MACRO_EOA, - MACRO_IR, MACRO_EXP, MACRO_EOA */ } }, - { "remq", emit_division, "__remq", - { MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA, - MACRO_IR, MACRO_IR, MACRO_EOA, - /* MACRO_IR, MACRO_EXP, MACRO_IR, MACRO_EOA, - MACRO_IR, MACRO_EXP, MACRO_EOA */ } }, - { "remqu", emit_division, "__remqu", - { MACRO_IR, MACRO_IR, MACRO_IR, MACRO_EOA, - MACRO_IR, MACRO_IR, MACRO_EOA, - /* MACRO_IR, MACRO_EXP, MACRO_IR, MACRO_EOA, - MACRO_IR, MACRO_EXP, MACRO_EOA */ } }, - - { "jsr", emit_jsrjmp, "jsr", - { MACRO_PIR, MACRO_EXP, MACRO_JSR, MACRO_EOA, - MACRO_PIR, MACRO_JSR, MACRO_EOA, - MACRO_IR, MACRO_EXP, MACRO_JSR, MACRO_EOA, - MACRO_EXP, MACRO_JSR, MACRO_EOA } }, - { "jmp", emit_jsrjmp, "jmp", - { MACRO_PIR, MACRO_EXP, MACRO_JSR, MACRO_EOA, - MACRO_PIR, MACRO_JSR, MACRO_EOA, - MACRO_IR, MACRO_EXP, MACRO_JSR, MACRO_EOA, - MACRO_EXP, MACRO_JSR, MACRO_EOA } }, - { "ret", emit_retjcr, "ret", - { MACRO_IR, MACRO_EXP, MACRO_EOA, - MACRO_IR, MACRO_EOA, - MACRO_PIR, MACRO_EXP, MACRO_EOA, - MACRO_PIR, MACRO_EOA, - MACRO_EXP, MACRO_EOA, - MACRO_EOA } }, - { "jcr", emit_retjcr, "jcr", - { MACRO_IR, MACRO_EXP, MACRO_EOA, - MACRO_IR, MACRO_EOA, - MACRO_PIR, MACRO_EXP, MACRO_EOA, - MACRO_PIR, MACRO_EOA, - MACRO_EXP, MACRO_EOA, - MACRO_EOA } }, - { "jsr_coroutine", emit_retjcr, "jcr", - { MACRO_IR, MACRO_EXP, MACRO_EOA, - MACRO_IR, MACRO_EOA, - MACRO_PIR, MACRO_EXP, MACRO_EOA, - MACRO_PIR, MACRO_EOA, - MACRO_EXP, MACRO_EOA, - MACRO_EOA } }, -}; - -static const unsigned int alpha_num_macros - = sizeof(alpha_macros) / sizeof(*alpha_macros); - -/* Public interface functions */ - -/* This function is called once, at assembler startup time. It sets - up all the tables, etc. that the MD part of the assembler will - need, that can be determined before arguments are parsed. */ - -void -md_begin () -{ - unsigned int i; - - /* Verify that X_op field is wide enough. */ - { - expressionS e; - e.X_op = O_max; - assert (e.X_op == O_max); - } - - /* Create the opcode hash table */ - - alpha_opcode_hash = hash_new (); - for (i = 0; i < alpha_num_opcodes; ) - { - const char *name, *retval, *slash; - - name = alpha_opcodes[i].name; - retval = hash_insert (alpha_opcode_hash, name, (PTR)&alpha_opcodes[i]); - if (retval) - as_fatal (_("internal error: can't hash opcode `%s': %s"), name, retval); - - /* Some opcodes include modifiers of various sorts with a "/mod" - syntax, like the architecture manual suggests. However, for - use with gcc at least, we also need access to those same opcodes - without the "/". */ - - if ((slash = strchr (name, '/')) != NULL) - { - char *p = xmalloc (strlen (name)); - memcpy (p, name, slash - name); - strcpy (p + (slash - name), slash + 1); - - (void)hash_insert(alpha_opcode_hash, p, (PTR)&alpha_opcodes[i]); - /* Ignore failures -- the opcode table does duplicate some - variants in different forms, like "hw_stq" and "hw_st/q". */ - } - - while (++i < alpha_num_opcodes - && (alpha_opcodes[i].name == name - || !strcmp (alpha_opcodes[i].name, name))) - continue; - } - - /* Create the macro hash table */ - - alpha_macro_hash = hash_new (); - for (i = 0; i < alpha_num_macros; ) - { - const char *name, *retval; - - name = alpha_macros[i].name; - retval = hash_insert (alpha_macro_hash, name, (PTR)&alpha_macros[i]); - if (retval) - as_fatal (_("internal error: can't hash macro `%s': %s"), name, retval); - - while (++i < alpha_num_macros - && (alpha_macros[i].name == name - || !strcmp (alpha_macros[i].name, name))) - continue; - } - - /* Construct symbols for each of the registers */ - - for (i = 0; i < 32; ++i) - { - char name[4]; - sprintf(name, "$%d", i); - alpha_register_table[i] = symbol_create(name, reg_section, i, - &zero_address_frag); - } - for (; i < 64; ++i) - { - char name[5]; - sprintf(name, "$f%d", i-32); - alpha_register_table[i] = symbol_create(name, reg_section, i, - &zero_address_frag); - } - - /* Create the special symbols and sections we'll be using */ - - /* So .sbss will get used for tiny objects. */ - bfd_set_gp_size (stdoutput, g_switch_value); - -#ifdef OBJ_ECOFF - create_literal_section (".lita", &alpha_lita_section, &alpha_lita_symbol); - - /* For handling the GP, create a symbol that won't be output in the - symbol table. We'll edit it out of relocs later. */ - alpha_gp_symbol = symbol_create ("<GP value>", alpha_lita_section, 0x8000, - &zero_address_frag); -#endif - -#ifdef OBJ_EVAX - create_literal_section (".link", &alpha_link_section, &alpha_link_symbol); -#endif - -#ifdef OBJ_ELF - if (ECOFF_DEBUGGING) - { - segT sec = subseg_new(".mdebug", (subsegT)0); - bfd_set_section_flags(stdoutput, sec, SEC_HAS_CONTENTS|SEC_READONLY); - bfd_set_section_alignment(stdoutput, sec, 3); - } -#endif /* OBJ_ELF */ - - subseg_set(text_section, 0); - -#ifdef RELOC_OP_P - /* Create literal lookup hash table. */ - alpha_literal_hash = hash_new(); -#endif -} - -/* The public interface to the instruction assembler. */ - -void -md_assemble (str) - char *str; -{ - char opname[32]; /* current maximum is 13 */ - expressionS tok[MAX_INSN_ARGS]; - int ntok, trunclen; - size_t opnamelen; - - /* split off the opcode */ - opnamelen = strspn (str, "abcdefghijklmnopqrstuvwxyz_/46819"); - trunclen = (opnamelen < sizeof (opname) - 1 - ? opnamelen - : sizeof (opname) - 1); - memcpy (opname, str, trunclen); - opname[trunclen] = '\0'; - - /* tokenize the rest of the line */ - if ((ntok = tokenize_arguments (str + opnamelen, tok, MAX_INSN_ARGS)) < 0) - { - if (ntok != TOKENIZE_ERROR_REPORT) - as_bad (_("syntax error")); - - return; - } - - /* finish it off */ - assemble_tokens (opname, tok, ntok, alpha_macros_on); -} - -/* Round up a section's size to the appropriate boundary. */ - -valueT -md_section_align (seg, size) - segT seg; - valueT size; -{ - int align = bfd_get_section_alignment(stdoutput, seg); - valueT mask = ((valueT)1 << align) - 1; - - return (size + mask) & ~mask; -} - -/* Turn a string in input_line_pointer into a floating point constant - of type type, and store the appropriate bytes in *litP. The number - of LITTLENUMS emitted is stored in *sizeP. An error message is - returned, or NULL on OK. */ - -/* Equal to MAX_PRECISION in atof-ieee.c */ -#define MAX_LITTLENUMS 6 - -extern char *vax_md_atof PARAMS ((int, char *, int *)); - -char * -md_atof (type, litP, sizeP) - char type; - char *litP; - int *sizeP; -{ - int prec; - LITTLENUM_TYPE words[MAX_LITTLENUMS]; - LITTLENUM_TYPE *wordP; - char *t; - - switch (type) - { - /* VAX floats */ - case 'G': - /* VAX md_atof doesn't like "G" for some reason. */ - type = 'g'; - case 'F': - case 'D': - return vax_md_atof (type, litP, sizeP); - - /* IEEE floats */ - case 'f': - prec = 2; - break; - - case 'd': - prec = 4; - break; - - case 'x': - case 'X': - prec = 6; - break; - - case 'p': - case 'P': - prec = 6; - break; - - default: - *sizeP = 0; - return _("Bad call to MD_ATOF()"); - } - t = atof_ieee (input_line_pointer, type, words); - if (t) - input_line_pointer = t; - *sizeP = prec * sizeof (LITTLENUM_TYPE); - - for (wordP = words + prec - 1; prec--;) - { - md_number_to_chars (litP, (long) (*wordP--), sizeof (LITTLENUM_TYPE)); - litP += sizeof (LITTLENUM_TYPE); - } - - return 0; -} - -/* Take care of the target-specific command-line options. */ - -int -md_parse_option (c, arg) - int c; - char *arg; -{ - switch (c) - { - case 'F': - alpha_nofloats_on = 1; - break; - - case OPTION_32ADDR: - alpha_addr32_on = 1; - break; - - case 'g': - alpha_debug = 1; - break; - - case 'G': - g_switch_value = atoi(arg); - break; - - case 'm': - { - const struct cpu_type *p; - for (p = cpu_types; p->name; ++p) - if (strcmp(arg, p->name) == 0) - { - alpha_target_name = p->name, alpha_target = p->flags; - goto found; - } - as_warn(_("Unknown CPU identifier `%s'"), arg); - found:; - } - break; - -#ifdef OBJ_EVAX - case '+': /* For g++. Hash any name > 63 chars long. */ - alpha_flag_hash_long_names = 1; - break; - - case 'H': /* Show new symbol after hash truncation */ - alpha_flag_show_after_trunc = 1; - break; - - case 'h': /* for gnu-c/vax compatibility. */ - break; -#endif - - case OPTION_RELAX: - alpha_flag_relax = 1; - break; - -#ifdef OBJ_ELF - case OPTION_MDEBUG: - alpha_flag_mdebug = 1; - break; - case OPTION_NO_MDEBUG: - alpha_flag_mdebug = 0; - break; -#endif - - default: - return 0; - } - - return 1; -} - -/* Print a description of the command-line options that we accept. */ - -void -md_show_usage (stream) - FILE *stream; -{ - fputs(_("\ -Alpha options:\n\ --32addr treat addresses as 32-bit values\n\ --F lack floating point instructions support\n\ --mev4 | -mev45 | -mev5 | -mev56 | -mpca56 | -mev6 | -mall\n\ - specify variant of Alpha architecture\n\ --m21064 | -m21066 | -m21164 | -m21164a | -m21164pc | -m21264\n\ - these variants include PALcode opcodes\n"), - stream); -#ifdef OBJ_EVAX - fputs (_("\ -VMS options:\n\ --+ hash encode (don't truncate) names longer than 64 characters\n\ --H show new symbol after hash truncation\n"), - stream); -#endif -} - -/* Decide from what point a pc-relative relocation is relative to, - relative to the pc-relative fixup. Er, relatively speaking. */ - -long -md_pcrel_from (fixP) - fixS *fixP; -{ - valueT addr = fixP->fx_where + fixP->fx_frag->fr_address; - switch (fixP->fx_r_type) - { - case BFD_RELOC_ALPHA_GPDISP: - case BFD_RELOC_ALPHA_GPDISP_HI16: - case BFD_RELOC_ALPHA_GPDISP_LO16: - return addr; - default: - return fixP->fx_size + addr; - } -} - -/* Attempt to simplify or even eliminate a fixup. The return value is - ignored; perhaps it was once meaningful, but now it is historical. - To indicate that a fixup has been eliminated, set fixP->fx_done. - - For ELF, here it is that we transform the GPDISP_HI16 reloc we used - internally into the GPDISP reloc used externally. We had to do - this so that we'd have the GPDISP_LO16 reloc as a tag to compute - the distance to the "lda" instruction for setting the addend to - GPDISP. */ - -int -md_apply_fix (fixP, valueP) - fixS *fixP; - valueT *valueP; -{ - char * const fixpos = fixP->fx_frag->fr_literal + fixP->fx_where; - valueT value = *valueP; - unsigned image, size; - - switch (fixP->fx_r_type) - { - /* The GPDISP relocations are processed internally with a symbol - referring to the current function; we need to drop in a value - which, when added to the address of the start of the function, - gives the desired GP. */ - case BFD_RELOC_ALPHA_GPDISP_HI16: - { - fixS *next = fixP->fx_next; - assert (next->fx_r_type == BFD_RELOC_ALPHA_GPDISP_LO16); - - fixP->fx_offset = (next->fx_frag->fr_address + next->fx_where - - fixP->fx_frag->fr_address - fixP->fx_where); - - value = (value - sign_extend_16 (value)) >> 16; - } -#ifdef OBJ_ELF - fixP->fx_r_type = BFD_RELOC_ALPHA_GPDISP; -#endif - goto do_reloc_gp; - - case BFD_RELOC_ALPHA_GPDISP_LO16: - value = sign_extend_16 (value); - fixP->fx_offset = 0; -#ifdef OBJ_ELF - fixP->fx_done = 1; -#endif - - do_reloc_gp: - fixP->fx_addsy = section_symbol (now_seg); - md_number_to_chars (fixpos, value, 2); - break; - - case BFD_RELOC_16: - if (fixP->fx_pcrel) - fixP->fx_r_type = BFD_RELOC_16_PCREL; - size = 2; - goto do_reloc_xx; - case BFD_RELOC_32: - if (fixP->fx_pcrel) - fixP->fx_r_type = BFD_RELOC_32_PCREL; - size = 4; - goto do_reloc_xx; - case BFD_RELOC_64: - if (fixP->fx_pcrel) - fixP->fx_r_type = BFD_RELOC_64_PCREL; - size = 8; - do_reloc_xx: - if (fixP->fx_pcrel == 0 && fixP->fx_addsy == 0) - { - md_number_to_chars (fixpos, value, size); - goto done; - } - return 1; - -#ifdef OBJ_ECOFF - case BFD_RELOC_GPREL32: - assert (fixP->fx_subsy == alpha_gp_symbol); - fixP->fx_subsy = 0; - /* FIXME: inherited this obliviousness of `value' -- why? */ - md_number_to_chars (fixpos, -alpha_gp_value, 4); - break; -#endif -#ifdef OBJ_ELF - case BFD_RELOC_GPREL32: - return 1; -#endif - - case BFD_RELOC_23_PCREL_S2: - if (fixP->fx_pcrel == 0 && fixP->fx_addsy == 0) - { - image = bfd_getl32(fixpos); - image = (image & ~0x1FFFFF) | ((value >> 2) & 0x1FFFFF); - goto write_done; - } - return 1; - - case BFD_RELOC_ALPHA_HINT: - if (fixP->fx_pcrel == 0 && fixP->fx_addsy == 0) - { - image = bfd_getl32(fixpos); - image = (image & ~0x3FFF) | ((value >> 2) & 0x3FFF); - goto write_done; - } - return 1; - -#ifdef OBJ_ECOFF - case BFD_RELOC_ALPHA_LITERAL: - md_number_to_chars (fixpos, value, 2); - return 1; - - case BFD_RELOC_ALPHA_LITUSE: - return 1; -#endif -#ifdef OBJ_ELF - case BFD_RELOC_ALPHA_ELF_LITERAL: - case BFD_RELOC_ALPHA_LITUSE: - return 1; -#endif -#ifdef OBJ_EVAX - case BFD_RELOC_ALPHA_LINKAGE: - case BFD_RELOC_ALPHA_CODEADDR: - return 1; -#endif - -#ifdef RELOC_OP_P - case BFD_RELOC_ALPHA_USER_LITERAL: - case BFD_RELOC_ALPHA_USER_LITUSE_BASE: - case BFD_RELOC_ALPHA_USER_LITUSE_BYTOFF: - case BFD_RELOC_ALPHA_USER_LITUSE_JSR: - return 1; - - case BFD_RELOC_ALPHA_USER_GPDISP: - case BFD_RELOC_ALPHA_USER_GPRELHIGH: - case BFD_RELOC_ALPHA_USER_GPRELLOW: - abort (); -#endif - - default: - { - const struct alpha_operand *operand; - - if ((int)fixP->fx_r_type >= 0) - as_fatal (_("unhandled relocation type %s"), - bfd_get_reloc_code_name (fixP->fx_r_type)); - - assert (-(int)fixP->fx_r_type < (int)alpha_num_operands); - operand = &alpha_operands[-(int)fixP->fx_r_type]; - - /* The rest of these fixups only exist internally during symbol - resolution and have no representation in the object file. - Therefore they must be completely resolved as constants. */ - - if (fixP->fx_addsy != 0 - && S_GET_SEGMENT (fixP->fx_addsy) != absolute_section) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("non-absolute expression in constant field")); - - image = bfd_getl32(fixpos); - image = insert_operand(image, operand, (offsetT)value, - fixP->fx_file, fixP->fx_line); - } - goto write_done; - } - - if (fixP->fx_addsy != 0 || fixP->fx_pcrel != 0) - return 1; - else - { - as_warn_where(fixP->fx_file, fixP->fx_line, - _("type %d reloc done?\n"), (int)fixP->fx_r_type); - goto done; - } - -write_done: - md_number_to_chars(fixpos, image, 4); - -done: - fixP->fx_done = 1; - return 0; -} - -/* - * Look for a register name in the given symbol. - */ - -symbolS * -md_undefined_symbol(name) - char *name; -{ - if (*name == '$') - { - int is_float = 0, num; - - switch (*++name) - { - case 'f': - if (name[1] == 'p' && name[2] == '\0') - return alpha_register_table[AXP_REG_FP]; - is_float = 32; - /* FALLTHRU */ - - case 'r': - if (!isdigit(*++name)) - break; - /* FALLTHRU */ - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - if (name[1] == '\0') - num = name[0] - '0'; - else if (name[0] != '0' && isdigit(name[1]) && name[2] == '\0') - { - num = (name[0] - '0') * 10 + name[1] - '0'; - if (num >= 32) - break; - } - else - break; - - if (!alpha_noat_on && num == AXP_REG_AT) - as_warn(_("Used $at without \".set noat\"")); - return alpha_register_table[num + is_float]; - - case 'a': - if (name[1] == 't' && name[2] == '\0') - { - if (!alpha_noat_on) - as_warn(_("Used $at without \".set noat\"")); - return alpha_register_table[AXP_REG_AT]; - } - break; - - case 'g': - if (name[1] == 'p' && name[2] == '\0') - return alpha_register_table[alpha_gp_register]; - break; - - case 's': - if (name[1] == 'p' && name[2] == '\0') - return alpha_register_table[AXP_REG_SP]; - break; - } - } - return NULL; -} - -#ifdef OBJ_ECOFF -/* @@@ Magic ECOFF bits. */ - -void -alpha_frob_ecoff_data () -{ - select_gp_value (); - /* $zero and $f31 are read-only */ - alpha_gprmask &= ~1; - alpha_fprmask &= ~1; -} -#endif - -/* Hook to remember a recently defined label so that the auto-align - code can adjust the symbol after we know what alignment will be - required. */ - -void -alpha_define_label (sym) - symbolS *sym; -{ - alpha_insn_label = sym; -} - -/* Return true if we must always emit a reloc for a type and false if - there is some hope of resolving it a assembly time. */ - -int -alpha_force_relocation (f) - fixS *f; -{ - if (alpha_flag_relax) - return 1; - - switch (f->fx_r_type) - { - case BFD_RELOC_ALPHA_GPDISP_HI16: - case BFD_RELOC_ALPHA_GPDISP_LO16: - case BFD_RELOC_ALPHA_GPDISP: -#ifdef OBJ_ECOFF - case BFD_RELOC_ALPHA_LITERAL: -#endif -#ifdef OBJ_ELF - case BFD_RELOC_ALPHA_ELF_LITERAL: -#endif - case BFD_RELOC_ALPHA_LITUSE: - case BFD_RELOC_GPREL32: -#ifdef OBJ_EVAX - case BFD_RELOC_ALPHA_LINKAGE: - case BFD_RELOC_ALPHA_CODEADDR: -#endif -#ifdef RELOC_OP_P - case BFD_RELOC_ALPHA_USER_LITERAL: - case BFD_RELOC_ALPHA_USER_LITUSE_BASE: - case BFD_RELOC_ALPHA_USER_LITUSE_BYTOFF: - case BFD_RELOC_ALPHA_USER_LITUSE_JSR: - case BFD_RELOC_ALPHA_USER_GPDISP: - case BFD_RELOC_ALPHA_USER_GPRELHIGH: - case BFD_RELOC_ALPHA_USER_GPRELLOW: -#endif - return 1; - - case BFD_RELOC_23_PCREL_S2: - case BFD_RELOC_32: - case BFD_RELOC_64: - case BFD_RELOC_ALPHA_HINT: - return 0; - - default: - assert((int)f->fx_r_type < 0 && -(int)f->fx_r_type < (int)alpha_num_operands); - return 0; - } -} - -/* Return true if we can partially resolve a relocation now. */ - -int -alpha_fix_adjustable (f) - fixS *f; -{ -#ifdef OBJ_ELF - /* Prevent all adjustments to global symbols */ - if (S_IS_EXTERN (f->fx_addsy) || S_IS_WEAK (f->fx_addsy)) - return 0; -#endif - - /* Are there any relocation types for which we must generate a reloc - but we can adjust the values contained within it? */ - switch (f->fx_r_type) - { - case BFD_RELOC_ALPHA_GPDISP_HI16: - case BFD_RELOC_ALPHA_GPDISP_LO16: - case BFD_RELOC_ALPHA_GPDISP: - return 0; - -#ifdef OBJ_ECOFF - case BFD_RELOC_ALPHA_LITERAL: -#endif -#ifdef OBJ_ELF - case BFD_RELOC_ALPHA_ELF_LITERAL: -#endif -#ifdef RELOC_OP_P - case BFD_RELOC_ALPHA_USER_LITERAL: -#endif -#ifdef OBJ_EVAX - case BFD_RELOC_ALPHA_LINKAGE: - case BFD_RELOC_ALPHA_CODEADDR: -#endif - return 1; - - case BFD_RELOC_ALPHA_LITUSE: -#ifdef RELOC_OP_P - case BFD_RELOC_ALPHA_USER_LITUSE_BASE: - case BFD_RELOC_ALPHA_USER_LITUSE_BYTOFF: - case BFD_RELOC_ALPHA_USER_LITUSE_JSR: - case BFD_RELOC_ALPHA_USER_GPDISP: - case BFD_RELOC_ALPHA_USER_GPRELHIGH: - case BFD_RELOC_ALPHA_USER_GPRELLOW: -#endif - return 0; - - case BFD_RELOC_GPREL32: - case BFD_RELOC_23_PCREL_S2: - case BFD_RELOC_32: - case BFD_RELOC_64: - case BFD_RELOC_ALPHA_HINT: - return 1; - - default: - assert ((int)f->fx_r_type < 0 - && - (int)f->fx_r_type < (int)alpha_num_operands); - return 1; - } - /*NOTREACHED*/ -} - -/* Generate the BFD reloc to be stuck in the object file from the - fixup used internally in the assembler. */ - -arelent * -tc_gen_reloc (sec, fixp) - asection *sec ATTRIBUTE_UNUSED; - fixS *fixp; -{ - arelent *reloc; - - reloc = (arelent *) xmalloc (sizeof (arelent)); - reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); - *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); - reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; - - /* Make sure none of our internal relocations make it this far. - They'd better have been fully resolved by this point. */ - assert ((int)fixp->fx_r_type > 0); - - reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); - if (reloc->howto == NULL) - { - as_bad_where (fixp->fx_file, fixp->fx_line, - _("cannot represent `%s' relocation in object file"), - bfd_get_reloc_code_name (fixp->fx_r_type)); - return NULL; - } - - if (!fixp->fx_pcrel != !reloc->howto->pc_relative) - { - as_fatal (_("internal error? cannot generate `%s' relocation"), - bfd_get_reloc_code_name (fixp->fx_r_type)); - } - assert (!fixp->fx_pcrel == !reloc->howto->pc_relative); - -#ifdef OBJ_ECOFF - if (fixp->fx_r_type == BFD_RELOC_ALPHA_LITERAL) - { - /* fake out bfd_perform_relocation. sigh */ - reloc->addend = -alpha_gp_value; - } - else -#endif - { - reloc->addend = fixp->fx_offset; -#ifdef OBJ_ELF - /* - * Ohhh, this is ugly. The problem is that if this is a local global - * symbol, the relocation will entirely be performed at link time, not - * at assembly time. bfd_perform_reloc doesn't know about this sort - * of thing, and as a result we need to fake it out here. - */ - if ((S_IS_EXTERN (fixp->fx_addsy) || S_IS_WEAK (fixp->fx_addsy)) - && !S_IS_COMMON(fixp->fx_addsy)) - reloc->addend -= symbol_get_bfdsym (fixp->fx_addsy)->value; -#endif - } - - return reloc; -} - -/* Parse a register name off of the input_line and return a register - number. Gets md_undefined_symbol above to do the register name - matching for us. - - Only called as a part of processing the ECOFF .frame directive. */ - -int -tc_get_register (frame) - int frame ATTRIBUTE_UNUSED; -{ - int framereg = AXP_REG_SP; - - SKIP_WHITESPACE (); - if (*input_line_pointer == '$') - { - char *s = input_line_pointer; - char c = get_symbol_end (); - symbolS *sym = md_undefined_symbol (s); - - *strchr(s, '\0') = c; - if (sym && (framereg = S_GET_VALUE (sym)) <= 31) - goto found; - } - as_warn (_("frame reg expected, using $%d."), framereg); - -found: - note_gpreg (framereg); - return framereg; -} - -/* This is called before the symbol table is processed. In order to - work with gcc when using mips-tfile, we must keep all local labels. - However, in other cases, we want to discard them. If we were - called with -g, but we didn't see any debugging information, it may - mean that gcc is smuggling debugging information through to - mips-tfile, in which case we must generate all local labels. */ - -#ifdef OBJ_ECOFF - -void -alpha_frob_file_before_adjust () -{ - if (alpha_debug != 0 - && ! ecoff_debugging_seen) - flag_keep_locals = 1; -} - -#endif /* OBJ_ECOFF */ - -#ifdef RELOC_OP_P - -/* Before the relocations are written, reorder them, so that user supplied - !lituse relocations follow the appropriate !literal relocations. Also - convert the gas-internal relocations to the appropriate linker relocations. - */ - -void -alpha_adjust_symtab () -{ - if (alpha_literal_hash) - { -#ifdef DEBUG2_ALPHA - fprintf (stderr, "alpha_adjust_symtab called\n"); -#endif - - /* Go over each section, reordering the relocations so that all of the - explicit LITUSE's are adjacent to the explicit LITERAL's */ - bfd_map_over_sections (stdoutput, alpha_adjust_symtab_relocs, (char *) 0); - } -} - - -/* Inner function to move LITUSE's next to the LITERAL. */ - -static void -alpha_adjust_symtab_relocs (abfd, sec, ptr) - bfd *abfd; - asection *sec; - PTR ptr; -{ - segment_info_type *seginfo = seg_info (sec); - fixS **prevP; - fixS *fixp; - fixS *next; - fixS *lituse; - int n_lituses = 0; - -#ifdef DEBUG2_ALPHA - int n = 0; - int n_literals = 0; - int n_dup_literals = 0; -#endif - - /* If seginfo is NULL, we did not create this section; don't do anything with - it. By using a pointer to a pointer, we can update the links in place. */ - if (seginfo == NULL) - return; - - /* If there are no relocations, skip the section. */ - if (! seginfo->fix_root) - return; - - /* First rebuild the fixup chain without the expicit lituse's. */ - prevP = &(seginfo->fix_root); - for (fixp = seginfo->fix_root; fixp; fixp = next) - { - next = fixp->fx_next; - fixp->fx_next = (fixS *)0; -#ifdef DEBUG2_ALPHA - n++; -#endif - - switch (fixp->fx_r_type) - { - default: - *prevP = fixp; - prevP = &(fixp->fx_next); -#ifdef DEBUG2_ALPHA - fprintf (stderr, - "alpha_adjust_symtab_relocs: 0x%lx, other relocation %s\n", - (long)fixp, - bfd_get_reloc_code_name (fixp->fx_r_type)); -#endif - break; - - case BFD_RELOC_ALPHA_USER_LITERAL: - *prevP = fixp; - prevP = &(fixp->fx_next); - /* prevent assembler from trying to adjust the offset */ -#ifdef DEBUG2_ALPHA - n_literals++; - if (fixp->tc_fix_data.info->n_literals != 1) - n_dup_literals++; - fprintf (stderr, - "alpha_adjust_symtab_relocs: 0x%lx, !literal!%.6d, # literals = %2d\n", - (long)fixp, - fixp->tc_fix_data.info->sequence, - fixp->tc_fix_data.info->n_literals); -#endif - break; - - /* do not link in lituse's */ - case BFD_RELOC_ALPHA_USER_LITUSE_BASE: - case BFD_RELOC_ALPHA_USER_LITUSE_BYTOFF: - case BFD_RELOC_ALPHA_USER_LITUSE_JSR: - n_lituses++; - if (fixp->tc_fix_data.info->n_literals == 0) - as_bad_where (fixp->fx_file, fixp->fx_line, - _("No !literal!%d was found"), - fixp->tc_fix_data.info->sequence); -#ifdef DEBUG2_ALPHA - fprintf (stderr, - "alpha_adjust_symtab_relocs: 0x%lx, !lituse !%.6d, # lituses = %2d, next_lituse = 0x%lx\n", - (long)fixp, - fixp->tc_fix_data.info->sequence, - fixp->tc_fix_data.info->n_lituses, - (long)fixp->tc_fix_data.next_lituse); -#endif - break; - } - } - - /* If there were any lituses, go and add them to the chain, unless there is - more than one !literal for a given sequence number. They are linked - through the next_lituse field in reverse order, so as we go through the - next_lituse chain, we effectively reverse the chain once again. If there - was more than one !literal, we fall back to loading up the address w/o - optimization. Also, if the !literals/!lituses are spread in different - segments (happens in the Linux kernel semaphores), suppress the - optimization. */ - if (n_lituses) - { - for (fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next) - { - switch (fixp->fx_r_type) - { - default: - break; - - case BFD_RELOC_ALPHA_USER_LITERAL: -#ifdef OBJ_ELF - fixp->fx_r_type = BFD_RELOC_ALPHA_ELF_LITERAL; -#else - fixp->fx_r_type = BFD_RELOC_ALPHA_LITERAL; /* XXX check this */ -#endif - if (fixp->tc_fix_data.info->n_literals == 1 - && ! fixp->tc_fix_data.info->multi_section_p) - { - for (lituse = fixp->tc_fix_data.info->lituse; - lituse != (fixS *)0; - lituse = lituse->tc_fix_data.next_lituse) - { - lituse->fx_next = fixp->fx_next; - fixp->fx_next = lituse; - } - } - break; - - case BFD_RELOC_ALPHA_USER_LITUSE_BASE: - case BFD_RELOC_ALPHA_USER_LITUSE_BYTOFF: - case BFD_RELOC_ALPHA_USER_LITUSE_JSR: - fixp->fx_r_type = BFD_RELOC_ALPHA_LITUSE; - break; - } - } - } - -#ifdef DEBUG2_ALPHA - fprintf (stderr, "alpha_adjust_symtab_relocs: %s, %d literal%s, %d duplicate literal%s, %d lituse%s\n\n", - sec->name, - n_literals, (n_literals == 1) ? "" : "s", - n_dup_literals, (n_dup_literals == 1) ? "" : "s", - n_lituses, (n_lituses == 1) ? "" : "s"); -#endif -} - -#endif /* RELOC_OP_P */ - - -#ifdef DEBUG_ALPHA -static void -debug_exp (tok, ntok) - expressionS tok[]; - int ntok; -{ - int i; - - fprintf (stderr, "debug_exp: %d tokens", ntok); - for (i = 0; i < ntok; i++) - { - expressionS *t = &tok[i]; - const char *name; - switch (t->X_op) - { - default: name = "unknown"; break; - case O_illegal: name = "O_illegal"; break; - case O_absent: name = "O_absent"; break; - case O_constant: name = "O_constant"; break; - case O_symbol: name = "O_symbol"; break; - case O_symbol_rva: name = "O_symbol_rva"; break; - case O_register: name = "O_register"; break; - case O_big: name = "O_big"; break; - case O_uminus: name = "O_uminus"; break; - case O_bit_not: name = "O_bit_not"; break; - case O_logical_not: name = "O_logical_not"; break; - case O_multiply: name = "O_multiply"; break; - case O_divide: name = "O_divide"; break; - case O_modulus: name = "O_modulus"; break; - case O_left_shift: name = "O_left_shift"; break; - case O_right_shift: name = "O_right_shift"; break; - case O_bit_inclusive_or: name = "O_bit_inclusive_or"; break; - case O_bit_or_not: name = "O_bit_or_not"; break; - case O_bit_exclusive_or: name = "O_bit_exclusive_or"; break; - case O_bit_and: name = "O_bit_and"; break; - case O_add: name = "O_add"; break; - case O_subtract: name = "O_subtract"; break; - case O_eq: name = "O_eq"; break; - case O_ne: name = "O_ne"; break; - case O_lt: name = "O_lt"; break; - case O_le: name = "O_le"; break; - case O_ge: name = "O_ge"; break; - case O_gt: name = "O_gt"; break; - case O_logical_and: name = "O_logical_and"; break; - case O_logical_or: name = "O_logical_or"; break; - case O_index: name = "O_index"; break; - case O_pregister: name = "O_pregister"; break; - case O_cpregister: name = "O_cpregister"; break; - case O_literal: name = "O_literal"; break; - case O_lituse_base: name = "O_lituse_base"; break; - case O_lituse_bytoff: name = "O_lituse_bytoff"; break; - case O_lituse_jsr: name = "O_lituse_jsr"; break; - case O_gpdisp: name = "O_gpdisp"; break; - case O_gprelhigh: name = "O_gprelhigh"; break; - case O_gprellow: name = "O_gprellow"; break; - case O_md10: name = "O_md10"; break; - case O_md11: name = "O_md11"; break; - case O_md12: name = "O_md12"; break; - case O_md13: name = "O_md13"; break; - case O_md14: name = "O_md14"; break; - case O_md15: name = "O_md15"; break; - case O_md16: name = "O_md16"; break; - } - - fprintf (stderr, ", %s(%s, %s, %d)", name, - (t->X_add_symbol) ? S_GET_NAME (t->X_add_symbol) : "--", - (t->X_op_symbol) ? S_GET_NAME (t->X_op_symbol) : "--", - (int)t->X_add_number); - } - fprintf (stderr, "\n"); - fflush (stderr); -} -#endif - -/* Parse the arguments to an opcode. */ - -static int -tokenize_arguments (str, tok, ntok) - char *str; - expressionS tok[]; - int ntok; -{ - expressionS *end_tok = tok + ntok; - char *old_input_line_pointer; - int saw_comma = 0, saw_arg = 0; -#ifdef DEBUG_ALPHA - expressionS *orig_tok = tok; -#endif -#ifdef RELOC_OP_P - char *p; - const struct alpha_reloc_op_tag *r; - int c, i; - size_t len; - int reloc_found_p = 0; -#endif - - memset (tok, 0, sizeof (*tok) * ntok); - - /* Save and restore input_line_pointer around this function */ - old_input_line_pointer = input_line_pointer; - input_line_pointer = str; - - while (tok < end_tok && *input_line_pointer) - { - SKIP_WHITESPACE (); - switch (*input_line_pointer) - { - case '\0': - goto fini; - -#ifdef RELOC_OP_P - case '!': - /* A relocation operand can be placed after the normal operand on an - assembly language statement, and has the following form: - !relocation_type!sequence_number. */ - if (reloc_found_p) - { /* only support one relocation op per insn */ - as_bad (_("More than one relocation op per insn")); - goto err_report; - } - - if (!saw_arg) - goto err; - - for (p = ++input_line_pointer; - ((c = *p) != '!' && c != ';' && c != '#' && c != ',' - && !is_end_of_line[c]); - p++) - ; - - /* Parse !relocation_type */ - len = p - input_line_pointer; - if (len == 0) - { - as_bad (_("No relocation operand")); - goto err_report; - } - - if (c != '!') - { - as_bad (_("No !sequence-number after !%s"), input_line_pointer); - goto err_report; - } - - r = &alpha_reloc_op[0]; - for (i = alpha_num_reloc_op-1; i >= 0; i--, r++) - { - if (len == r->length - && memcmp (input_line_pointer, r->name, len) == 0) - break; - } - if (i < 0) - { - as_bad (_("Unknown relocation operand: !%s"), input_line_pointer); - goto err_report; - } - - input_line_pointer = ++p; - - /* Parse !sequence_number */ - memset (tok, '\0', sizeof (expressionS)); - expression (tok); - - if (tok->X_op != O_constant - || ! ALPHA_RELOC_SEQUENCE_OK (tok->X_add_number)) - { - as_bad (_("Bad sequence number: !%s!%s"), r->name, input_line_pointer); - goto err_report; - } - - tok->X_op = r->op; - reloc_found_p = 1; - ++tok; - break; -#endif - - case ',': - ++input_line_pointer; - if (saw_comma || !saw_arg) - goto err; - saw_comma = 1; - break; - - case '(': - { - char *hold = input_line_pointer++; - - /* First try for parenthesized register ... */ - expression (tok); - if (*input_line_pointer == ')' && tok->X_op == O_register) - { - tok->X_op = (saw_comma ? O_cpregister : O_pregister); - saw_comma = 0; - saw_arg = 1; - ++input_line_pointer; - ++tok; - break; - } - - /* ... then fall through to plain expression */ - input_line_pointer = hold; - } - - default: - if (saw_arg && !saw_comma) - goto err; - - expression (tok); - if (tok->X_op == O_illegal || tok->X_op == O_absent) - goto err; - - saw_comma = 0; - saw_arg = 1; - ++tok; - break; - } - } - -fini: - if (saw_comma) - goto err; - input_line_pointer = old_input_line_pointer; - -#ifdef DEBUG_ALPHA - debug_exp (orig_tok, ntok - (end_tok - tok)); -#endif - - return ntok - (end_tok - tok); - -err: - input_line_pointer = old_input_line_pointer; - return TOKENIZE_ERROR; - -#ifdef RELOC_OP_P -err_report: - input_line_pointer = old_input_line_pointer; - return TOKENIZE_ERROR_REPORT; -#endif -} - -/* Search forward through all variants of an opcode looking for a - syntax match. */ - -static const struct alpha_opcode * -find_opcode_match(first_opcode, tok, pntok, pcpumatch) - const struct alpha_opcode *first_opcode; - const expressionS *tok; - int *pntok; - int *pcpumatch; -{ - const struct alpha_opcode *opcode = first_opcode; - int ntok = *pntok; - int got_cpu_match = 0; - - do - { - const unsigned char *opidx; - int tokidx = 0; - - /* Don't match opcodes that don't exist on this architecture */ - if (!(opcode->flags & alpha_target)) - goto match_failed; - - got_cpu_match = 1; - - for (opidx = opcode->operands; *opidx; ++opidx) - { - const struct alpha_operand *operand = &alpha_operands[*opidx]; - - /* only take input from real operands */ - if (operand->flags & AXP_OPERAND_FAKE) - continue; - - /* when we expect input, make sure we have it */ - if (tokidx >= ntok) - { - if ((operand->flags & AXP_OPERAND_OPTIONAL_MASK) == 0) - goto match_failed; - continue; - } - - /* match operand type with expression type */ - switch (operand->flags & AXP_OPERAND_TYPECHECK_MASK) - { - case AXP_OPERAND_IR: - if (tok[tokidx].X_op != O_register - || !is_ir_num(tok[tokidx].X_add_number)) - goto match_failed; - break; - case AXP_OPERAND_FPR: - if (tok[tokidx].X_op != O_register - || !is_fpr_num(tok[tokidx].X_add_number)) - goto match_failed; - break; - case AXP_OPERAND_IR|AXP_OPERAND_PARENS: - if (tok[tokidx].X_op != O_pregister - || !is_ir_num(tok[tokidx].X_add_number)) - goto match_failed; - break; - case AXP_OPERAND_IR|AXP_OPERAND_PARENS|AXP_OPERAND_COMMA: - if (tok[tokidx].X_op != O_cpregister - || !is_ir_num(tok[tokidx].X_add_number)) - goto match_failed; - break; - - case AXP_OPERAND_RELATIVE: - case AXP_OPERAND_SIGNED: - case AXP_OPERAND_UNSIGNED: - switch (tok[tokidx].X_op) - { - case O_illegal: - case O_absent: - case O_register: - case O_pregister: - case O_cpregister: - goto match_failed; - - default: - break; - } - break; - - default: - /* everything else should have been fake */ - abort(); - } - ++tokidx; - } - - /* possible match -- did we use all of our input? */ - if (tokidx == ntok) - { - *pntok = ntok; - return opcode; - } - - match_failed:; - } - while (++opcode-alpha_opcodes < alpha_num_opcodes - && !strcmp(opcode->name, first_opcode->name)); - - if (*pcpumatch) - *pcpumatch = got_cpu_match; - - return NULL; -} - -/* Search forward through all variants of a macro looking for a syntax - match. */ - -static const struct alpha_macro * -find_macro_match(first_macro, tok, pntok) - const struct alpha_macro *first_macro; - const expressionS *tok; - int *pntok; -{ - const struct alpha_macro *macro = first_macro; - int ntok = *pntok; - - do - { - const enum alpha_macro_arg *arg = macro->argsets; - int tokidx = 0; - - while (*arg) - { - switch (*arg) - { - case MACRO_EOA: - if (tokidx == ntok) - return macro; - else - tokidx = 0; - break; - - /* index register */ - case MACRO_IR: - if (tokidx >= ntok || tok[tokidx].X_op != O_register - || !is_ir_num(tok[tokidx].X_add_number)) - goto match_failed; - ++tokidx; - break; - - /* parenthesized index register */ - case MACRO_PIR: - if (tokidx >= ntok || tok[tokidx].X_op != O_pregister - || !is_ir_num(tok[tokidx].X_add_number)) - goto match_failed; - ++tokidx; - break; - - /* optional parenthesized index register */ - case MACRO_OPIR: - if (tokidx < ntok && tok[tokidx].X_op == O_pregister - && is_ir_num(tok[tokidx].X_add_number)) - ++tokidx; - break; - - /* leading comma with a parenthesized index register */ - case MACRO_CPIR: - if (tokidx >= ntok || tok[tokidx].X_op != O_cpregister - || !is_ir_num(tok[tokidx].X_add_number)) - goto match_failed; - ++tokidx; - break; - - /* floating point register */ - case MACRO_FPR: - if (tokidx >= ntok || tok[tokidx].X_op != O_register - || !is_fpr_num(tok[tokidx].X_add_number)) - goto match_failed; - ++tokidx; - break; - - /* normal expression */ - case MACRO_EXP: - if (tokidx >= ntok) - goto match_failed; - switch (tok[tokidx].X_op) - { - case O_illegal: - case O_absent: - case O_register: - case O_pregister: - case O_cpregister: -#ifdef RELOC_OP_P - case O_literal: - case O_lituse_base: - case O_lituse_bytoff: - case O_lituse_jsr: - case O_gpdisp: - case O_gprelhigh: - case O_gprellow: -#endif - goto match_failed; - - default: - break; - } - ++tokidx; - break; - - /* optional !literal!<number> */ - case MACRO_LITERAL: -#ifdef RELOC_OP_P - if (tokidx < ntok && tok[tokidx].X_op == O_literal) - tokidx++; -#endif - break; - - /* optional !lituse_base!<number> */ - case MACRO_BASE: -#ifdef RELOC_OP_P - if (tokidx < ntok && tok[tokidx].X_op == O_lituse_base) - tokidx++; -#endif - break; - - /* optional !lituse_bytoff!<number> */ - case MACRO_BYTOFF: -#ifdef RELOC_OP_P - if (tokidx < ntok && tok[tokidx].X_op == O_lituse_bytoff) - tokidx++; -#endif - break; - - /* optional !lituse_jsr!<number> */ - case MACRO_JSR: -#ifdef RELOC_OP_P - if (tokidx < ntok && tok[tokidx].X_op == O_lituse_jsr) - tokidx++; -#endif - break; - - match_failed: - while (*arg != MACRO_EOA) - ++arg; - tokidx = 0; - break; - } - ++arg; - } - } - while (++macro-alpha_macros < alpha_num_macros - && !strcmp(macro->name, first_macro->name)); - - return NULL; -} - -/* Insert an operand value into an instruction. */ - -static unsigned -insert_operand(insn, operand, val, file, line) - unsigned insn; - const struct alpha_operand *operand; - offsetT val; - char *file; - unsigned line; -{ - if (operand->bits != 32 && !(operand->flags & AXP_OPERAND_NOOVERFLOW)) - { - offsetT min, max; - - if (operand->flags & AXP_OPERAND_SIGNED) - { - max = (1 << (operand->bits - 1)) - 1; - min = -(1 << (operand->bits - 1)); - } - else - { - max = (1 << operand->bits) - 1; - min = 0; - } - - if (val < min || val > max) - { - const char *err = - _("operand out of range (%s not between %d and %d)"); - char buf[sizeof (val) * 3 + 2]; - - sprint_value(buf, val); - if (file) - as_warn_where(file, line, err, buf, min, max); - else - as_warn(err, buf, min, max); - } - } - - if (operand->insert) - { - const char *errmsg = NULL; - - insn = (*operand->insert) (insn, val, &errmsg); - if (errmsg) - as_warn (errmsg); - } - else - insn |= ((val & ((1 << operand->bits) - 1)) << operand->shift); - - return insn; -} - -/* - * Turn an opcode description and a set of arguments into - * an instruction and a fixup. - */ - -static void -assemble_insn(opcode, tok, ntok, insn) - const struct alpha_opcode *opcode; - const expressionS *tok; - int ntok; - struct alpha_insn *insn; -{ - const unsigned char *argidx; - unsigned image; - int tokidx = 0; - - memset (insn, 0, sizeof (*insn)); - image = opcode->opcode; - - for (argidx = opcode->operands; *argidx; ++argidx) - { - const struct alpha_operand *operand = &alpha_operands[*argidx]; - const expressionS *t = (const expressionS *)0; - - if (operand->flags & AXP_OPERAND_FAKE) - { - /* fake operands take no value and generate no fixup */ - image = insert_operand(image, operand, 0, NULL, 0); - continue; - } - - if (tokidx >= ntok) - { - switch (operand->flags & AXP_OPERAND_OPTIONAL_MASK) - { - case AXP_OPERAND_DEFAULT_FIRST: - t = &tok[0]; - break; - case AXP_OPERAND_DEFAULT_SECOND: - t = &tok[1]; - break; - case AXP_OPERAND_DEFAULT_ZERO: - { - static expressionS zero_exp; - t = &zero_exp; - zero_exp.X_op = O_constant; - zero_exp.X_unsigned = 1; - } - break; - default: - abort(); - } - } - else - t = &tok[tokidx++]; - - switch (t->X_op) - { - case O_register: - case O_pregister: - case O_cpregister: - image = insert_operand(image, operand, regno(t->X_add_number), - NULL, 0); - break; - - case O_constant: - image = insert_operand(image, operand, t->X_add_number, NULL, 0); - break; - - default: - { - struct alpha_fixup *fixup; - - if (insn->nfixups >= MAX_INSN_FIXUPS) - as_fatal(_("too many fixups")); - - fixup = &insn->fixups[insn->nfixups++]; - - fixup->exp = *t; - fixup->reloc = operand->default_reloc; - } - break; - } - } - - insn->insn = image; -} - -/* - * Actually output an instruction with its fixup. - */ - -static void -emit_insn (insn) - struct alpha_insn *insn; -{ - char *f; - int i; - - /* Take care of alignment duties */ - if (alpha_auto_align_on && alpha_current_align < 2) - alpha_align (2, (char *) NULL, alpha_insn_label, 0); - if (alpha_current_align > 2) - alpha_current_align = 2; - alpha_insn_label = NULL; - - /* Write out the instruction. */ - f = frag_more (4); - md_number_to_chars (f, insn->insn, 4); - - /* Apply the fixups in order */ - for (i = 0; i < insn->nfixups; ++i) - { - const struct alpha_operand *operand = (const struct alpha_operand *)0; - struct alpha_fixup *fixup = &insn->fixups[i]; - int size, pcrel; - fixS *fixP; -#ifdef RELOC_OP_P - char buffer[ALPHA_RELOC_DIGITS]; - struct alpha_literal_tag *info; -#endif - - /* Some fixups are only used internally and so have no howto */ - if ((int)fixup->reloc < 0) - { - operand = &alpha_operands[-(int)fixup->reloc]; - size = 4; - pcrel = ((operand->flags & AXP_OPERAND_RELATIVE) != 0); - } - else switch (fixup->reloc) - { -#ifdef OBJ_ELF - /* These relocation types are only used internally. */ - case BFD_RELOC_ALPHA_GPDISP_HI16: - case BFD_RELOC_ALPHA_GPDISP_LO16: - size = 2; - pcrel = 0; - break; -#endif -#ifdef RELOC_OP_P - /* and these also are internal only relocations */ - case BFD_RELOC_ALPHA_USER_LITERAL: - case BFD_RELOC_ALPHA_USER_LITUSE_BASE: - case BFD_RELOC_ALPHA_USER_LITUSE_BYTOFF: - case BFD_RELOC_ALPHA_USER_LITUSE_JSR: - case BFD_RELOC_ALPHA_USER_GPDISP: - case BFD_RELOC_ALPHA_USER_GPRELHIGH: - case BFD_RELOC_ALPHA_USER_GPRELLOW: - size = 2; - pcrel = 0; - break; -#endif - - default: - { - reloc_howto_type *reloc_howto - = bfd_reloc_type_lookup (stdoutput, fixup->reloc); - assert (reloc_howto); - - size = bfd_get_reloc_size (reloc_howto); - pcrel = reloc_howto->pc_relative; - } - assert (size >= 1 && size <= 4); - break; - } - - fixP = fix_new_exp (frag_now, f - frag_now->fr_literal, size, - &fixup->exp, pcrel, fixup->reloc); - - /* Turn off complaints that the addend is too large for some fixups, - and copy in the sequence number for the explicit relocations. */ - switch (fixup->reloc) - { - case BFD_RELOC_ALPHA_GPDISP_LO16: -#ifdef OBJ_ECOFF - case BFD_RELOC_ALPHA_LITERAL: -#endif -#ifdef OBJ_ELF - case BFD_RELOC_ALPHA_ELF_LITERAL: -#endif - case BFD_RELOC_GPREL32: - fixP->fx_no_overflow = 1; - break; - -#ifdef RELOC_OP_P - case BFD_RELOC_ALPHA_USER_LITERAL: - fixP->fx_no_overflow = 1; - sprintf (buffer, "!%u", insn->sequence[i]); - info = ((struct alpha_literal_tag *) - hash_find (alpha_literal_hash, buffer)); - - if (! info) - { - size_t len = strlen (buffer); - const char *errmsg; - - info = ((struct alpha_literal_tag *) - xcalloc (sizeof (struct alpha_literal_tag) + len, 1)); - - info->segment = now_seg; - info->sequence = insn->sequence[i]; - strcpy (info->string, buffer); - errmsg = hash_insert (alpha_literal_hash, info->string, (PTR)info); - if (errmsg) - as_bad (errmsg); - } - - ++info->n_literals; - - if (info->segment != now_seg) - info->multi_section_p = 1; - - fixP->tc_fix_data.info = info; - break; - - case BFD_RELOC_ALPHA_USER_LITUSE_BASE: - case BFD_RELOC_ALPHA_USER_LITUSE_BYTOFF: - case BFD_RELOC_ALPHA_USER_LITUSE_JSR: - sprintf (buffer, "!%u", insn->sequence[i]); - info = ((struct alpha_literal_tag *) - hash_find (alpha_literal_hash, buffer)); - - if (! info) - { - size_t len = strlen (buffer); - const char *errmsg; - - info = ((struct alpha_literal_tag *) - xcalloc (sizeof (struct alpha_literal_tag) + len, 1)); - - info->segment = now_seg; - info->sequence = insn->sequence[i]; - strcpy (info->string, buffer); - errmsg = hash_insert (alpha_literal_hash, info->string, (PTR)info); - if (errmsg) - as_bad (errmsg); - } - info->n_lituses++; - fixP->tc_fix_data.info = info; - fixP->tc_fix_data.next_lituse = info->lituse; - info->lituse = fixP; - if (info->segment != now_seg) - info->multi_section_p = 1; - - break; -#endif - - default: - if ((int)fixup->reloc < 0) - { - if (operand->flags & AXP_OPERAND_NOOVERFLOW) - fixP->fx_no_overflow = 1; - } - break; - } - } -} - -/* Given an opcode name and a pre-tokenized set of arguments, assemble - the insn, but do not emit it. - - Note that this implies no macros allowed, since we can't store more - than one insn in an insn structure. */ - -static void -assemble_tokens_to_insn(opname, tok, ntok, insn) - const char *opname; - const expressionS *tok; - int ntok; - struct alpha_insn *insn; -{ - const struct alpha_opcode *opcode; - - /* search opcodes */ - opcode = (const struct alpha_opcode *) hash_find (alpha_opcode_hash, opname); - if (opcode) - { - int cpumatch; - opcode = find_opcode_match (opcode, tok, &ntok, &cpumatch); - if (opcode) - { - assemble_insn (opcode, tok, ntok, insn); - return; - } - else if (cpumatch) - as_bad (_("inappropriate arguments for opcode `%s'"), opname); - else - as_bad (_("opcode `%s' not supported for target %s"), opname, - alpha_target_name); - } - else - as_bad (_("unknown opcode `%s'"), opname); -} - -/* Given an opcode name and a pre-tokenized set of arguments, take the - opcode all the way through emission. */ - -static void -assemble_tokens (opname, tok, ntok, local_macros_on) - const char *opname; - const expressionS *tok; - int ntok; - int local_macros_on; -{ - int found_something = 0; - const struct alpha_opcode *opcode; - const struct alpha_macro *macro; - int cpumatch = 1; - - /* search macros */ - if (local_macros_on) - { - macro = ((const struct alpha_macro *) - hash_find (alpha_macro_hash, opname)); - if (macro) - { - found_something = 1; - macro = find_macro_match (macro, tok, &ntok); - if (macro) - { - (*macro->emit) (tok, ntok, macro->arg); - return; - } - } - } - -#ifdef RELOC_OP_P - if (ntok && USER_RELOC_P (tok[ntok-1].X_op)) - { - const expressionS *reloc_exp = &tok[ntok-1]; - const struct alpha_reloc_op_tag *r = ALPHA_RELOC_TABLE (reloc_exp->X_op); - as_bad (_("Cannot use !%s!%d with %s"), r->name, - (int)reloc_exp->X_add_number, opname); - ntok--; - } -#endif - - /* search opcodes */ - opcode = (const struct alpha_opcode *) hash_find (alpha_opcode_hash, opname); - if (opcode) - { - found_something = 1; - opcode = find_opcode_match (opcode, tok, &ntok, &cpumatch); - if (opcode) - { - struct alpha_insn insn; - assemble_insn (opcode, tok, ntok, &insn); - emit_insn (&insn); - return; - } - } - - if (found_something) - if (cpumatch) - as_bad (_("inappropriate arguments for opcode `%s'"), opname); - else - as_bad (_("opcode `%s' not supported for target %s"), opname, - alpha_target_name); - else - as_bad (_("unknown opcode `%s'"), opname); -} - - -/* Some instruction sets indexed by lg(size) */ -static const char * const sextX_op[] = { "sextb", "sextw", "sextl", NULL }; -static const char * const insXl_op[] = { "insbl", "inswl", "insll", "insql" }; -static const char * const insXh_op[] = { NULL, "inswh", "inslh", "insqh" }; -static const char * const extXl_op[] = { "extbl", "extwl", "extll", "extql" }; -static const char * const extXh_op[] = { NULL, "extwh", "extlh", "extqh" }; -static const char * const mskXl_op[] = { "mskbl", "mskwl", "mskll", "mskql" }; -static const char * const mskXh_op[] = { NULL, "mskwh", "msklh", "mskqh" }; -static const char * const stX_op[] = { "stb", "stw", "stl", "stq" }; -static const char * const ldX_op[] = { "ldb", "ldw", "ldll", "ldq" }; -static const char * const ldXu_op[] = { "ldbu", "ldwu", NULL, NULL }; - -/* Implement the ldgp macro. */ - -static void -emit_ldgp (tok, ntok, unused) - const expressionS *tok; - int ntok ATTRIBUTE_UNUSED; - const PTR unused ATTRIBUTE_UNUSED; -{ -#ifdef OBJ_AOUT -FIXME -#endif -#if defined(OBJ_ECOFF) || defined(OBJ_ELF) - /* from "ldgp r1,n(r2)", generate "ldah r1,X(R2); lda r1,Y(r1)" - with appropriate constants and relocations. */ - struct alpha_insn insn; - expressionS newtok[3]; - expressionS addend; - -#ifdef RELOC_OP_P - if (ntok && USER_RELOC_P (tok[ntok-1].X_op)) - { - const expressionS *reloc_exp = &tok[ntok-1]; - const struct alpha_reloc_op_tag *r = ALPHA_RELOC_TABLE (reloc_exp->X_op); - as_bad (_("Cannot use !%s!%d with %s"), r->name, - (int)reloc_exp->X_add_number, "ldgp"); - ntok--; - } -#endif - -#ifdef OBJ_ECOFF - if (regno (tok[2].X_add_number) == AXP_REG_PV) - ecoff_set_gp_prolog_size (0); -#endif - - newtok[0] = tok[0]; - set_tok_const (newtok[1], 0); - newtok[2] = tok[2]; - - assemble_tokens_to_insn ("ldah", newtok, 3, &insn); - - addend = tok[1]; - -#ifdef OBJ_ECOFF - if (addend.X_op != O_constant) - as_bad (_("can not resolve expression")); - addend.X_op = O_symbol; - addend.X_add_symbol = alpha_gp_symbol; -#endif - - insn.nfixups = 1; - insn.fixups[0].exp = addend; - insn.fixups[0].reloc = BFD_RELOC_ALPHA_GPDISP_HI16; - - emit_insn (&insn); - - set_tok_preg (newtok[2], tok[0].X_add_number); - - assemble_tokens_to_insn ("lda", newtok, 3, &insn); - -#ifdef OBJ_ECOFF - addend.X_add_number += 4; -#endif - - insn.nfixups = 1; - insn.fixups[0].exp = addend; - insn.fixups[0].reloc = BFD_RELOC_ALPHA_GPDISP_LO16; - - emit_insn (&insn); -#endif /* OBJ_ECOFF || OBJ_ELF */ -} - -#ifdef OBJ_EVAX - -/* Add symbol+addend to link pool. - Return offset from basesym to entry in link pool. - - Add new fixup only if offset isn't 16bit. */ - -valueT -add_to_link_pool (basesym, sym, addend) - symbolS *basesym; - symbolS *sym; - offsetT addend; -{ - segT current_section = now_seg; - int current_subsec = now_subseg; - valueT offset; - bfd_reloc_code_real_type reloc_type; - char *p; - segment_info_type *seginfo = seg_info (alpha_link_section); - fixS *fixp; - - offset = - *symbol_get_obj (basesym); - - /* @@ This assumes all entries in a given section will be of the same - size... Probably correct, but unwise to rely on. */ - /* This must always be called with the same subsegment. */ - - if (seginfo->frchainP) - for (fixp = seginfo->frchainP->fix_root; - fixp != (fixS *) NULL; - fixp = fixp->fx_next, offset += 8) - { - if (fixp->fx_addsy == sym && fixp->fx_offset == addend) - { - if (range_signed_16 (offset)) - { - return offset; - } - } - } - - /* Not found in 16bit signed range. */ - - subseg_set (alpha_link_section, 0); - p = frag_more (8); - memset (p, 0, 8); - - fix_new (frag_now, p - frag_now->fr_literal, 8, sym, addend, 0, - BFD_RELOC_64); - - subseg_set (current_section, current_subsec); - seginfo->literal_pool_size += 8; - return offset; -} - -#endif /* OBJ_EVAX */ - -/* Load a (partial) expression into a target register. - - If poffset is not null, after the call it will either contain - O_constant 0, or a 16-bit offset appropriate for any MEM format - instruction. In addition, pbasereg will be modified to point to - the base register to use in that MEM format instruction. - - In any case, *pbasereg should contain a base register to add to the - expression. This will normally be either AXP_REG_ZERO or - alpha_gp_register. Symbol addresses will always be loaded via $gp, - so "foo($0)" is interpreted as adding the address of foo to $0; - i.e. "ldq $targ, LIT($gp); addq $targ, $0, $targ". Odd, perhaps, - but this is what OSF/1 does. - - If explicit relocations of the form !literal!<number> are allowed, - and used, then explict_reloc with be an expression pointer. - - Finally, the return value is true if the calling macro may emit a - LITUSE reloc if otherwise appropriate. */ - -static int -load_expression (targreg, exp, pbasereg, poffset, explicit_reloc) - int targreg; - const expressionS *exp; - int *pbasereg; - expressionS *poffset; - const expressionS *explicit_reloc; -{ - int emit_lituse = 0; - offsetT addend = exp->X_add_number; - int basereg = *pbasereg; - struct alpha_insn insn; - expressionS newtok[3]; - - switch (exp->X_op) - { - case O_symbol: - { -#ifdef OBJ_ECOFF - offsetT lit; - - /* attempt to reduce .lit load by splitting the offset from - its symbol when possible, but don't create a situation in - which we'd fail. */ - if (!range_signed_32 (addend) && - (alpha_noat_on || targreg == AXP_REG_AT)) - { - lit = add_to_literal_pool (exp->X_add_symbol, addend, - alpha_lita_section, 8); - addend = 0; - } - else - { - lit = add_to_literal_pool (exp->X_add_symbol, 0, - alpha_lita_section, 8); - } - - if (lit >= 0x8000) - as_fatal (_("overflow in literal (.lita) table")); - - /* emit "ldq r, lit(gp)" */ - - if (basereg != alpha_gp_register && targreg == basereg) - { - if (alpha_noat_on) - as_bad (_("macro requires $at register while noat in effect")); - if (targreg == AXP_REG_AT) - as_bad (_("macro requires $at while $at in use")); - - set_tok_reg (newtok[0], AXP_REG_AT); - } - else - set_tok_reg (newtok[0], targreg); - set_tok_sym (newtok[1], alpha_lita_symbol, lit); - set_tok_preg (newtok[2], alpha_gp_register); - - assemble_tokens_to_insn ("ldq", newtok, 3, &insn); - - assert (explicit_reloc == (const expressionS *)0); - assert (insn.nfixups == 1); - insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITERAL; -#endif /* OBJ_ECOFF */ -#ifdef OBJ_ELF - /* emit "ldq r, gotoff(gp)" */ - - if (basereg != alpha_gp_register && targreg == basereg) - { - if (alpha_noat_on) - as_bad (_("macro requires $at register while noat in effect")); - if (targreg == AXP_REG_AT) - as_bad (_("macro requires $at while $at in use")); - - set_tok_reg (newtok[0], AXP_REG_AT); - } - else - set_tok_reg (newtok[0], targreg); - - /* XXX: Disable this .got minimizing optimization so that we can get - better instruction offset knowledge in the compiler. This happens - very infrequently anyway. */ - if (1 || (!range_signed_32 (addend) - && (alpha_noat_on || targreg == AXP_REG_AT))) - { - newtok[1] = *exp; - addend = 0; - } - else - { - set_tok_sym (newtok[1], exp->X_add_symbol, 0); - } - - set_tok_preg (newtok[2], alpha_gp_register); - - assemble_tokens_to_insn ("ldq", newtok, 3, &insn); - - assert (insn.nfixups == 1); - if (!explicit_reloc) - insn.fixups[0].reloc = BFD_RELOC_ALPHA_ELF_LITERAL; - else - { -#ifdef RELOC_OP_P - insn.fixups[0].reloc - = (ALPHA_RELOC_TABLE (explicit_reloc->X_op))->reloc; - insn.sequence[0] = explicit_reloc->X_add_number; -#else - abort (); -#endif - } -#endif /* OBJ_ELF */ -#ifdef OBJ_EVAX - offsetT link; - - /* Find symbol or symbol pointer in link section. */ - - assert (explicit_reloc == (const expressionS *)0); - if (exp->X_add_symbol == alpha_evax_proc.symbol) - { - if (range_signed_16 (addend)) - { - set_tok_reg (newtok[0], targreg); - set_tok_const (newtok[1], addend); - set_tok_preg (newtok[2], basereg); - assemble_tokens_to_insn ("lda", newtok, 3, &insn); - addend = 0; - } - else - { - set_tok_reg (newtok[0], targreg); - set_tok_const (newtok[1], 0); - set_tok_preg (newtok[2], basereg); - assemble_tokens_to_insn ("lda", newtok, 3, &insn); - } - } - else - { - if (!range_signed_32 (addend)) - { - link = add_to_link_pool (alpha_evax_proc.symbol, - exp->X_add_symbol, addend); - addend = 0; - } - else - { - link = add_to_link_pool (alpha_evax_proc.symbol, - exp->X_add_symbol, 0); - } - set_tok_reg (newtok[0], targreg); - set_tok_const (newtok[1], link); - set_tok_preg (newtok[2], basereg); - assemble_tokens_to_insn ("ldq", newtok, 3, &insn); - } -#endif /* OBJ_EVAX */ - - emit_insn(&insn); - -#ifndef OBJ_EVAX - emit_lituse = 1; - - if (basereg != alpha_gp_register && basereg != AXP_REG_ZERO) - { - /* emit "addq r, base, r" */ - - set_tok_reg (newtok[1], basereg); - set_tok_reg (newtok[2], targreg); - assemble_tokens ("addq", newtok, 3, 0); - } -#endif - - basereg = targreg; - } - break; - - case O_constant: - assert (explicit_reloc == (const expressionS *)0); - break; - - case O_subtract: - /* Assume that this difference expression will be resolved to an - absolute value and that that value will fit in 16 bits. */ - - assert (explicit_reloc == (const expressionS *)0); - set_tok_reg (newtok[0], targreg); - newtok[1] = *exp; - set_tok_preg (newtok[2], basereg); - assemble_tokens ("lda", newtok, 3, 0); - - if (poffset) - set_tok_const (*poffset, 0); - return 0; - - case O_big: - if (exp->X_add_number > 0) - as_bad (_("bignum invalid; zero assumed")); - else - as_bad (_("floating point number invalid; zero assumed")); - addend = 0; - break; - - default: - as_bad (_("can't handle expression")); - addend = 0; - break; - } - - if (!range_signed_32 (addend)) - { - offsetT lit; - - /* for 64-bit addends, just put it in the literal pool */ - -#ifdef OBJ_EVAX - /* emit "ldq targreg, lit(basereg)" */ - lit = add_to_link_pool (alpha_evax_proc.symbol, - section_symbol (absolute_section), addend); - set_tok_reg (newtok[0], targreg); - set_tok_const (newtok[1], lit); - set_tok_preg (newtok[2], alpha_gp_register); - assemble_tokens ("ldq", newtok, 3, 0); -#else - - if (alpha_lit8_section == NULL) - { - create_literal_section (".lit8", - &alpha_lit8_section, - &alpha_lit8_symbol); - -#ifdef OBJ_ECOFF - alpha_lit8_literal = add_to_literal_pool (alpha_lit8_symbol, 0x8000, - alpha_lita_section, 8); - if (alpha_lit8_literal >= 0x8000) - as_fatal (_("overflow in literal (.lita) table")); -#endif - } - - lit = add_to_literal_pool (NULL, addend, alpha_lit8_section, 8) - 0x8000; - if (lit >= 0x8000) - as_fatal (_("overflow in literal (.lit8) table")); - - /* emit "lda litreg, .lit8+0x8000" */ - - if (targreg == basereg) - { - if (alpha_noat_on) - as_bad (_("macro requires $at register while noat in effect")); - if (targreg == AXP_REG_AT) - as_bad (_("macro requires $at while $at in use")); - - set_tok_reg (newtok[0], AXP_REG_AT); - } - else - set_tok_reg (newtok[0], targreg); -#ifdef OBJ_ECOFF - set_tok_sym (newtok[1], alpha_lita_symbol, alpha_lit8_literal); -#endif -#ifdef OBJ_ELF - set_tok_sym (newtok[1], alpha_lit8_symbol, 0x8000); -#endif - set_tok_preg (newtok[2], alpha_gp_register); - - assemble_tokens_to_insn ("ldq", newtok, 3, &insn); - - assert (insn.nfixups == 1); -#ifdef OBJ_ECOFF - insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITERAL; -#endif -#ifdef OBJ_ELF - insn.fixups[0].reloc = BFD_RELOC_ALPHA_ELF_LITERAL; -#endif - - emit_insn (&insn); - - /* emit "ldq litreg, lit(litreg)" */ - - set_tok_const (newtok[1], lit); - set_tok_preg (newtok[2], newtok[0].X_add_number); - - assemble_tokens_to_insn ("ldq", newtok, 3, &insn); - - assert (insn.nfixups < MAX_INSN_FIXUPS); - if (insn.nfixups > 0) - { - memmove (&insn.fixups[1], &insn.fixups[0], - sizeof(struct alpha_fixup) * insn.nfixups); - } - insn.nfixups++; - insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITUSE; - insn.fixups[0].exp.X_op = O_symbol; - insn.fixups[0].exp.X_add_symbol = section_symbol (now_seg); - insn.fixups[0].exp.X_add_number = LITUSE_BASE; - emit_lituse = 0; - - emit_insn (&insn); - - /* emit "addq litreg, base, target" */ - - if (basereg != AXP_REG_ZERO) - { - set_tok_reg (newtok[1], basereg); - set_tok_reg (newtok[2], targreg); - assemble_tokens ("addq", newtok, 3, 0); - } -#endif /* !OBJ_EVAX */ - - if (poffset) - set_tok_const (*poffset, 0); - *pbasereg = targreg; - } - else - { - offsetT low, high, extra, tmp; - - /* for 32-bit operands, break up the addend */ - - low = sign_extend_16 (addend); - tmp = addend - low; - high = sign_extend_16 (tmp >> 16); - - if (tmp - (high << 16)) - { - extra = 0x4000; - tmp -= 0x40000000; - high = sign_extend_16 (tmp >> 16); - } - else - extra = 0; - - set_tok_reg (newtok[0], targreg); - set_tok_preg (newtok[2], basereg); - - if (extra) - { - /* emit "ldah r, extra(r) */ - set_tok_const (newtok[1], extra); - assemble_tokens ("ldah", newtok, 3, 0); - set_tok_preg (newtok[2], basereg = targreg); - } - - if (high) - { - /* emit "ldah r, high(r) */ - set_tok_const (newtok[1], high); - assemble_tokens ("ldah", newtok, 3, 0); - basereg = targreg; - set_tok_preg (newtok[2], basereg); - } - - if ((low && !poffset) || (!poffset && basereg != targreg)) - { - /* emit "lda r, low(base)" */ - set_tok_const (newtok[1], low); - assemble_tokens ("lda", newtok, 3, 0); - basereg = targreg; - low = 0; - } - - if (poffset) - set_tok_const (*poffset, low); - *pbasereg = basereg; - } - - return emit_lituse; -} - -/* The lda macro differs from the lda instruction in that it handles - most simple expressions, particualrly symbol address loads and - large constants. */ - -static void -emit_lda (tok, ntok, opname) - const expressionS *tok; - int ntok; - const PTR opname; -{ - int basereg; - const expressionS *reloc = (const expressionS *)0; - -#ifdef RELOC_OP_P - if (ntok && USER_RELOC_P (tok[ntok-1].X_op)) - { - const struct alpha_reloc_op_tag *r; - - reloc = &tok[ntok-1]; - r = ALPHA_RELOC_TABLE (reloc->X_op); - switch (reloc->X_op) - { - default: - as_bad (_("Cannot use !%s!%d with %s"), r->name, - (int)reloc->X_add_number, (const char *)opname); - - reloc = (const expressionS *)0; - ntok--; - break; - - case O_literal: - ntok--; - break; - - /* For lda $x,0($x)!lituse_base!y, don't use load_expression, since - it is really too general for our needs. Instead just generate the - lda directly. */ - case O_lituse_base: - if (ntok != 4 - || tok[0].X_op != O_register - || !is_ir_num(tok[0].X_add_number) - || tok[1].X_op != O_constant - || tok[2].X_op != O_pregister - || !is_ir_num(tok[2].X_add_number)) - { - as_bad (_("bad instruction format for lda !%s!%d"), r->name, - reloc->X_add_number); - - reloc = (const expressionS *)0; - ntok--; - break; - } - - emit_loadstore (tok, ntok, "lda"); - return; - } - } -#endif - - if (ntok == 2) - basereg = (tok[1].X_op == O_constant ? AXP_REG_ZERO : alpha_gp_register); - else - basereg = tok[2].X_add_number; - - (void) load_expression (tok[0].X_add_number, &tok[1], &basereg, NULL, reloc); -} - -/* The ldah macro differs from the ldah instruction in that it has $31 - as an implied base register. */ - -static void -emit_ldah (tok, ntok, unused) - const expressionS *tok; - int ntok ATTRIBUTE_UNUSED; - const PTR unused ATTRIBUTE_UNUSED; -{ - expressionS newtok[3]; - -#ifdef RELOC_OP_P - if (ntok && USER_RELOC_P (tok[ntok-1].X_op)) - { - const expressionS *reloc_exp = &tok[ntok-1]; - const struct alpha_reloc_op_tag *r = ALPHA_RELOC_TABLE (reloc_exp->X_op); - as_bad (_("Cannot use !%s!%d with %s"), r->name, - (int)reloc_exp->X_add_number, "ldah"); - ntok--; - } -#endif - - newtok[0] = tok[0]; - newtok[1] = tok[1]; - set_tok_preg (newtok[2], AXP_REG_ZERO); - - assemble_tokens ("ldah", newtok, 3, 0); -} - -/* Handle all "simple" integer register loads -- ldq, ldq_l, ldq_u, - etc. They differ from the real instructions in that they do simple - expressions like the lda macro. */ - -static void -emit_ir_load (tok, ntok, opname) - const expressionS *tok; - int ntok; - const PTR opname; -{ - int basereg, lituse; - expressionS newtok[3]; - struct alpha_insn insn; - -#ifdef RELOC_OP_P - const expressionS *reloc = (const expressionS *)0; - - if (ntok && USER_RELOC_P (tok[ntok-1].X_op)) - { - const struct alpha_reloc_op_tag *r; - - reloc = &tok[ntok-1]; - switch (reloc->X_op) - { - case O_lituse_base: - ntok--; - break; - - case O_literal: - if (strcmp ((const char *)opname, "ldq") == 0) - { - emit_lda (tok, ntok, opname); - return; - } - - /* fall through */ - default: - ntok--; - r = ALPHA_RELOC_TABLE (reloc->X_op); - as_bad (_("Cannot use !%s!%d with %s"), r->name, - (int)reloc->X_add_number, (const char *)opname); - } - } -#endif - - if (ntok == 2) - basereg = (tok[1].X_op == O_constant ? AXP_REG_ZERO : alpha_gp_register); - else - basereg = tok[2].X_add_number; - - lituse = load_expression (tok[0].X_add_number, &tok[1], &basereg, - &newtok[1], (const expressionS *)0); - - newtok[0] = tok[0]; - set_tok_preg (newtok[2], basereg); - - assemble_tokens_to_insn ((const char *)opname, newtok, 3, &insn); - -#ifdef RELOC_OP_P - if (reloc) - { - int nfixups = insn.nfixups; - const struct alpha_reloc_op_tag *r = ALPHA_RELOC_TABLE (reloc->X_op); - - assert (nfixups < MAX_INSN_FIXUPS); - insn.fixups[nfixups].reloc = r->reloc; - insn.fixups[nfixups].exp.X_op = O_symbol; - insn.fixups[nfixups].exp.X_add_symbol = section_symbol (now_seg); - insn.fixups[nfixups].exp.X_add_number = r->lituse; - insn.sequence[nfixups] = reloc->X_add_number; - insn.nfixups++; - } -#endif - - if (lituse) - { - assert (insn.nfixups < MAX_INSN_FIXUPS); - if (insn.nfixups > 0) - { - memmove (&insn.fixups[1], &insn.fixups[0], - sizeof(struct alpha_fixup) * insn.nfixups); - } - insn.nfixups++; - insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITUSE; - insn.fixups[0].exp.X_op = O_symbol; - insn.fixups[0].exp.X_add_symbol = section_symbol (now_seg); - insn.fixups[0].exp.X_add_number = LITUSE_BASE; - } - - emit_insn (&insn); -} - -/* Handle fp register loads, and both integer and fp register stores. - Again, we handle simple expressions. */ - -static void -emit_loadstore (tok, ntok, opname) - const expressionS *tok; - int ntok; - const PTR opname; -{ - int basereg, lituse; - expressionS newtok[3]; - struct alpha_insn insn; - -#ifdef RELOC_OP_P - const expressionS *reloc = (const expressionS *)0; - - if (ntok && USER_RELOC_P (tok[ntok-1].X_op)) - { - reloc = &tok[--ntok]; - if (reloc->X_op != O_lituse_base) - { - const struct alpha_reloc_op_tag *r = &alpha_reloc_op[ reloc->X_md ]; - as_bad (_("Cannot use !%s!%d with %s"), r->name, - (int)reloc->X_add_number, (const char *)opname); - } - } -#endif - - if (ntok == 2) - basereg = (tok[1].X_op == O_constant ? AXP_REG_ZERO : alpha_gp_register); - else - basereg = tok[2].X_add_number; - - if (tok[1].X_op != O_constant || !range_signed_16(tok[1].X_add_number)) - { - if (alpha_noat_on) - as_bad (_("macro requires $at register while noat in effect")); - - lituse = load_expression (AXP_REG_AT, &tok[1], &basereg, &newtok[1], - (const expressionS *)0); - } - else - { - newtok[1] = tok[1]; - lituse = 0; - } - - newtok[0] = tok[0]; - set_tok_preg (newtok[2], basereg); - - assemble_tokens_to_insn ((const char *)opname, newtok, 3, &insn); - -#ifdef RELOC_OP_P - if (reloc) - { - int nfixups = insn.nfixups; - const struct alpha_reloc_op_tag *r = ALPHA_RELOC_TABLE (reloc->X_op); - - assert (nfixups < MAX_INSN_FIXUPS); - insn.fixups[nfixups].reloc = r->reloc; - insn.fixups[nfixups].exp.X_op = O_symbol; - insn.fixups[nfixups].exp.X_add_symbol = section_symbol (now_seg); - insn.fixups[nfixups].exp.X_add_number = r->lituse; - insn.sequence[nfixups] = reloc->X_add_number; - insn.nfixups++; - } -#endif - - if (lituse) - { - assert (insn.nfixups < MAX_INSN_FIXUPS); - if (insn.nfixups > 0) - { - memmove (&insn.fixups[1], &insn.fixups[0], - sizeof(struct alpha_fixup) * insn.nfixups); - } - insn.nfixups++; - insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITUSE; - insn.fixups[0].exp.X_op = O_symbol; - insn.fixups[0].exp.X_add_symbol = section_symbol (now_seg); - insn.fixups[0].exp.X_add_number = LITUSE_BASE; - } - - emit_insn (&insn); -} - -/* Load a half-word or byte as an unsigned value. */ - -static void -emit_ldXu (tok, ntok, vlgsize) - const expressionS *tok; - int ntok; - const PTR vlgsize; -{ - if (alpha_target & AXP_OPCODE_BWX) - emit_ir_load (tok, ntok, ldXu_op[(long)vlgsize]); - else - { - expressionS newtok[3]; - -#ifdef RELOC_OP_P - if (ntok && USER_RELOC_P (tok[ntok-1].X_op)) - { - const expressionS *reloc_exp = &tok[ntok-1]; - const struct alpha_reloc_op_tag *r - = ALPHA_RELOC_TABLE (reloc_exp->X_op); - - as_bad (_("Cannot use !%s!%d with %s"), r->name, - (int)reloc_exp->X_add_number, "ldbu/ldwu"); - ntok--; - } -#endif - - if (alpha_noat_on) - as_bad (_("macro requires $at register while noat in effect")); - - /* emit "lda $at, exp" */ - - memcpy (newtok, tok, sizeof (expressionS) * ntok); - newtok[0].X_add_number = AXP_REG_AT; - assemble_tokens ("lda", newtok, ntok, 1); - - /* emit "ldq_u targ, 0($at)" */ - - newtok[0] = tok[0]; - set_tok_const (newtok[1], 0); - set_tok_preg (newtok[2], AXP_REG_AT); - assemble_tokens ("ldq_u", newtok, 3, 1); - - /* emit "extXl targ, $at, targ" */ - - set_tok_reg (newtok[1], AXP_REG_AT); - newtok[2] = newtok[0]; - assemble_tokens (extXl_op[(long)vlgsize], newtok, 3, 1); - } -} - -/* Load a half-word or byte as a signed value. */ - -static void -emit_ldX (tok, ntok, vlgsize) - const expressionS *tok; - int ntok; - const PTR vlgsize; -{ - emit_ldXu (tok, ntok, vlgsize); - assemble_tokens (sextX_op[(long)vlgsize], tok, 1, 1); -} - -/* Load an integral value from an unaligned address as an unsigned - value. */ - -static void -emit_uldXu (tok, ntok, vlgsize) - const expressionS *tok; - int ntok; - const PTR vlgsize; -{ - long lgsize = (long)vlgsize; - expressionS newtok[3]; - - if (alpha_noat_on) - as_bad (_("macro requires $at register while noat in effect")); - - /* emit "lda $at, exp" */ - - memcpy (newtok, tok, sizeof (expressionS) * ntok); - newtok[0].X_add_number = AXP_REG_AT; - assemble_tokens ("lda", newtok, ntok, 1); - - /* emit "ldq_u $t9, 0($at)" */ - - set_tok_reg (newtok[0], AXP_REG_T9); - set_tok_const (newtok[1], 0); - set_tok_preg (newtok[2], AXP_REG_AT); - assemble_tokens ("ldq_u", newtok, 3, 1); - - /* emit "ldq_u $t10, size-1($at)" */ - - set_tok_reg (newtok[0], AXP_REG_T10); - set_tok_const (newtok[1], (1<<lgsize)-1); - assemble_tokens ("ldq_u", newtok, 3, 1); - - /* emit "extXl $t9, $at, $t9" */ - - set_tok_reg (newtok[0], AXP_REG_T9); - set_tok_reg (newtok[1], AXP_REG_AT); - set_tok_reg (newtok[2], AXP_REG_T9); - assemble_tokens (extXl_op[lgsize], newtok, 3, 1); - - /* emit "extXh $t10, $at, $t10" */ - - set_tok_reg (newtok[0], AXP_REG_T10); - set_tok_reg (newtok[2], AXP_REG_T10); - assemble_tokens (extXh_op[lgsize], newtok, 3, 1); - - /* emit "or $t9, $t10, targ" */ - - set_tok_reg (newtok[0], AXP_REG_T9); - set_tok_reg (newtok[1], AXP_REG_T10); - newtok[2] = tok[0]; - assemble_tokens ("or", newtok, 3, 1); -} - -/* Load an integral value from an unaligned address as a signed value. - Note that quads should get funneled to the unsigned load since we - don't have to do the sign extension. */ - -static void -emit_uldX (tok, ntok, vlgsize) - const expressionS *tok; - int ntok; - const PTR vlgsize; -{ - emit_uldXu (tok, ntok, vlgsize); - assemble_tokens (sextX_op[(long)vlgsize], tok, 1, 1); -} - -/* Implement the ldil macro. */ - -static void -emit_ldil (tok, ntok, unused) - const expressionS *tok; - int ntok; - const PTR unused ATTRIBUTE_UNUSED; -{ - expressionS newtok[2]; - -#ifdef RELOC_OP_P - if (ntok && USER_RELOC_P (tok[ntok-1].X_op)) - { - const expressionS *reloc_exp = &tok[ntok-1]; - const struct alpha_reloc_op_tag *r = ALPHA_RELOC_TABLE (reloc_exp->X_op); - as_bad (_("Cannot use !%s!%d with %s"), r->name, - (int)reloc_exp->X_add_number, "ldil"); - ntok--; - } -#endif - - memcpy (newtok, tok, sizeof(newtok)); - newtok[1].X_add_number = sign_extend_32 (tok[1].X_add_number); - - assemble_tokens ("lda", newtok, ntok, 1); -} - -/* Store a half-word or byte. */ - -static void -emit_stX (tok, ntok, vlgsize) - const expressionS *tok; - int ntok; - const PTR vlgsize; -{ - int lgsize = (int)(long)vlgsize; - - if (alpha_target & AXP_OPCODE_BWX) - emit_loadstore (tok, ntok, stX_op[lgsize]); - else - { - expressionS newtok[3]; - - if (alpha_noat_on) - as_bad(_("macro requires $at register while noat in effect")); - - /* emit "lda $at, exp" */ - - memcpy (newtok, tok, sizeof (expressionS) * ntok); - newtok[0].X_add_number = AXP_REG_AT; - assemble_tokens ("lda", newtok, ntok, 1); - - /* emit "ldq_u $t9, 0($at)" */ - - set_tok_reg (newtok[0], AXP_REG_T9); - set_tok_const (newtok[1], 0); - set_tok_preg (newtok[2], AXP_REG_AT); - assemble_tokens ("ldq_u", newtok, 3, 1); - - /* emit "insXl src, $at, $t10" */ - - newtok[0] = tok[0]; - set_tok_reg (newtok[1], AXP_REG_AT); - set_tok_reg (newtok[2], AXP_REG_T10); - assemble_tokens (insXl_op[lgsize], newtok, 3, 1); - - /* emit "mskXl $t9, $at, $t9" */ - - set_tok_reg (newtok[0], AXP_REG_T9); - newtok[2] = newtok[0]; - assemble_tokens (mskXl_op[lgsize], newtok, 3, 1); - - /* emit "or $t9, $t10, $t9" */ - - set_tok_reg (newtok[1], AXP_REG_T10); - assemble_tokens ("or", newtok, 3, 1); - - /* emit "stq_u $t9, 0($at) */ - - set_tok_const (newtok[1], 0); - set_tok_preg (newtok[2], AXP_REG_AT); - assemble_tokens ("stq_u", newtok, 3, 1); - } -} - -/* Store an integer to an unaligned address. */ - -static void -emit_ustX (tok, ntok, vlgsize) - const expressionS *tok; - int ntok; - const PTR vlgsize; -{ - int lgsize = (int)(long)vlgsize; - expressionS newtok[3]; - - /* emit "lda $at, exp" */ - - memcpy (newtok, tok, sizeof (expressionS) * ntok); - newtok[0].X_add_number = AXP_REG_AT; - assemble_tokens ("lda", newtok, ntok, 1); - - /* emit "ldq_u $9, 0($at)" */ - - set_tok_reg (newtok[0], AXP_REG_T9); - set_tok_const (newtok[1], 0); - set_tok_preg (newtok[2], AXP_REG_AT); - assemble_tokens ("ldq_u", newtok, 3, 1); - - /* emit "ldq_u $10, size-1($at)" */ - - set_tok_reg (newtok[0], AXP_REG_T10); - set_tok_const (newtok[1], (1 << lgsize)-1); - assemble_tokens ("ldq_u", newtok, 3, 1); - - /* emit "insXl src, $at, $t11" */ - - newtok[0] = tok[0]; - set_tok_reg (newtok[1], AXP_REG_AT); - set_tok_reg (newtok[2], AXP_REG_T11); - assemble_tokens (insXl_op[lgsize], newtok, 3, 1); - - /* emit "insXh src, $at, $t12" */ - - set_tok_reg (newtok[2], AXP_REG_T12); - assemble_tokens (insXh_op[lgsize], newtok, 3, 1); - - /* emit "mskXl $t9, $at, $t9" */ - - set_tok_reg (newtok[0], AXP_REG_T9); - newtok[2] = newtok[0]; - assemble_tokens (mskXl_op[lgsize], newtok, 3, 1); - - /* emit "mskXh $t10, $at, $t10" */ - - set_tok_reg (newtok[0], AXP_REG_T10); - newtok[2] = newtok[0]; - assemble_tokens (mskXh_op[lgsize], newtok, 3, 1); - - /* emit "or $t9, $t11, $t9" */ - - set_tok_reg (newtok[0], AXP_REG_T9); - set_tok_reg (newtok[1], AXP_REG_T11); - newtok[2] = newtok[0]; - assemble_tokens ("or", newtok, 3, 1); - - /* emit "or $t10, $t12, $t10" */ - - set_tok_reg (newtok[0], AXP_REG_T10); - set_tok_reg (newtok[1], AXP_REG_T12); - newtok[2] = newtok[0]; - assemble_tokens ("or", newtok, 3, 1); - - /* emit "stq_u $t9, 0($at)" */ - - set_tok_reg (newtok[0], AXP_REG_T9); - set_tok_const (newtok[1], 0); - set_tok_preg (newtok[2], AXP_REG_AT); - assemble_tokens ("stq_u", newtok, 3, 1); - - /* emit "stq_u $t10, size-1($at)" */ - - set_tok_reg (newtok[0], AXP_REG_T10); - set_tok_const (newtok[1], (1 << lgsize)-1); - assemble_tokens ("stq_u", newtok, 3, 1); -} - -/* Sign extend a half-word or byte. The 32-bit sign extend is - implemented as "addl $31, $r, $t" in the opcode table. */ - -static void -emit_sextX (tok, ntok, vlgsize) - const expressionS *tok; - int ntok; - const PTR vlgsize; -{ - long lgsize = (long)vlgsize; - - if (alpha_target & AXP_OPCODE_BWX) - assemble_tokens (sextX_op[lgsize], tok, ntok, 0); - else - { - int bitshift = 64 - 8 * (1 << lgsize); - expressionS newtok[3]; - -#ifdef RELOC_OP_P - if (ntok && USER_RELOC_P (tok[ntok-1].X_op)) - { - const expressionS *reloc_exp = &tok[ntok-1]; - const struct alpha_reloc_op_tag *r - = ALPHA_RELOC_TABLE (reloc_exp->X_op); - - as_bad (_("Cannot use !%s!%d with %s"), r->name, - (int)reloc_exp->X_add_number, "setxt"); - ntok--; - } -#endif - - /* emit "sll src,bits,dst" */ - - newtok[0] = tok[0]; - set_tok_const (newtok[1], bitshift); - newtok[2] = tok[ntok - 1]; - assemble_tokens ("sll", newtok, 3, 1); - - /* emit "sra dst,bits,dst" */ - - newtok[0] = newtok[2]; - assemble_tokens ("sra", newtok, 3, 1); - } -} - -/* Implement the division and modulus macros. */ - -#ifdef OBJ_EVAX - -/* Make register usage like in normal procedure call. - Don't clobber PV and RA. */ - -static void -emit_division (tok, ntok, symname) - const expressionS *tok; - int ntok; - const PTR symname; -{ - /* DIVISION and MODULUS. Yech. - * - * Convert - * OP x,y,result - * to - * mov x,R16 # if x != R16 - * mov y,R17 # if y != R17 - * lda AT,__OP - * jsr AT,(AT),0 - * mov R0,result - * - * with appropriate optimizations if R0,R16,R17 are the registers - * specified by the compiler. - */ - - int xr, yr, rr; - symbolS *sym; - expressionS newtok[3]; - -#ifdef RELOC_OP_P - if (ntok && USER_RELOC_P (tok[ntok-1].X_op)) - { - const expressionS *reloc_exp = &tok[ntok-1]; - const struct alpha_reloc_op_tag *r = ALPHA_RELOC_TABLE (reloc_exp->X_op); - as_bad (_("Cannot use !%s!%d with %s"), r->name, - (int)reloc_exp->X_add_number, (char char *)symname); - ntok--; - } -#endif - - xr = regno (tok[0].X_add_number); - yr = regno (tok[1].X_add_number); - - if (ntok < 3) - rr = xr; - else - rr = regno (tok[2].X_add_number); - - /* Move the operands into the right place */ - if (yr == AXP_REG_R16 && xr == AXP_REG_R17) - { - /* They are in exactly the wrong order -- swap through AT */ - - if (alpha_noat_on) - as_bad (_("macro requires $at register while noat in effect")); - - set_tok_reg (newtok[0], AXP_REG_R16); - set_tok_reg (newtok[1], AXP_REG_AT); - assemble_tokens ("mov", newtok, 2, 1); - - set_tok_reg (newtok[0], AXP_REG_R17); - set_tok_reg (newtok[1], AXP_REG_R16); - assemble_tokens ("mov", newtok, 2, 1); - - set_tok_reg (newtok[0], AXP_REG_AT); - set_tok_reg (newtok[1], AXP_REG_R17); - assemble_tokens ("mov", newtok, 2, 1); - } - else - { - if (yr == AXP_REG_R16) - { - set_tok_reg (newtok[0], AXP_REG_R16); - set_tok_reg (newtok[1], AXP_REG_R17); - assemble_tokens ("mov", newtok, 2, 1); - } - - if (xr != AXP_REG_R16) - { - set_tok_reg (newtok[0], xr); - set_tok_reg (newtok[1], AXP_REG_R16); - assemble_tokens ("mov", newtok, 2, 1); - } - - if (yr != AXP_REG_R16 && yr != AXP_REG_R17) - { - set_tok_reg (newtok[0], yr); - set_tok_reg (newtok[1], AXP_REG_R17); - assemble_tokens ("mov", newtok, 2, 1); - } - } - - sym = symbol_find_or_make ((const char *)symname); - - set_tok_reg (newtok[0], AXP_REG_AT); - set_tok_sym (newtok[1], sym, 0); - assemble_tokens ("lda", newtok, 2, 1); - - /* Call the division routine */ - set_tok_reg (newtok[0], AXP_REG_AT); - set_tok_cpreg (newtok[1], AXP_REG_AT); - set_tok_const (newtok[2], 0); - assemble_tokens ("jsr", newtok, 3, 1); - - /* Move the result to the right place */ - if (rr != AXP_REG_R0) - { - set_tok_reg (newtok[0], AXP_REG_R0); - set_tok_reg (newtok[1], rr); - assemble_tokens ("mov", newtok, 2, 1); - } -} - -#else /* !OBJ_EVAX */ - -static void -emit_division (tok, ntok, symname) - const expressionS *tok; - int ntok; - const PTR symname; -{ - /* DIVISION and MODULUS. Yech. - * Convert - * OP x,y,result - * to - * lda pv,__OP - * mov x,t10 - * mov y,t11 - * jsr t9,(pv),__OP - * mov t12,result - * - * with appropriate optimizations if t10,t11,t12 are the registers - * specified by the compiler. - */ - - int xr, yr, rr; - symbolS *sym; - expressionS newtok[3]; - -#ifdef RELOC_OP_P - if (ntok && USER_RELOC_P (tok[ntok-1].X_op)) - { - const expressionS *reloc_exp = &tok[ntok-1]; - const struct alpha_reloc_op_tag *r = ALPHA_RELOC_TABLE (reloc_exp->X_op); - as_bad (_("Cannot use !%s!%d with %s"), r->name, - (int)reloc_exp->X_add_number, (const char *)symname); - ntok--; - } -#endif - - xr = regno (tok[0].X_add_number); - yr = regno (tok[1].X_add_number); - - if (ntok < 3) - rr = xr; - else - rr = regno (tok[2].X_add_number); - - sym = symbol_find_or_make ((const char *)symname); - - /* Move the operands into the right place */ - if (yr == AXP_REG_T10 && xr == AXP_REG_T11) - { - /* They are in exactly the wrong order -- swap through AT */ - - if (alpha_noat_on) - as_bad (_("macro requires $at register while noat in effect")); - - set_tok_reg (newtok[0], AXP_REG_T10); - set_tok_reg (newtok[1], AXP_REG_AT); - assemble_tokens ("mov", newtok, 2, 1); - - set_tok_reg (newtok[0], AXP_REG_T11); - set_tok_reg (newtok[1], AXP_REG_T10); - assemble_tokens ("mov", newtok, 2, 1); - - set_tok_reg (newtok[0], AXP_REG_AT); - set_tok_reg (newtok[1], AXP_REG_T11); - assemble_tokens ("mov", newtok, 2, 1); - } - else - { - if (yr == AXP_REG_T10) - { - set_tok_reg (newtok[0], AXP_REG_T10); - set_tok_reg (newtok[1], AXP_REG_T11); - assemble_tokens ("mov", newtok, 2, 1); - } - - if (xr != AXP_REG_T10) - { - set_tok_reg (newtok[0], xr); - set_tok_reg (newtok[1], AXP_REG_T10); - assemble_tokens ("mov", newtok, 2, 1); - } - - if (yr != AXP_REG_T10 && yr != AXP_REG_T11) - { - set_tok_reg (newtok[0], yr); - set_tok_reg (newtok[1], AXP_REG_T11); - assemble_tokens ("mov", newtok, 2, 1); - } - } - - /* Call the division routine */ - set_tok_reg (newtok[0], AXP_REG_T9); - set_tok_sym (newtok[1], sym, 0); - assemble_tokens ("jsr", newtok, 2, 1); - - /* Reload the GP register */ -#ifdef OBJ_AOUT -FIXME -#endif -#if defined(OBJ_ECOFF) || defined(OBJ_ELF) - set_tok_reg (newtok[0], alpha_gp_register); - set_tok_const (newtok[1], 0); - set_tok_preg (newtok[2], AXP_REG_T9); - assemble_tokens ("ldgp", newtok, 3, 1); -#endif - - /* Move the result to the right place */ - if (rr != AXP_REG_T12) - { - set_tok_reg (newtok[0], AXP_REG_T12); - set_tok_reg (newtok[1], rr); - assemble_tokens ("mov", newtok, 2, 1); - } -} - -#endif /* !OBJ_EVAX */ - -/* The jsr and jmp macros differ from their instruction counterparts - in that they can load the target address and default most - everything. */ - -static void -emit_jsrjmp (tok, ntok, vopname) - const expressionS *tok; - int ntok; - const PTR vopname; -{ - const char *opname = (const char *) vopname; - struct alpha_insn insn; - expressionS newtok[3]; - int r, tokidx = 0, lituse = 0; - -#ifdef RELOC_OP_P - if (ntok && USER_RELOC_P (tok[ntok-1].X_op)) - { - const expressionS *reloc_exp = &tok[ntok-1]; - const struct alpha_reloc_op_tag *r = ALPHA_RELOC_TABLE (reloc_exp->X_op); - as_bad (_("Cannot use !%s!%d with %s"), r->name, - (int)reloc_exp->X_add_number, opname); - ntok--; - } -#endif - - if (tokidx < ntok && tok[tokidx].X_op == O_register) - r = regno (tok[tokidx++].X_add_number); - else - r = strcmp (opname, "jmp") == 0 ? AXP_REG_ZERO : AXP_REG_RA; - - set_tok_reg (newtok[0], r); - - if (tokidx < ntok && - (tok[tokidx].X_op == O_pregister || tok[tokidx].X_op == O_cpregister)) - r = regno (tok[tokidx++].X_add_number); -#ifdef OBJ_EVAX - /* keep register if jsr $n.<sym> */ -#else - else - { - int basereg = alpha_gp_register; - lituse = load_expression (r = AXP_REG_PV, &tok[tokidx], &basereg, NULL, - (const expressionS *)0); - } -#endif - - set_tok_cpreg (newtok[1], r); - -#ifdef OBJ_EVAX - /* FIXME: Add hint relocs to BFD for evax. */ -#else - if (tokidx < ntok) - newtok[2] = tok[tokidx]; - else -#endif - set_tok_const (newtok[2], 0); - - assemble_tokens_to_insn (opname, newtok, 3, &insn); - - /* add the LITUSE fixup */ - if (lituse) - { - assert (insn.nfixups < MAX_INSN_FIXUPS); - if (insn.nfixups > 0) - { - memmove (&insn.fixups[1], &insn.fixups[0], - sizeof(struct alpha_fixup) * insn.nfixups); - } - insn.nfixups++; - insn.fixups[0].reloc = BFD_RELOC_ALPHA_LITUSE; - insn.fixups[0].exp.X_op = O_symbol; - insn.fixups[0].exp.X_add_symbol = section_symbol (now_seg); - insn.fixups[0].exp.X_add_number = LITUSE_JSR; - } - - emit_insn (&insn); -} - -/* The ret and jcr instructions differ from their instruction - counterparts in that everything can be defaulted. */ - -static void -emit_retjcr (tok, ntok, vopname) - const expressionS *tok; - int ntok; - const PTR vopname; -{ - const char *opname = (const char *)vopname; - expressionS newtok[3]; - int r, tokidx = 0; - -#ifdef RELOC_OP_P - if (ntok && USER_RELOC_P (tok[ntok-1].X_op)) - { - const expressionS *reloc_exp = &tok[ntok-1]; - const struct alpha_reloc_op_tag *r = ALPHA_RELOC_TABLE (reloc_exp->X_op); - as_bad (_("Cannot use !%s!%d with %s"), r->name, - (int)reloc_exp->X_add_number, opname); - ntok--; - } -#endif - - if (tokidx < ntok && tok[tokidx].X_op == O_register) - r = regno (tok[tokidx++].X_add_number); - else - r = AXP_REG_ZERO; - - set_tok_reg (newtok[0], r); - - if (tokidx < ntok && - (tok[tokidx].X_op == O_pregister || tok[tokidx].X_op == O_cpregister)) - r = regno (tok[tokidx++].X_add_number); - else - r = AXP_REG_RA; - - set_tok_cpreg (newtok[1], r); - - if (tokidx < ntok) - newtok[2] = tok[tokidx]; - else - set_tok_const (newtok[2], strcmp(opname, "ret") == 0); - - assemble_tokens (opname, newtok, 3, 0); -} - -/* Assembler directives */ - -/* Handle the .text pseudo-op. This is like the usual one, but it - clears alpha_insn_label and restores auto alignment. */ - -static void -s_alpha_text (i) - int i; - -{ - s_text (i); - alpha_insn_label = NULL; - alpha_auto_align_on = 1; - alpha_current_align = 0; -} - -/* Handle the .data pseudo-op. This is like the usual one, but it - clears alpha_insn_label and restores auto alignment. */ - -static void -s_alpha_data (i) - int i; -{ - s_data (i); - alpha_insn_label = NULL; - alpha_auto_align_on = 1; - alpha_current_align = 0; -} - -#if defined (OBJ_ECOFF) || defined (OBJ_EVAX) - -/* Handle the OSF/1 and openVMS .comm pseudo quirks. - openVMS constructs a section for every common symbol. */ - -static void -s_alpha_comm (ignore) - int ignore; -{ - register char *name; - register char c; - register char *p; - offsetT temp; - register symbolS *symbolP; - -#ifdef OBJ_EVAX - segT current_section = now_seg; - int current_subsec = now_subseg; - segT new_seg; -#endif - - name = input_line_pointer; - c = get_symbol_end (); - - /* just after name is now '\0' */ - p = input_line_pointer; - *p = c; - - SKIP_WHITESPACE (); - - /* Alpha OSF/1 compiler doesn't provide the comma, gcc does. */ - if (*input_line_pointer == ',') - { - input_line_pointer++; - SKIP_WHITESPACE (); - } - if ((temp = get_absolute_expression ()) < 0) - { - as_warn (_(".COMMon length (%ld.) <0! Ignored."), (long) temp); - ignore_rest_of_line (); - return; - } - - *p = 0; - symbolP = symbol_find_or_make (name); - -#ifdef OBJ_EVAX - /* Make a section for the common symbol. */ - new_seg = subseg_new (xstrdup (name), 0); -#endif - - *p = c; - -#ifdef OBJ_EVAX - /* alignment might follow */ - if (*input_line_pointer == ',') - { - offsetT align; - - input_line_pointer++; - align = get_absolute_expression (); - bfd_set_section_alignment (stdoutput, new_seg, align); - } -#endif - - if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP)) - { - as_bad (_("Ignoring attempt to re-define symbol")); - ignore_rest_of_line (); - return; - } - -#ifdef OBJ_EVAX - if (bfd_section_size (stdoutput, new_seg) > 0) - { - if (bfd_section_size (stdoutput, new_seg) != temp) - as_bad (_("Length of .comm \"%s\" is already %ld. Not changed to %ld."), - S_GET_NAME (symbolP), - (long) bfd_section_size (stdoutput, new_seg), - (long) temp); - } -#else - if (S_GET_VALUE (symbolP)) - { - if (S_GET_VALUE (symbolP) != (valueT) temp) - as_bad (_("Length of .comm \"%s\" is already %ld. Not changed to %ld."), - S_GET_NAME (symbolP), - (long) S_GET_VALUE (symbolP), - (long) temp); - } -#endif - else - { -#ifdef OBJ_EVAX - subseg_set (new_seg, 0); - p = frag_more (temp); - new_seg->flags |= SEC_IS_COMMON; - if (! S_IS_DEFINED (symbolP)) - S_SET_SEGMENT (symbolP, new_seg); -#else - S_SET_VALUE (symbolP, (valueT) temp); -#endif - S_SET_EXTERNAL (symbolP); - } - -#ifdef OBJ_EVAX - subseg_set (current_section, current_subsec); -#endif - - know (symbol_get_frag (symbolP) == &zero_address_frag); - - demand_empty_rest_of_line (); -} - -#endif /* ! OBJ_ELF */ - -#ifdef OBJ_ECOFF - -/* Handle the .rdata pseudo-op. This is like the usual one, but it - clears alpha_insn_label and restores auto alignment. */ - -static void -s_alpha_rdata (ignore) - int ignore; -{ - int temp; - - temp = get_absolute_expression (); - subseg_new (".rdata", 0); - demand_empty_rest_of_line (); - alpha_insn_label = NULL; - alpha_auto_align_on = 1; - alpha_current_align = 0; -} - -#endif - -#ifdef OBJ_ECOFF - -/* Handle the .sdata pseudo-op. This is like the usual one, but it - clears alpha_insn_label and restores auto alignment. */ - -static void -s_alpha_sdata (ignore) - int ignore; -{ - int temp; - - temp = get_absolute_expression (); - subseg_new (".sdata", 0); - demand_empty_rest_of_line (); - alpha_insn_label = NULL; - alpha_auto_align_on = 1; - alpha_current_align = 0; -} -#endif - -#ifdef OBJ_ELF - -/* Handle the .section pseudo-op. This is like the usual one, but it - clears alpha_insn_label and restores auto alignment. */ - -static void -s_alpha_section (ignore) - int ignore; -{ - obj_elf_section (ignore); - - alpha_insn_label = NULL; - alpha_auto_align_on = 1; - alpha_current_align = 0; -} - -static void -s_alpha_ent (dummy) - int dummy ATTRIBUTE_UNUSED; -{ - if (ECOFF_DEBUGGING) - ecoff_directive_ent (0); - else - { - char *name, name_end; - name = input_line_pointer; - name_end = get_symbol_end (); - - if (! is_name_beginner (*name)) - { - as_warn (_(".ent directive has no name")); - *input_line_pointer = name_end; - } - else - { - symbolS *sym; - - if (alpha_cur_ent_sym) - as_warn (_("nested .ent directives")); - - sym = symbol_find_or_make (name); - symbol_get_bfdsym (sym)->flags |= BSF_FUNCTION; - alpha_cur_ent_sym = sym; - - /* The .ent directive is sometimes followed by a number. Not sure - what it really means, but ignore it. */ - *input_line_pointer = name_end; - SKIP_WHITESPACE (); - if (*input_line_pointer == ',') - { - input_line_pointer++; - SKIP_WHITESPACE (); - } - if (isdigit (*input_line_pointer) || *input_line_pointer == '-') - (void) get_absolute_expression (); - } - demand_empty_rest_of_line (); - } -} - -static void -s_alpha_end (dummy) - int dummy ATTRIBUTE_UNUSED; -{ - if (ECOFF_DEBUGGING) - ecoff_directive_end (0); - else - { - char *name, name_end; - name = input_line_pointer; - name_end = get_symbol_end (); - - if (! is_name_beginner (*name)) - { - as_warn (_(".end directive has no name")); - *input_line_pointer = name_end; - } - else - { - symbolS *sym; - - sym = symbol_find (name); - if (sym != alpha_cur_ent_sym) - as_warn (_(".end directive names different symbol than .ent")); - - /* Create an expression to calculate the size of the function. */ - if (sym) - { - symbol_get_obj (sym)->size = - (expressionS *) xmalloc (sizeof (expressionS)); - symbol_get_obj (sym)->size->X_op = O_subtract; - symbol_get_obj (sym)->size->X_add_symbol - = symbol_new ("L0\001", now_seg, frag_now_fix (), frag_now); - symbol_get_obj (sym)->size->X_op_symbol = sym; - symbol_get_obj (sym)->size->X_add_number = 0; - } - - alpha_cur_ent_sym = NULL; - - *input_line_pointer = name_end; - } - demand_empty_rest_of_line (); - } -} - -static void -s_alpha_mask (fp) - int fp; -{ - if (ECOFF_DEBUGGING) - { - if (fp) - ecoff_directive_fmask (0); - else - ecoff_directive_mask (0); - } - else - discard_rest_of_line (); -} - -static void -s_alpha_frame (dummy) - int dummy ATTRIBUTE_UNUSED; -{ - if (ECOFF_DEBUGGING) - ecoff_directive_frame (0); - else - discard_rest_of_line (); -} - -static void -s_alpha_prologue (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - symbolS *sym; - int arg; - - arg = get_absolute_expression (); - demand_empty_rest_of_line (); - - if (ECOFF_DEBUGGING) - sym = ecoff_get_cur_proc_sym (); - else - sym = alpha_cur_ent_sym; - know (sym != NULL); - - switch (arg) - { - case 0: /* No PV required. */ - S_SET_OTHER (sym, STO_ALPHA_NOPV); - break; - case 1: /* Std GP load. */ - S_SET_OTHER (sym, STO_ALPHA_STD_GPLOAD); - break; - case 2: /* Non-std use of PV. */ - break; - - default: - as_bad (_("Invalid argument %d to .prologue."), arg); - break; - } -} - -static void -s_alpha_coff_wrapper (which) - int which; -{ - static void (* const fns[]) PARAMS ((int)) = { - ecoff_directive_begin, - ecoff_directive_bend, - ecoff_directive_def, - ecoff_directive_dim, - ecoff_directive_endef, - ecoff_directive_file, - ecoff_directive_scl, - ecoff_directive_tag, - ecoff_directive_val, - ecoff_directive_loc, - }; - - assert (which >= 0 && which < (int)(sizeof(fns)/sizeof(*fns))); - - if (ECOFF_DEBUGGING) - (*fns[which])(0); - else - { - as_bad (_("ECOFF debugging is disabled.")); - ignore_rest_of_line (); - } -} -#endif /* OBJ_ELF */ - -#ifdef OBJ_EVAX - -/* Handle the section specific pseudo-op. */ - -static void -s_alpha_section (secid) - int secid; -{ - int temp; -#define EVAX_SECTION_COUNT 5 - static char *section_name[EVAX_SECTION_COUNT+1] = - { "NULL", ".rdata", ".comm", ".link", ".ctors", ".dtors" }; - - if ((secid <= 0) || (secid > EVAX_SECTION_COUNT)) - { - as_fatal (_("Unknown section directive")); - demand_empty_rest_of_line (); - return; - } - temp = get_absolute_expression (); - subseg_new (section_name[secid], 0); - demand_empty_rest_of_line (); - alpha_insn_label = NULL; - alpha_auto_align_on = 1; - alpha_current_align = 0; -} - - -/* Parse .ent directives. */ - -static void -s_alpha_ent (ignore) - int ignore; -{ - symbolS *symbol; - expressionS symexpr; - - alpha_evax_proc.pdsckind = 0; - alpha_evax_proc.framereg = -1; - alpha_evax_proc.framesize = 0; - alpha_evax_proc.rsa_offset = 0; - alpha_evax_proc.ra_save = AXP_REG_RA; - alpha_evax_proc.fp_save = -1; - alpha_evax_proc.imask = 0; - alpha_evax_proc.fmask = 0; - alpha_evax_proc.prologue = 0; - alpha_evax_proc.type = 0; - - expression (&symexpr); - - if (symexpr.X_op != O_symbol) - { - as_fatal (_(".ent directive has no symbol")); - demand_empty_rest_of_line (); - return; - } - - symbol = make_expr_symbol (&symexpr); - symbol_get_bfdsym (symbol)->flags |= BSF_FUNCTION; - alpha_evax_proc.symbol = symbol; - - demand_empty_rest_of_line (); - return; -} - - -/* Parse .frame <framreg>,<framesize>,RA,<rsa_offset> directives. */ - -static void -s_alpha_frame (ignore) - int ignore; -{ - long val; - - alpha_evax_proc.framereg = tc_get_register (1); - - SKIP_WHITESPACE (); - if (*input_line_pointer++ != ',' - || get_absolute_expression_and_terminator (&val) != ',') - { - as_warn (_("Bad .frame directive 1./2. param")); - --input_line_pointer; - demand_empty_rest_of_line (); - return; - } - - alpha_evax_proc.framesize = val; - - (void) tc_get_register (1); - SKIP_WHITESPACE (); - if (*input_line_pointer++ != ',') - { - as_warn (_("Bad .frame directive 3./4. param")); - --input_line_pointer; - demand_empty_rest_of_line (); - return; - } - alpha_evax_proc.rsa_offset = get_absolute_expression (); - - return; -} - -static void -s_alpha_pdesc (ignore) - int ignore; -{ - char *name; - char name_end; - long val; - register char *p; - expressionS exp; - symbolS *entry_sym; - fixS *fixp; - segment_info_type *seginfo = seg_info (alpha_link_section); - - if (now_seg != alpha_link_section) - { - as_bad (_(".pdesc directive not in link (.link) section")); - demand_empty_rest_of_line (); - return; - } - - if ((alpha_evax_proc.symbol == 0) - || (!S_IS_DEFINED (alpha_evax_proc.symbol))) - { - as_fatal (_(".pdesc has no matching .ent")); - demand_empty_rest_of_line (); - return; - } - - *symbol_get_obj (alpha_evax_proc.symbol) = - (valueT) seginfo->literal_pool_size; - - expression (&exp); - if (exp.X_op != O_symbol) - { - as_warn (_(".pdesc directive has no entry symbol")); - demand_empty_rest_of_line (); - return; - } - - entry_sym = make_expr_symbol (&exp); - /* Save bfd symbol of proc desc in function symbol. */ - symbol_get_bfdsym (alpha_evax_proc.symbol)->udata.p - = symbol_get_bfdsym (entry_sym); - - SKIP_WHITESPACE (); - if (*input_line_pointer++ != ',') - { - as_warn (_("No comma after .pdesc <entryname>")); - demand_empty_rest_of_line (); - return; - } - - SKIP_WHITESPACE (); - name = input_line_pointer; - name_end = get_symbol_end (); - - if (strncmp(name, "stack", 5) == 0) - { - alpha_evax_proc.pdsckind = PDSC_S_K_KIND_FP_STACK; - } - else if (strncmp(name, "reg", 3) == 0) - { - alpha_evax_proc.pdsckind = PDSC_S_K_KIND_FP_REGISTER; - } - else if (strncmp(name, "null", 4) == 0) - { - alpha_evax_proc.pdsckind = PDSC_S_K_KIND_NULL; - } - else - { - as_fatal (_("unknown procedure kind")); - demand_empty_rest_of_line (); - return; - } - - *input_line_pointer = name_end; - demand_empty_rest_of_line (); - -#ifdef md_flush_pending_output - md_flush_pending_output (); -#endif - - frag_align (3, 0, 0); - p = frag_more (16); - fixp = fix_new (frag_now, p - frag_now->fr_literal, 8, 0, 0, 0, 0); - fixp->fx_done = 1; - seginfo->literal_pool_size += 16; - - *p = alpha_evax_proc.pdsckind - | ((alpha_evax_proc.framereg == 29) ? PDSC_S_M_BASE_REG_IS_FP : 0); - *(p+1) = PDSC_S_M_NATIVE - | PDSC_S_M_NO_JACKET; - - switch (alpha_evax_proc.pdsckind) - { - case PDSC_S_K_KIND_NULL: - *(p+2) = 0; - *(p+3) = 0; - break; - case PDSC_S_K_KIND_FP_REGISTER: - *(p+2) = alpha_evax_proc.fp_save; - *(p+3) = alpha_evax_proc.ra_save; - break; - case PDSC_S_K_KIND_FP_STACK: - md_number_to_chars (p+2, (valueT)alpha_evax_proc.rsa_offset, 2); - break; - default: /* impossible */ - break; - } - - *(p+4) = 0; - *(p+5) = alpha_evax_proc.type & 0x0f; - - /* Signature offset. */ - md_number_to_chars (p+6, (valueT)0, 2); - - fix_new_exp (frag_now, p-frag_now->fr_literal+8, 8, &exp, 0, BFD_RELOC_64); - - if (alpha_evax_proc.pdsckind == PDSC_S_K_KIND_NULL) - return; - - /* Add dummy fix to make add_to_link_pool work. */ - p = frag_more (8); - fixp = fix_new (frag_now, p - frag_now->fr_literal, 8, 0, 0, 0, 0); - fixp->fx_done = 1; - seginfo->literal_pool_size += 8; - - /* pdesc+16: Size. */ - md_number_to_chars (p, (valueT)alpha_evax_proc.framesize, 4); - - md_number_to_chars (p+4, (valueT)0, 2); - - /* Entry length. */ - md_number_to_chars (p+6, alpha_evax_proc.prologue, 2); - - if (alpha_evax_proc.pdsckind == PDSC_S_K_KIND_FP_REGISTER) - return; - - /* Add dummy fix to make add_to_link_pool work. */ - p = frag_more (8); - fixp = fix_new (frag_now, p - frag_now->fr_literal, 8, 0, 0, 0, 0); - fixp->fx_done = 1; - seginfo->literal_pool_size += 8; - - /* pdesc+24: register masks. */ - - md_number_to_chars (p, alpha_evax_proc.imask, 4); - md_number_to_chars (p+4, alpha_evax_proc.fmask, 4); - - return; -} - - -/* Support for crash debug on vms. */ - -static void -s_alpha_name (ignore) - int ignore; -{ - register char *p; - expressionS exp; - segment_info_type *seginfo = seg_info (alpha_link_section); - - if (now_seg != alpha_link_section) - { - as_bad (_(".name directive not in link (.link) section")); - demand_empty_rest_of_line (); - return; - } - - expression (&exp); - if (exp.X_op != O_symbol) - { - as_warn (_(".name directive has no symbol")); - demand_empty_rest_of_line (); - return; - } - - demand_empty_rest_of_line (); - -#ifdef md_flush_pending_output - md_flush_pending_output (); -#endif - - frag_align (3, 0, 0); - p = frag_more (8); - seginfo->literal_pool_size += 8; - - fix_new_exp (frag_now, p-frag_now->fr_literal, 8, &exp, 0, BFD_RELOC_64); - - return; -} - - -static void -s_alpha_linkage (ignore) - int ignore; -{ - expressionS exp; - char *p; - -#ifdef md_flush_pending_output - md_flush_pending_output (); -#endif - - expression (&exp); - if (exp.X_op != O_symbol) - { - as_fatal (_("No symbol after .linkage")); - } - else - { - p = frag_more (LKP_S_K_SIZE); - memset (p, 0, LKP_S_K_SIZE); - fix_new_exp (frag_now, p - frag_now->fr_literal, LKP_S_K_SIZE, &exp, 0,\ - BFD_RELOC_ALPHA_LINKAGE); - } - demand_empty_rest_of_line (); - - return; -} - - -static void -s_alpha_code_address (ignore) - int ignore; -{ - expressionS exp; - char *p; - -#ifdef md_flush_pending_output - md_flush_pending_output (); -#endif - - expression (&exp); - if (exp.X_op != O_symbol) - { - as_fatal (_("No symbol after .code_address")); - } - else - { - p = frag_more (8); - memset (p, 0, 8); - fix_new_exp (frag_now, p - frag_now->fr_literal, 8, &exp, 0,\ - BFD_RELOC_ALPHA_CODEADDR); - } - demand_empty_rest_of_line (); - - return; -} - - -static void -s_alpha_fp_save (ignore) - int ignore; -{ - - alpha_evax_proc.fp_save = tc_get_register (1); - - demand_empty_rest_of_line (); - return; -} - - -static void -s_alpha_mask (ignore) - int ignore; -{ - long val; - - if (get_absolute_expression_and_terminator (&val) != ',') - { - as_warn (_("Bad .mask directive")); - --input_line_pointer; - } - else - { - alpha_evax_proc.imask = val; - (void)get_absolute_expression (); - } - demand_empty_rest_of_line (); - - return; -} - - -static void -s_alpha_fmask (ignore) - int ignore; -{ - long val; - - if (get_absolute_expression_and_terminator (&val) != ',') - { - as_warn (_("Bad .fmask directive")); - --input_line_pointer; - } - else - { - alpha_evax_proc.fmask = val; - (void) get_absolute_expression (); - } - demand_empty_rest_of_line (); - - return; -} - -static void -s_alpha_end (ignore) - int ignore; -{ - char c; - - c = get_symbol_end (); - *input_line_pointer = c; - demand_empty_rest_of_line (); - alpha_evax_proc.symbol = 0; - - return; -} - - -static void -s_alpha_file (ignore) - int ignore; -{ - symbolS *s; - int length; - static char case_hack[32]; - - extern char *demand_copy_string PARAMS ((int *lenP)); - - sprintf (case_hack, "<CASE:%01d%01d>", - alpha_flag_hash_long_names, alpha_flag_show_after_trunc); - - s = symbol_find_or_make (case_hack); - symbol_get_bfdsym (s)->flags |= BSF_FILE; - - get_absolute_expression (); - s = symbol_find_or_make (demand_copy_string (&length)); - symbol_get_bfdsym (s)->flags |= BSF_FILE; - demand_empty_rest_of_line (); - - return; -} -#endif /* OBJ_EVAX */ - -/* Handle the .gprel32 pseudo op. */ - -static void -s_alpha_gprel32 (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - expressionS e; - char *p; - - SKIP_WHITESPACE (); - expression (&e); - -#ifdef OBJ_ELF - switch (e.X_op) - { - case O_constant: - e.X_add_symbol = section_symbol(absolute_section); - e.X_op = O_symbol; - /* FALLTHRU */ - case O_symbol: - break; - default: - abort(); - } -#else -#ifdef OBJ_ECOFF - switch (e.X_op) - { - case O_constant: - e.X_add_symbol = section_symbol (absolute_section); - /* fall through */ - case O_symbol: - e.X_op = O_subtract; - e.X_op_symbol = alpha_gp_symbol; - break; - default: - abort (); - } -#endif -#endif - - if (alpha_auto_align_on && alpha_current_align < 2) - alpha_align (2, (char *) NULL, alpha_insn_label, 0); - if (alpha_current_align > 2) - alpha_current_align = 2; - alpha_insn_label = NULL; - - p = frag_more (4); - memset (p, 0, 4); - fix_new_exp (frag_now, p-frag_now->fr_literal, 4, - &e, 0, BFD_RELOC_GPREL32); -} - -/* Handle floating point allocation pseudo-ops. This is like the - generic vresion, but it makes sure the current label, if any, is - correctly aligned. */ - -static void -s_alpha_float_cons (type) - int type; -{ - int log_size; - - switch (type) - { - default: - case 'f': - case 'F': - log_size = 2; - break; - - case 'd': - case 'D': - case 'G': - log_size = 3; - break; - - case 'x': - case 'X': - case 'p': - case 'P': - log_size = 4; - break; - } - - if (alpha_auto_align_on && alpha_current_align < log_size) - alpha_align (log_size, (char *) NULL, alpha_insn_label, 0); - if (alpha_current_align > log_size) - alpha_current_align = log_size; - alpha_insn_label = NULL; - - float_cons (type); -} - -/* Handle the .proc pseudo op. We don't really do much with it except - parse it. */ - -static void -s_alpha_proc (is_static) - int is_static ATTRIBUTE_UNUSED; -{ - char *name; - char c; - char *p; - symbolS *symbolP; - int temp; - - /* Takes ".proc name,nargs" */ - SKIP_WHITESPACE (); - name = input_line_pointer; - c = get_symbol_end (); - p = input_line_pointer; - symbolP = symbol_find_or_make (name); - *p = c; - SKIP_WHITESPACE (); - if (*input_line_pointer != ',') - { - *p = 0; - as_warn (_("Expected comma after name \"%s\""), name); - *p = c; - temp = 0; - ignore_rest_of_line (); - } - else - { - input_line_pointer++; - temp = get_absolute_expression (); - } - /* *symbol_get_obj (symbolP) = (signed char) temp; */ - as_warn (_("unhandled: .proc %s,%d"), name, temp); - demand_empty_rest_of_line (); -} - -/* Handle the .set pseudo op. This is used to turn on and off most of - the assembler features. */ - -static void -s_alpha_set (x) - int x ATTRIBUTE_UNUSED; -{ - char *name, ch, *s; - int yesno = 1; - - SKIP_WHITESPACE (); - name = input_line_pointer; - ch = get_symbol_end (); - - s = name; - if (s[0] == 'n' && s[1] == 'o') - { - yesno = 0; - s += 2; - } - if (!strcmp ("reorder", s)) - /* ignore */ ; - else if (!strcmp ("at", s)) - alpha_noat_on = !yesno; - else if (!strcmp ("macro", s)) - alpha_macros_on = yesno; - else if (!strcmp ("move", s)) - /* ignore */ ; - else if (!strcmp ("volatile", s)) - /* ignore */ ; - else - as_warn (_("Tried to .set unrecognized mode `%s'"), name); - - *input_line_pointer = ch; - demand_empty_rest_of_line (); -} - -/* Handle the .base pseudo op. This changes the assembler's notion of - the $gp register. */ - -static void -s_alpha_base (ignore) - int ignore ATTRIBUTE_UNUSED; -{ -#if 0 - if (first_32bit_quadrant) - { - /* not fatal, but it might not work in the end */ - as_warn (_("File overrides no-base-register option.")); - first_32bit_quadrant = 0; - } -#endif - - SKIP_WHITESPACE (); - if (*input_line_pointer == '$') - { /* $rNN form */ - input_line_pointer++; - if (*input_line_pointer == 'r') - input_line_pointer++; - } - - alpha_gp_register = get_absolute_expression (); - if (alpha_gp_register < 0 || alpha_gp_register > 31) - { - alpha_gp_register = AXP_REG_GP; - as_warn (_("Bad base register, using $%d."), alpha_gp_register); - } - - demand_empty_rest_of_line (); -} - -/* Handle the .align pseudo-op. This aligns to a power of two. It - also adjusts any current instruction label. We treat this the same - way the MIPS port does: .align 0 turns off auto alignment. */ - -static void -s_alpha_align (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - int align; - char fill, *pfill; - long max_alignment = 15; - - align = get_absolute_expression (); - if (align > max_alignment) - { - align = max_alignment; - as_bad (_("Alignment too large: %d. assumed"), align); - } - else if (align < 0) - { - as_warn (_("Alignment negative: 0 assumed")); - align = 0; - } - - if (*input_line_pointer == ',') - { - input_line_pointer++; - fill = get_absolute_expression (); - pfill = &fill; - } - else - pfill = NULL; - - if (align != 0) - { - alpha_auto_align_on = 1; - alpha_align (align, pfill, alpha_insn_label, 1); - } - else - { - alpha_auto_align_on = 0; - } - - demand_empty_rest_of_line (); -} - -/* Hook the normal string processor to reset known alignment. */ - -static void -s_alpha_stringer (terminate) - int terminate; -{ - alpha_current_align = 0; - alpha_insn_label = NULL; - stringer (terminate); -} - -/* Hook the normal space processing to reset known alignment. */ - -static void -s_alpha_space (ignore) - int ignore; -{ - alpha_current_align = 0; - alpha_insn_label = NULL; - s_space (ignore); -} - -/* Hook into cons for auto-alignment. */ - -void -alpha_cons_align (size) - int size; -{ - int log_size; - - log_size = 0; - while ((size >>= 1) != 0) - ++log_size; - - if (alpha_auto_align_on && alpha_current_align < log_size) - alpha_align (log_size, (char *) NULL, alpha_insn_label, 0); - if (alpha_current_align > log_size) - alpha_current_align = log_size; - alpha_insn_label = NULL; -} - -/* Here come the .uword, .ulong, and .uquad explicitly unaligned - pseudos. We just turn off auto-alignment and call down to cons. */ - -static void -s_alpha_ucons (bytes) - int bytes; -{ - int hold = alpha_auto_align_on; - alpha_auto_align_on = 0; - cons (bytes); - alpha_auto_align_on = hold; -} - -/* Switch the working cpu type. */ - -static void -s_alpha_arch (ignored) - int ignored ATTRIBUTE_UNUSED; -{ - char *name, ch; - const struct cpu_type *p; - - SKIP_WHITESPACE (); - name = input_line_pointer; - ch = get_symbol_end (); - - for (p = cpu_types; p->name; ++p) - if (strcmp(name, p->name) == 0) - { - alpha_target_name = p->name, alpha_target = p->flags; - goto found; - } - as_warn("Unknown CPU identifier `%s'", name); - -found: - *input_line_pointer = ch; - demand_empty_rest_of_line (); -} - - - -#ifdef DEBUG1 -/* print token expression with alpha specific extension. */ - -static void -alpha_print_token(f, exp) - FILE *f; - const expressionS *exp; -{ - switch (exp->X_op) - { - case O_cpregister: - putc (',', f); - /* FALLTHRU */ - case O_pregister: - putc ('(', f); - { - expressionS nexp = *exp; - nexp.X_op = O_register; - print_expr (f, &nexp); - } - putc (')', f); - break; - default: - print_expr (f, exp); - break; - } - return; -} -#endif - -/* The target specific pseudo-ops which we support. */ - -const pseudo_typeS md_pseudo_table[] = -{ -#ifdef OBJ_ECOFF - {"comm", s_alpha_comm, 0}, /* osf1 compiler does this */ - {"rdata", s_alpha_rdata, 0}, -#endif - {"text", s_alpha_text, 0}, - {"data", s_alpha_data, 0}, -#ifdef OBJ_ECOFF - {"sdata", s_alpha_sdata, 0}, -#endif -#ifdef OBJ_ELF - {"section", s_alpha_section, 0}, - {"section.s", s_alpha_section, 0}, - {"sect", s_alpha_section, 0}, - {"sect.s", s_alpha_section, 0}, -#endif -#ifdef OBJ_EVAX - { "pdesc", s_alpha_pdesc, 0}, - { "name", s_alpha_name, 0}, - { "linkage", s_alpha_linkage, 0}, - { "code_address", s_alpha_code_address, 0}, - { "ent", s_alpha_ent, 0}, - { "frame", s_alpha_frame, 0}, - { "fp_save", s_alpha_fp_save, 0}, - { "mask", s_alpha_mask, 0}, - { "fmask", s_alpha_fmask, 0}, - { "end", s_alpha_end, 0}, - { "file", s_alpha_file, 0}, - { "rdata", s_alpha_section, 1}, - { "comm", s_alpha_comm, 0}, - { "link", s_alpha_section, 3}, - { "ctors", s_alpha_section, 4}, - { "dtors", s_alpha_section, 5}, -#endif -#ifdef OBJ_ELF - /* Frame related pseudos. */ - {"ent", s_alpha_ent, 0}, - {"end", s_alpha_end, 0}, - {"mask", s_alpha_mask, 0}, - {"fmask", s_alpha_mask, 1}, - {"frame", s_alpha_frame, 0}, - {"prologue", s_alpha_prologue, 0}, - /* COFF debugging related pseudos. */ - {"begin", s_alpha_coff_wrapper, 0}, - {"bend", s_alpha_coff_wrapper, 1}, - {"def", s_alpha_coff_wrapper, 2}, - {"dim", s_alpha_coff_wrapper, 3}, - {"endef", s_alpha_coff_wrapper, 4}, - {"file", s_alpha_coff_wrapper, 5}, - {"scl", s_alpha_coff_wrapper, 6}, - {"tag", s_alpha_coff_wrapper, 7}, - {"val", s_alpha_coff_wrapper, 8}, - {"loc", s_alpha_coff_wrapper, 9}, -#else - {"prologue", s_ignore, 0}, -#endif - {"gprel32", s_alpha_gprel32, 0}, - {"t_floating", s_alpha_float_cons, 'd'}, - {"s_floating", s_alpha_float_cons, 'f'}, - {"f_floating", s_alpha_float_cons, 'F'}, - {"g_floating", s_alpha_float_cons, 'G'}, - {"d_floating", s_alpha_float_cons, 'D'}, - - {"proc", s_alpha_proc, 0}, - {"aproc", s_alpha_proc, 1}, - {"set", s_alpha_set, 0}, - {"reguse", s_ignore, 0}, - {"livereg", s_ignore, 0}, - {"base", s_alpha_base, 0}, /*??*/ - {"option", s_ignore, 0}, - {"aent", s_ignore, 0}, - {"ugen", s_ignore, 0}, - {"eflag", s_ignore, 0}, - - {"align", s_alpha_align, 0}, - {"double", s_alpha_float_cons, 'd'}, - {"float", s_alpha_float_cons, 'f'}, - {"single", s_alpha_float_cons, 'f'}, - {"ascii", s_alpha_stringer, 0}, - {"asciz", s_alpha_stringer, 1}, - {"string", s_alpha_stringer, 1}, - {"space", s_alpha_space, 0}, - {"skip", s_alpha_space, 0}, - {"zero", s_alpha_space, 0}, - -/* Unaligned data pseudos. */ - {"uword", s_alpha_ucons, 2}, - {"ulong", s_alpha_ucons, 4}, - {"uquad", s_alpha_ucons, 8}, - -#ifdef OBJ_ELF -/* Dwarf wants these versions of unaligned. */ - {"2byte", s_alpha_ucons, 2}, - {"4byte", s_alpha_ucons, 4}, - {"8byte", s_alpha_ucons, 8}, -#endif - -/* We don't do any optimizing, so we can safely ignore these. */ - {"noalias", s_ignore, 0}, - {"alias", s_ignore, 0}, - - {"arch", s_alpha_arch, 0}, - - {NULL, 0, 0}, -}; - - -/* Build a BFD section with its flags set appropriately for the .lita, - .lit8, or .lit4 sections. */ - -static void -create_literal_section (name, secp, symp) - const char *name; - segT *secp; - symbolS **symp; -{ - segT current_section = now_seg; - int current_subsec = now_subseg; - segT new_sec; - - *secp = new_sec = subseg_new (name, 0); - subseg_set (current_section, current_subsec); - bfd_set_section_alignment (stdoutput, new_sec, 4); - bfd_set_section_flags (stdoutput, new_sec, - SEC_RELOC | SEC_ALLOC | SEC_LOAD | SEC_READONLY - | SEC_DATA); - - S_CLEAR_EXTERNAL (*symp = section_symbol (new_sec)); -} - -#ifdef OBJ_ECOFF - -/* @@@ GP selection voodoo. All of this seems overly complicated and - unnecessary; which is the primary reason it's for ECOFF only. */ - -static inline void -maybe_set_gp (sec) - asection *sec; -{ - bfd_vma vma; - if (!sec) - return; - vma = bfd_get_section_vma (foo, sec); - if (vma && vma < alpha_gp_value) - alpha_gp_value = vma; -} - -static void -select_gp_value () -{ - assert (alpha_gp_value == 0); - - /* Get minus-one in whatever width... */ - alpha_gp_value = 0; alpha_gp_value--; - - /* Select the smallest VMA of these existing sections. */ - maybe_set_gp (alpha_lita_section); -#if 0 - /* These were disabled before -- should we use them? */ - maybe_set_gp (sdata); - maybe_set_gp (lit8_sec); - maybe_set_gp (lit4_sec); -#endif - -/* @@ Will a simple 0x8000 work here? If not, why not? */ -#define GP_ADJUSTMENT (0x8000 - 0x10) - - alpha_gp_value += GP_ADJUSTMENT; - - S_SET_VALUE (alpha_gp_symbol, alpha_gp_value); - -#ifdef DEBUG1 - printf (_("Chose GP value of %lx\n"), alpha_gp_value); -#endif -} -#endif /* OBJ_ECOFF */ - -/* Called internally to handle all alignment needs. This takes care - of eliding calls to frag_align if'n the cached current alignment - says we've already got it, as well as taking care of the auto-align - feature wrt labels. */ - -static void -alpha_align (n, pfill, label, force) - int n; - char *pfill; - symbolS *label; - int force ATTRIBUTE_UNUSED; -{ - if (alpha_current_align >= n) - return; - - if (pfill == NULL) - { - if (n > 2 - && (bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE) != 0) - { - static char const unop[4] = { 0x00, 0x00, 0xe0, 0x2f }; - static char const nopunop[8] = { - 0x1f, 0x04, 0xff, 0x47, - 0x00, 0x00, 0xe0, 0x2f - }; - - /* First, make sure we're on a four-byte boundary, in case - someone has been putting .byte values into the text - section. The DEC assembler silently fills with unaligned - no-op instructions. This will zero-fill, then nop-fill - with proper alignment. */ - if (alpha_current_align < 2) - frag_align (2, 0, 0); - if (alpha_current_align < 3) - frag_align_pattern (3, unop, sizeof unop, 0); - if (n > 3) - frag_align_pattern (n, nopunop, sizeof nopunop, 0); - } - else - frag_align (n, 0, 0); - } - else - frag_align (n, *pfill, 0); - - alpha_current_align = n; - - if (label != NULL && S_GET_SEGMENT (label) == now_seg) - { - symbol_set_frag (label, frag_now); - S_SET_VALUE (label, (valueT) frag_now_fix ()); - } - - record_alignment (now_seg, n); - - /* ??? if alpha_flag_relax && force && elf, record the requested alignment - in a reloc for the linker to see. */ -} - -/* The Alpha has support for some VAX floating point types, as well as for - IEEE floating point. We consider IEEE to be the primary floating point - format, and sneak in the VAX floating point support here. */ -#define md_atof vax_md_atof -#include "config/atof-vax.c" diff --git a/contrib/binutils/gas/config/tc-alpha.h b/contrib/binutils/gas/config/tc-alpha.h deleted file mode 100644 index 632b04ebc3cf0..0000000000000 --- a/contrib/binutils/gas/config/tc-alpha.h +++ /dev/null @@ -1,148 +0,0 @@ -/* This file is tc-alpha.h - Copyright (C) 1994, 95, 96, 97, 98, 1999 Free Software Foundation, Inc. - Written by Ken Raeburn <raeburn@cygnus.com>. - - 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. */ - -#define TC_ALPHA - -#define TARGET_BYTES_BIG_ENDIAN 0 - -#define WORKING_DOT_WORD - -#define TARGET_ARCH bfd_arch_alpha - -#define TARGET_FORMAT (OUTPUT_FLAVOR == bfd_target_ecoff_flavour \ - ? "ecoff-littlealpha" \ - : OUTPUT_FLAVOR == bfd_target_elf_flavour \ - ? "elf64-alpha" \ - : OUTPUT_FLAVOR == bfd_target_evax_flavour \ - ? "vms-alpha" \ - : "unknown-format") - -#define NEED_LITERAL_POOL -#define TC_HANDLES_FX_DONE -#define REPEAT_CONS_EXPRESSIONS - -extern int alpha_force_relocation PARAMS ((struct fix *)); -extern int alpha_fix_adjustable PARAMS ((struct fix *)); - -extern unsigned long alpha_gprmask, alpha_fprmask; -extern valueT alpha_gp_value; - -#define TC_FORCE_RELOCATION(FIXP) alpha_force_relocation (FIXP) -#define tc_fix_adjustable(FIXP) alpha_fix_adjustable (FIXP) -#define RELOC_REQUIRES_SYMBOL - -/* 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. This is only used for pcrel relocations. */ - -#define TC_RELOC_RTSYM_LOC_FIXUP(FIX) \ - ((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))) - -#define md_convert_frag(b,s,f) as_fatal ("alpha convert_frag\n") -#define md_estimate_size_before_relax(f,s) \ - (as_fatal("estimate_size_before_relax called"),1) -#define md_operand(x) - -#ifdef OBJ_EVAX - -/* This field keeps the symbols position in the link section. */ -#define OBJ_SYMFIELD_TYPE valueT - -#define TC_CONS_FIX_NEW(FRAG,OFF,LEN,EXP) \ - fix_new_exp (FRAG, OFF, (int)LEN, EXP, 0, \ - LEN == 2 ? BFD_RELOC_16 \ - : LEN == 4 ? BFD_RELOC_32 \ - : LEN == 8 ? BFD_RELOC_64 \ - : BFD_RELOC_ALPHA_LINKAGE); -#endif - -#define md_number_to_chars number_to_chars_littleendian - -extern int tc_get_register PARAMS ((int frame)); -extern void alpha_frob_ecoff_data PARAMS ((void)); - -#define tc_frob_label(sym) alpha_define_label (sym) -extern void alpha_define_label PARAMS ((symbolS *)); - -#define md_cons_align(nbytes) alpha_cons_align (nbytes) -extern void alpha_cons_align PARAMS ((int)); - -#ifdef OBJ_ECOFF -#define tc_frob_file_before_adjust() alpha_frob_file_before_adjust () -extern void alpha_frob_file_before_adjust PARAMS ((void)); -#endif - -#define DIFF_EXPR_OK /* foo-. gets turned into PC relative relocs */ - -#ifdef OBJ_ELF -#define ELF_TC_SPECIAL_SECTIONS \ - { ".sdata", SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_ALPHA_GPREL }, \ - { ".sbss", SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_ALPHA_GPREL }, -#endif - -/* Whether to add support for explict !relocation_op!sequence_number. At the - moment, only do this for ELF, though ECOFF could use it as well. */ - -#ifdef OBJ_ELF -#define RELOC_OP_P -#endif - -#ifdef RELOC_OP_P -/* Before the relocations are written, reorder them, so that user supplied - !lituse relocations follow the appropriate !literal relocations. Also - convert the gas-internal relocations to the appropriate linker relocations. - */ -#define tc_adjust_symtab() alpha_adjust_symtab () -extern void alpha_adjust_symtab PARAMS ((void)); - -/* New fields for supporting explicit relocations (such as !literal to mark - where a pointer is loaded from the global table, and !lituse_base to track - all of the normal uses of that pointer). */ - -#define TC_FIX_TYPE struct alpha_fix_tag - -struct alpha_fix_tag -{ - struct fix *next_lituse; /* next !lituse */ - struct alpha_literal_tag *info; /* other members with same sequence */ -}; - -/* Initialize the TC_FIX_TYPE field. */ -#define TC_INIT_FIX_DATA(fixP) \ -do { \ - fixP->tc_fix_data.next_lituse = (struct fix *)0; \ - fixP->tc_fix_data.info = (struct alpha_literal_tag *)0; \ -} while (0) - -/* Work with DEBUG5 to print fields in tc_fix_type. */ -#define TC_FIX_DATA_PRINT(stream,fixP) \ -do { \ - if (fixP->tc_fix_data.info) \ - fprintf (stderr, "\tinfo = 0x%lx, next_lituse = 0x%lx\n", \ - (long)fixP->tc_fix_data.info, \ - (long)fixP->tc_fix_data.next_lituse); \ -} while (0) -#endif diff --git a/contrib/binutils/gas/config/tc-arc.c b/contrib/binutils/gas/config/tc-arc.c deleted file mode 100644 index 3aafea3648107..0000000000000 --- a/contrib/binutils/gas/config/tc-arc.c +++ /dev/null @@ -1,1484 +0,0 @@ -/* tc-arc.c -- Assembler for the ARC - Copyright (C) 1994, 1995, 1997, 1998, 1999 Free Software Foundation, Inc. - Contributed by Doug Evans (dje@cygnus.com). - - 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. */ - -#include <stdio.h> -#include <ctype.h> -#include "as.h" -#include "subsegs.h" -#include "opcode/arc.h" -#include "elf/arc.h" - -extern int arc_get_mach PARAMS ((char *)); - -static arc_insn arc_insert_operand PARAMS ((arc_insn, - const struct arc_operand *, int, - const struct arc_operand_value *, - offsetT, char *, unsigned int)); -static void arc_common PARAMS ((int)); -static void arc_cpu PARAMS ((int)); -/*static void arc_rename PARAMS ((int));*/ -static int get_arc_exp_reloc_type PARAMS ((int, int, expressionS *, - expressionS *)); - -const pseudo_typeS md_pseudo_table[] = -{ - { "align", s_align_bytes, 0 }, /* Defaulting is invalid (0) */ - { "common", arc_common, 0 }, -/*{ "hword", cons, 2 }, - already exists */ - { "word", cons, 4 }, -/*{ "xword", cons, 8 },*/ - { "cpu", arc_cpu, 0 }, -/*{ "rename", arc_rename, 0 },*/ - { NULL, 0, 0 }, -}; - -/* This array holds the chars that always start a comment. If the - pre-processor is disabled, these aren't very useful */ -const char comment_chars[] = "#;"; - -/* This array holds the chars that only start a comment at the beginning of - a line. If the line seems to have the form '# 123 filename' - .line and .file directives will appear in the pre-processed output */ -/* Note that input_file.c hand checks for '#' at the beginning of the - first line of the input file. This is because the compiler outputs - #NO_APP at the beginning of its output. */ -/* Also note that comments started like this one will always - work if '/' isn't otherwise defined. */ -const char line_comment_chars[] = "#"; - -const char line_separator_chars[] = ""; - -/* Chars that can be used to separate mant from exp in floating point nums */ -const char EXP_CHARS[] = "eE"; - -/* Chars that mean this number is a floating point constant */ -/* As in 0f12.456 */ -/* or 0d1.2345e12 */ -const char FLT_CHARS[] = "rRsSfFdD"; - -/* Byte order. */ -extern int target_big_endian; -const char *arc_target_format = DEFAULT_TARGET_FORMAT; -static int byte_order = DEFAULT_BYTE_ORDER; - -/* One of bfd_mach_arc_xxx. */ -static int arc_mach_type = bfd_mach_arc_base; - -/* Non-zero if the cpu type has been explicitly specified. */ -static int mach_type_specified_p = 0; - -/* Non-zero if opcode tables have been initialized. - A .cpu command must appear before any instructions. */ -static int cpu_tables_init_p = 0; - -static struct hash_control *arc_suffix_hash = NULL; - -const char *md_shortopts = ""; -struct option md_longopts[] = -{ -#define OPTION_EB (OPTION_MD_BASE + 0) - {"EB", no_argument, NULL, OPTION_EB}, -#define OPTION_EL (OPTION_MD_BASE + 1) - {"EL", no_argument, NULL, OPTION_EL}, - { NULL, no_argument, NULL, 0 } -}; -size_t md_longopts_size = sizeof (md_longopts); - -/* - * md_parse_option - * - * Invocation line includes a switch not recognized by the base assembler. - * See if it's a processor-specific option. - */ - -int -md_parse_option (c, arg) - int c; - char *arg; -{ - switch (c) - { - case OPTION_EB: - byte_order = BIG_ENDIAN; - arc_target_format = "elf32-bigarc"; - break; - case OPTION_EL: - byte_order = LITTLE_ENDIAN; - arc_target_format = "elf32-littlearc"; - break; - default: - return 0; - } - return 1; -} - -void -md_show_usage (stream) - FILE *stream; -{ - fprintf (stream, _("\ -ARC options:\n\ --EB generate big endian output\n\ --EL generate little endian output\n")); -} - -/* This function is called once, at assembler startup time. It should - set up all the tables, etc. that the MD part of the assembler will need. - Opcode selection is defered until later because we might see a .cpu - command. */ - -void -md_begin () -{ - /* The endianness can be chosen "at the factory". */ - target_big_endian = byte_order == BIG_ENDIAN; - - if (!bfd_set_arch_mach (stdoutput, bfd_arch_arc, arc_mach_type)) - as_warn (_("could not set architecture and machine")); - - /* Assume the base cpu. This call is necessary because we need to - initialize `arc_operand_map' which may be needed before we see the - first insn. */ - arc_opcode_init_tables (arc_get_opcode_mach (bfd_mach_arc_base, - target_big_endian)); -} - -/* Initialize the various opcode and operand tables. - MACH is one of bfd_mach_arc_xxx. */ - -static void -init_opcode_tables (mach) - int mach; -{ - register unsigned int i; - char *last; - - if ((arc_suffix_hash = hash_new ()) == NULL) - as_fatal (_("virtual memory exhausted")); - - if (!bfd_set_arch_mach (stdoutput, bfd_arch_arc, mach)) - as_warn (_("could not set architecture and machine")); - - /* This initializes a few things in arc-opc.c that we need. - This must be called before the various arc_xxx_supported fns. */ - arc_opcode_init_tables (arc_get_opcode_mach (mach, target_big_endian)); - - /* Only put the first entry of each equivalently named suffix in the - table. */ - last = ""; - for (i = 0; i < arc_suffixes_count; i++) - { - if (! arc_opval_supported (&arc_suffixes[i])) - continue; - if (strcmp (arc_suffixes[i].name, last) != 0) - hash_insert (arc_suffix_hash, arc_suffixes[i].name, (PTR) (arc_suffixes + i)); - last = arc_suffixes[i].name; - } - - /* Since registers don't have a prefix, we put them in the symbol table so - they can't be used as symbols. This also simplifies argument parsing as - we can let gas parse registers for us. The recorded register number is - the index in `arc_reg_names'. */ - for (i = 0; i < arc_reg_names_count; i++) - { - if (! arc_opval_supported (&arc_reg_names[i])) - continue; - /* Use symbol_create here instead of symbol_new so we don't try to - output registers into the object file's symbol table. */ - symbol_table_insert (symbol_create (arc_reg_names[i].name, reg_section, - i, &zero_address_frag)); - } - - /* Tell `s_cpu' it's too late. */ - cpu_tables_init_p = 1; -} - -/* Insert an operand value into an instruction. - If REG is non-NULL, it is a register number and ignore VAL. */ - -static arc_insn -arc_insert_operand (insn, operand, mods, reg, val, file, line) - arc_insn insn; - const struct arc_operand *operand; - int mods; - const struct arc_operand_value *reg; - offsetT val; - char *file; - unsigned int line; -{ - if (operand->bits != 32) - { - long min, max; - offsetT test; - - if ((operand->flags & ARC_OPERAND_SIGNED) != 0) - { - if ((operand->flags & ARC_OPERAND_SIGNOPT) != 0) - max = (1 << operand->bits) - 1; - else - max = (1 << (operand->bits - 1)) - 1; - min = - (1 << (operand->bits - 1)); - } - else - { - max = (1 << operand->bits) - 1; - min = 0; - } - - if ((operand->flags & ARC_OPERAND_NEGATIVE) != 0) - test = - val; - else - test = val; - - if (test < (offsetT) min || test > (offsetT) max) - { - const char *err = - _("operand out of range (%s not between %ld and %ld)"); - char buf[100]; - - sprint_value (buf, test); - if (file == (char *) NULL) - as_warn (err, buf, min, max); - else - as_warn_where (file, line, err, buf, min, max); - } - } - - if (operand->insert) - { - const char *errmsg; - - errmsg = NULL; - insn = (*operand->insert) (insn, operand, mods, reg, (long) val, &errmsg); - if (errmsg != (const char *) NULL) - as_warn (errmsg); - } - else - insn |= (((long) val & ((1 << operand->bits) - 1)) - << operand->shift); - - return insn; -} - -/* We need to keep a list of fixups. We can't simply generate them as - we go, because that would require us to first create the frag, and - that would screw up references to ``.''. */ - -struct arc_fixup -{ - /* index into `arc_operands' */ - int opindex; - expressionS exp; -}; - -#define MAX_FIXUPS 5 - -#define MAX_SUFFIXES 5 - -/* This routine is called for each instruction to be assembled. */ - -void -md_assemble (str) - char *str; -{ - const struct arc_opcode *opcode; - char *start; - arc_insn insn; - static int init_tables_p = 0; - - /* Opcode table initialization is deferred until here because we have to - wait for a possible .cpu command. */ - if (!init_tables_p) - { - init_opcode_tables (arc_mach_type); - init_tables_p = 1; - } - - /* Skip leading white space. */ - while (isspace (*str)) - str++; - - /* The instructions are stored in lists hashed by the first letter (though - we needn't care how they're hashed). Get the first in the list. */ - - opcode = arc_opcode_lookup_asm (str); - - /* Keep looking until we find a match. */ - - start = str; - for ( ; opcode != NULL; opcode = ARC_OPCODE_NEXT_ASM (opcode)) - { - int past_opcode_p, fc, num_suffixes; - char *syn; - struct arc_fixup fixups[MAX_FIXUPS]; - /* Used as a sanity check. If we need a limm reloc, make sure we ask - for an extra 4 bytes from frag_more. */ - int limm_reloc_p; - const struct arc_operand_value *insn_suffixes[MAX_SUFFIXES]; - - /* Is this opcode supported by the selected cpu? */ - if (! arc_opcode_supported (opcode)) - continue; - - /* Scan the syntax string. If it doesn't match, try the next one. */ - - arc_opcode_init_insert (); - insn = opcode->value; - fc = 0; - past_opcode_p = 0; - num_suffixes = 0; - limm_reloc_p = 0; - - /* We don't check for (*str != '\0') here because we want to parse - any trailing fake arguments in the syntax string. */ - for (str = start, syn = opcode->syntax; *syn != '\0'; ) - { - int mods; - const struct arc_operand *operand; - - /* Non operand chars must match exactly. */ - if (*syn != '%' || *++syn == '%') - { - /* Handle '+' specially as we want to allow "ld r0,[sp-4]". */ - /* ??? The syntax has changed to [sp,-4]. */ - if (0 && *syn == '+' && *str == '-') - { - /* Skip over syn's +, but leave str's - alone. - That makes the case identical to "ld r0,[sp+-4]". */ - ++syn; - } - else if (*str == *syn) - { - if (*syn == ' ') - past_opcode_p = 1; - ++syn; - ++str; - } - else - break; - continue; - } - - /* We have an operand. Pick out any modifiers. */ - mods = 0; - while (ARC_MOD_P (arc_operands[arc_operand_map[*syn]].flags)) - { - mods |= arc_operands[arc_operand_map[*syn]].flags & ARC_MOD_BITS; - ++syn; - } - operand = arc_operands + arc_operand_map[*syn]; - if (operand->fmt == 0) - as_fatal (_("unknown syntax format character `%c'"), *syn); - - if (operand->flags & ARC_OPERAND_FAKE) - { - const char *errmsg = NULL; - if (operand->insert) - { - insn = (*operand->insert) (insn, operand, mods, NULL, 0, &errmsg); - /* If we get an error, go on to try the next insn. */ - if (errmsg) - break; - } - ++syn; - } - /* Are we finished with suffixes? */ - else if (!past_opcode_p) - { - int found; - char c; - char *s,*t; - const struct arc_operand_value *suf,*suffix,*suffix_end; - - if (!(operand->flags & ARC_OPERAND_SUFFIX)) - abort (); - - /* If we're at a space in the input string, we want to skip the - remaining suffixes. There may be some fake ones though, so - just go on to try the next one. */ - if (*str == ' ') - { - ++syn; - continue; - } - - s = str; - if (mods & ARC_MOD_DOT) - { - if (*s != '.') - break; - ++s; - } - else - { - /* This can happen in "b.nd foo" and we're currently looking - for "%q" (ie: a condition code suffix). */ - if (*s == '.') - { - ++syn; - continue; - } - } - - /* Pick the suffix out and look it up via the hash table. */ - for (t = s; *t && isalpha (*t); ++t) - continue; - c = *t; - *t = '\0'; - suf = hash_find (arc_suffix_hash, s); - *t = c; - if (!suf) - { - /* This can happen in "blle foo" and we're currently using - the template "b%q%.n %j". The "bl" insn occurs later in - the table so "lle" isn't an illegal suffix. */ - break; - } - - /* Is it the right type? Note that the same character is used - several times, so we have to examine all of them. This is - relatively efficient as equivalent entries are kept - together. If it's not the right type, don't increment `str' - so we try the next one in the series. */ - found = 0; - suffix_end = arc_suffixes + arc_suffixes_count; - for (suffix = suf; - suffix < suffix_end && strcmp (suffix->name, suf->name) == 0; - ++suffix) - { - if (arc_operands[suffix->type].fmt == *syn) - { - /* Insert the suffix's value into the insn. */ - if (operand->insert) - insn = (*operand->insert) (insn, operand, - mods, NULL, suffix->value, - NULL); - else - insn |= suffix->value << operand->shift; - - str = t; - found = 1; - break; - } - } - ++syn; - if (!found) - ; /* Wrong type. Just go on to try next insn entry. */ - else - { - if (num_suffixes == MAX_SUFFIXES) - as_bad (_("too many suffixes")); - else - insn_suffixes[num_suffixes++] = suffix; - } - } - else - /* This is either a register or an expression of some kind. */ - { - char c; - char *hold; - const struct arc_operand_value *reg = NULL; - long value = 0; - expressionS exp; - - if (operand->flags & ARC_OPERAND_SUFFIX) - abort (); - - /* Is there anything left to parse? - We don't check for this at the top because we want to parse - any trailing fake arguments in the syntax string. */ - if (*str == '\0') - break; -#if 0 - /* Is this a syntax character? Eg: is there a '[' present when - there shouldn't be? */ - if (!isalnum (*str) - /* '.' as in ".LLC0" */ - && *str != '.' - /* '_' as in "_print" */ - && *str != '_' - /* '-' as in "[fp,-4]" */ - && *str != '-' - /* '%' as in "%ia(_func)" */ - && *str != '%') - break; -#endif - - /* Parse the operand. */ - hold = input_line_pointer; - input_line_pointer = str; - expression (&exp); - str = input_line_pointer; - input_line_pointer = hold; - - if (exp.X_op == O_illegal) - as_bad (_("illegal operand")); - else if (exp.X_op == O_absent) - as_bad (_("missing operand")); - else if (exp.X_op == O_constant) - { - value = exp.X_add_number; - } - else if (exp.X_op == O_register) - { - reg = arc_reg_names + exp.X_add_number; - } - else - { - /* We need to generate a fixup for this expression. */ - if (fc >= MAX_FIXUPS) - as_fatal (_("too many fixups")); - fixups[fc].exp = exp; - - /* If this is a register constant (IE: one whose - register value gets stored as 61-63) then this - must be a limm. We don't support shimm relocs. */ - /* ??? This bit could use some cleaning up. - Referencing the format chars like this goes - against style. */ -#define IS_REG_OPERAND(o) ((o) == 'a' || (o) == 'b' || (o) == 'c') - if (IS_REG_OPERAND (*syn)) - { - const char *junk; - - fixups[fc].opindex = arc_operand_map['L']; - limm_reloc_p = 1; - /* Tell insert_reg we need a limm. This is - needed because the value at this point is - zero, a shimm. */ - /* ??? We need a cleaner interface than this. */ - (*arc_operands[arc_operand_map['Q']].insert) - (insn, operand, mods, reg, 0L, &junk); - } - else - fixups[fc].opindex = arc_operand_map[*syn]; - ++fc; - value = 0; - } - - /* Insert the register or expression into the instruction. */ - if (operand->insert) - { - const char *errmsg = NULL; - insn = (*operand->insert) (insn, operand, mods, - reg, (long) value, &errmsg); -#if 0 - if (errmsg != (const char *) NULL) - as_warn (errmsg); -#endif - /* FIXME: We want to try shimm insns for limm ones. But if - the constant won't fit, we must go on to try the next - possibility. Where do we issue warnings for constants - that are too big then? At present, we'll flag the insn - as unrecognizable! Maybe have the "bad instruction" - error message include our `errmsg'? */ - if (errmsg != (const char *) NULL) - break; - } - else - insn |= (value & ((1 << operand->bits) - 1)) << operand->shift; - - ++syn; - } - } - - /* If we're at the end of the syntax string, we're done. */ - /* FIXME: try to move this to a separate function. */ - if (*syn == '\0') - { - int i; - char *f; - long limm, limm_p; - - /* For the moment we assume a valid `str' can only contain blanks - now. IE: We needn't try again with a longer version of the - insn and it is assumed that longer versions of insns appear - before shorter ones (eg: lsr r2,r3,1 vs lsr r2,r3). */ - - while (isspace (*str)) - ++str; - - if (*str != '\0') - as_bad (_("junk at end of line: `%s'"), str); - - /* Is there a limm value? */ - limm_p = arc_opcode_limm_p (&limm); - - /* Perform various error and warning tests. */ - - { - static int in_delay_slot_p = 0; - static int prev_insn_needs_cc_nop_p = 0; - /* delay slot type seen */ - int delay_slot_type = ARC_DELAY_NONE; - /* conditional execution flag seen */ - int conditional = 0; - /* 1 if condition codes are being set */ - int cc_set_p = 0; - /* 1 if conditional branch, including `b' "branch always" */ - int cond_branch_p = opcode->flags & ARC_OPCODE_COND_BRANCH; - int need_cc_nop_p = 0; - - for (i = 0; i < num_suffixes; ++i) - { - switch (arc_operands[insn_suffixes[i]->type].fmt) - { - case 'n' : - delay_slot_type = insn_suffixes[i]->value; - break; - case 'q' : - conditional = insn_suffixes[i]->value; - break; - case 'f' : - cc_set_p = 1; - break; - } - } - - /* Putting an insn with a limm value in a delay slot is supposed to - be legal, but let's warn the user anyway. Ditto for 8 byte - jumps with delay slots. */ - if (in_delay_slot_p && limm_p) - as_warn (_("8 byte instruction in delay slot")); - if (delay_slot_type != ARC_DELAY_NONE && limm_p) - as_warn (_("8 byte jump instruction with delay slot")); - in_delay_slot_p = (delay_slot_type != ARC_DELAY_NONE) && !limm_p; - - /* Warn when a conditional branch immediately follows a set of - the condition codes. Note that this needn't be done if the - insn that sets the condition codes uses a limm. */ - if (cond_branch_p && conditional != 0 /* 0 = "always" */ - && prev_insn_needs_cc_nop_p) - as_warn (_("conditional branch follows set of flags")); - prev_insn_needs_cc_nop_p = cc_set_p && !limm_p; - } - - /* Write out the instruction. - It is important to fetch enough space in one call to `frag_more'. - We use (f - frag_now->fr_literal) to compute where we are and we - don't want frag_now to change between calls. */ - if (limm_p) - { - f = frag_more (8); - md_number_to_chars (f, insn, 4); - md_number_to_chars (f + 4, limm, 4); - } - else if (limm_reloc_p) - { - /* We need a limm reloc, but the tables think we don't. */ - abort (); - } - else - { - f = frag_more (4); - md_number_to_chars (f, insn, 4); - } - - /* Create any fixups. */ - for (i = 0; i < fc; ++i) - { - int op_type, reloc_type; - expressionS exptmp; - const struct arc_operand *operand; - - /* Create a fixup for this operand. - At this point we do not use a bfd_reloc_code_real_type for - operands residing in the insn, but instead just use the - operand index. This lets us easily handle fixups for any - operand type, although that is admittedly not a very exciting - feature. We pick a BFD reloc type in md_apply_fix. - - Limm values (4 byte immediate "constants") must be treated - normally because they're not part of the actual insn word - and thus the insertion routines don't handle them. */ - - if (arc_operands[fixups[i].opindex].flags & ARC_OPERAND_LIMM) - { - op_type = fixups[i].opindex; - /* FIXME: can we add this data to the operand table? */ - if (op_type == arc_operand_map['L']) - reloc_type = BFD_RELOC_32; - else if (op_type == arc_operand_map['J']) - reloc_type = BFD_RELOC_ARC_B26; - else - abort (); - reloc_type = get_arc_exp_reloc_type (1, reloc_type, - &fixups[i].exp, - &exptmp); - } - else - { - op_type = get_arc_exp_reloc_type (0, fixups[i].opindex, - &fixups[i].exp, &exptmp); - reloc_type = op_type + (int) BFD_RELOC_UNUSED; - } - operand = &arc_operands[op_type]; - fix_new_exp (frag_now, - ((f - frag_now->fr_literal) - + (operand->flags & ARC_OPERAND_LIMM ? 4 : 0)), 4, - &exptmp, - (operand->flags & ARC_OPERAND_RELATIVE_BRANCH) != 0, - (bfd_reloc_code_real_type) reloc_type); - } - - /* All done. */ - return; - } - - /* Try the next entry. */ - } - - as_bad (_("bad instruction `%s'"), start); -} - -/* ??? This was copied from tc-sparc.c, I think. Is it necessary? */ - -static void -arc_common (ignore) - int ignore; -{ - char *name; - char c; - char *p; - int temp, size; - symbolS *symbolP; - - name = input_line_pointer; - c = get_symbol_end (); - /* just after name is now '\0' */ - p = input_line_pointer; - *p = c; - SKIP_WHITESPACE (); - if (*input_line_pointer != ',') - { - as_bad (_("expected comma after symbol-name")); - ignore_rest_of_line (); - return; - } - input_line_pointer++; /* skip ',' */ - if ((temp = get_absolute_expression ()) < 0) - { - as_bad (_(".COMMon length (%d.) <0! Ignored."), temp); - ignore_rest_of_line (); - return; - } - size = temp; - *p = 0; - symbolP = symbol_find_or_make (name); - *p = c; - if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP)) - { - as_bad (_("ignoring attempt to re-define symbol")); - ignore_rest_of_line (); - return; - } - if (S_GET_VALUE (symbolP) != 0) - { - if (S_GET_VALUE (symbolP) != size) - { - as_warn (_("Length of .comm \"%s\" is already %ld. Not changed to %d."), - S_GET_NAME (symbolP), (long) S_GET_VALUE (symbolP), size); - } - } - assert (symbol_get_frag (symbolP) == &zero_address_frag); - if (*input_line_pointer != ',') - { - as_bad (_("expected comma after common length")); - ignore_rest_of_line (); - return; - } - input_line_pointer++; - SKIP_WHITESPACE (); - if (*input_line_pointer != '"') - { - temp = get_absolute_expression (); - if (temp < 0) - { - temp = 0; - as_warn (_("Common alignment negative; 0 assumed")); - } - if (symbolP->local) - { - segT old_sec; - int old_subsec; - char *p; - int align; - - allocate_bss: - old_sec = now_seg; - old_subsec = now_subseg; - align = temp; - record_alignment (bss_section, align); - subseg_set (bss_section, 0); - if (align) - frag_align (align, 0, 0); - if (S_GET_SEGMENT (symbolP) == bss_section) - symbol_get_frag (symbolP)->fr_symbol = 0; - symbol_set_frag (symbolP, frag_now); - p = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP, - (offsetT) size, (char *) 0); - *p = 0; - S_SET_SEGMENT (symbolP, bss_section); - S_CLEAR_EXTERNAL (symbolP); - subseg_set (old_sec, old_subsec); - } - else - { - allocate_common: - S_SET_VALUE (symbolP, (valueT) size); - S_SET_ALIGN (symbolP, temp); - S_SET_EXTERNAL (symbolP); - S_SET_SEGMENT (symbolP, bfd_com_section_ptr); - } - } - else - { - input_line_pointer++; - /* ??? Some say data, some say bss. */ - if (strncmp (input_line_pointer, ".bss\"", 5) - && strncmp (input_line_pointer, ".data\"", 6)) - { - input_line_pointer--; - goto bad_common_segment; - } - while (*input_line_pointer++ != '"') - ; - goto allocate_common; - } - demand_empty_rest_of_line (); - return; - - { - bad_common_segment: - p = input_line_pointer; - while (*p && *p != '\n') - p++; - c = *p; - *p = '\0'; - as_bad (_("bad .common segment %s"), input_line_pointer + 1); - *p = c; - input_line_pointer = p; - ignore_rest_of_line (); - return; - } -} - -/* Select the cpu we're assembling for. */ - -static void -arc_cpu (ignore) - int ignore; -{ - int mach; - char c; - char *cpu; - - /* If an instruction has already been seen, it's too late. */ - if (cpu_tables_init_p) - { - as_bad (_(".cpu command must appear before any instructions")); - ignore_rest_of_line (); - return; - } - - cpu = input_line_pointer; - c = get_symbol_end (); - mach = arc_get_mach (cpu); - *input_line_pointer = c; - if (mach == -1) - goto bad_cpu; - - demand_empty_rest_of_line (); - - /* The cpu may have been selected on the command line. - The choices must match. */ - /* ??? This was a command line option early on. It's gone now, but - leave this in. */ - if (mach_type_specified_p && mach != arc_mach_type) - as_bad (_(".cpu conflicts with previous value")); - else - { - arc_mach_type = mach; - mach_type_specified_p = 1; - if (!bfd_set_arch_mach (stdoutput, bfd_arch_arc, mach)) - as_warn (_("could not set architecture and machine")); - } - return; - - bad_cpu: - as_bad (_("bad .cpu op")); - ignore_rest_of_line (); -} - -#if 0 -/* The .rename pseudo-op. This is used by gcc to implement - -mmangle-cpu-libgcc. */ - -static void -arc_rename (ignore) - int ignore; -{ - char *name,*new; - char c; - symbolS *sym; - int len; - - name = input_line_pointer; - c = get_symbol_end (); - sym = symbol_find_or_make (name); - *input_line_pointer = c; - - if (*input_line_pointer != ',') - { - as_bad (_("missing rename string")); - ignore_rest_of_line (); - return; - } - ++input_line_pointer; - SKIP_WHITESPACE (); - - name = input_line_pointer; - c = get_symbol_end (); - if (*name == '\0') - { - *input_line_pointer = c; - as_bad (_("invalid symbol to rename to")); - ignore_rest_of_line (); - return; - } - new = (char *) xmalloc (strlen (name) + 1); - strcpy (new, name); - *input_line_pointer = c; - symbol_get_tc (sym)->real_name = new; - - demand_empty_rest_of_line (); -} -#endif - -/* Turn a string in input_line_pointer into a floating point constant of type - type, and store the appropriate bytes in *litP. The number of LITTLENUMS - emitted is stored in *sizeP. - An error message is returned, or NULL on OK. */ - -/* Equal to MAX_PRECISION in atof-ieee.c */ -#define MAX_LITTLENUMS 6 - -char * -md_atof (type, litP, sizeP) - char type; - char *litP; - int *sizeP; -{ - int prec; - LITTLENUM_TYPE words[MAX_LITTLENUMS]; - LITTLENUM_TYPE *wordP; - char *t; - char *atof_ieee (); - - switch (type) - { - case 'f': - case 'F': - prec = 2; - break; - - case 'd': - case 'D': - prec = 4; - break; - - default: - *sizeP = 0; - return _("bad call to md_atof"); - } - - t = atof_ieee (input_line_pointer, type, words); - if (t) - input_line_pointer = t; - *sizeP = prec * sizeof (LITTLENUM_TYPE); - for (wordP = words; prec--;) - { - md_number_to_chars (litP, (valueT) (*wordP++), sizeof (LITTLENUM_TYPE)); - litP += sizeof (LITTLENUM_TYPE); - } - - return NULL; -} - -/* Write a value out to the object file, using the appropriate - endianness. */ - -void -md_number_to_chars (buf, val, n) - char *buf; - valueT val; - int n; -{ - if (target_big_endian) - number_to_chars_bigendian (buf, val, n); - else - number_to_chars_littleendian (buf, val, n); -} - -/* Round up a section size to the appropriate boundary. */ - -valueT -md_section_align (segment, size) - segT segment; - valueT size; -{ - int align = bfd_get_section_alignment (stdoutput, segment); - - return ((size + (1 << align) - 1) & (-1 << align)); -} - -/* We don't have any form of relaxing. */ - -int -md_estimate_size_before_relax (fragp, seg) - fragS *fragp; - asection *seg; -{ - abort (); -} - -/* Convert a machine dependent frag. We never generate these. */ - -void -md_convert_frag (abfd, sec, fragp) - bfd *abfd; - asection *sec; - fragS *fragp; -{ - abort (); -} - -/* Parse an operand that is machine-specific. - - The ARC has a special %-op to adjust addresses so they're usable in - branches. The "st" is short for the STatus register. - ??? Later expand this to take a flags value too. - - ??? We can't create new expression types so we map the %-op's onto the - existing syntax. This means that the user could use the chosen syntax - to achieve the same effect. Perhaps put a special cookie in X_add_number - to mark the expression as special. */ - -void -md_operand (expressionP) - expressionS *expressionP; -{ - char *p = input_line_pointer; - - if (*p == '%' && strncmp (p, "%st(", 4) == 0) - { - input_line_pointer += 4; - expression (expressionP); - if (*input_line_pointer != ')') - { - as_bad (_("missing ')' in %-op")); - return; - } - ++input_line_pointer; - if (expressionP->X_op == O_symbol - && expressionP->X_add_number == 0 - /* I think this test is unnecessary but just as a sanity check... */ - && expressionP->X_op_symbol == NULL) - { - expressionS two; - - expressionP->X_op = O_right_shift; - two.X_op = O_constant; - two.X_add_symbol = two.X_op_symbol = NULL; - two.X_add_number = 2; - expressionP->X_op_symbol = make_expr_symbol (&two); - } - /* allow %st(sym1-sym2) */ - else if (expressionP->X_op == O_subtract - && expressionP->X_add_symbol != NULL - && expressionP->X_op_symbol != NULL - && expressionP->X_add_number == 0) - { - expressionS two; - - expressionP->X_add_symbol = make_expr_symbol (expressionP); - expressionP->X_op = O_right_shift; - two.X_op = O_constant; - two.X_add_symbol = two.X_op_symbol = NULL; - two.X_add_number = 2; - expressionP->X_op_symbol = make_expr_symbol (&two); - } - else - { - as_bad (_("expression too complex for %%st")); - return; - } - } -} - -/* We have no need to default values of symbols. - We could catch register names here, but that is handled by inserting - them all in the symbol table to begin with. */ - -symbolS * -md_undefined_symbol (name) - char *name; -{ - return 0; -} - -/* Functions concerning expressions. */ - -/* Parse a .byte, .word, etc. expression. - - Values for the status register are specified with %st(label). - `label' will be right shifted by 2. */ - -void -arc_parse_cons_expression (exp, nbytes) - expressionS *exp; - int nbytes; -{ - expr (0, exp); -} - -/* Record a fixup for a cons expression. */ - -void -arc_cons_fix_new (frag, where, nbytes, exp) - fragS *frag; - int where; - int nbytes; - expressionS *exp; -{ - if (nbytes == 4) - { - int reloc_type; - expressionS exptmp; - - /* This may be a special ARC reloc (eg: %st()). */ - reloc_type = get_arc_exp_reloc_type (1, BFD_RELOC_32, exp, &exptmp); - fix_new_exp (frag, where, nbytes, &exptmp, 0, reloc_type); - } - else - { - fix_new_exp (frag, where, nbytes, exp, 0, - nbytes == 2 ? BFD_RELOC_16 - : nbytes == 8 ? BFD_RELOC_64 - : BFD_RELOC_32); - } -} - -/* Functions concerning relocs. */ - -/* The location from which a PC relative jump should be calculated, - given a PC relative reloc. */ - -long -md_pcrel_from (fixP) - fixS *fixP; -{ - if (fixP->fx_addsy != (symbolS *) NULL - && ! S_IS_DEFINED (fixP->fx_addsy)) - { - /* The symbol is undefined. Let the linker figure it out. */ - return 0; - } - - /* Return the address of the delay slot. */ - return fixP->fx_frag->fr_address + fixP->fx_where + fixP->fx_size; -} - -/* Compute the reloc type of an expression. - The possibly modified expression is stored in EXPNEW. - - This is used to convert the expressions generated by the %-op's into - the appropriate operand type. It is called for both data in instructions - (operands) and data outside instructions (variables, debugging info, etc.). - - Currently supported %-ops: - - %st(symbol): represented as "symbol >> 2" - "st" is short for STatus as in the status register (pc) - - DEFAULT_TYPE is the type to use if no special processing is required. - - DATA_P is non-zero for data or limm values, zero for insn operands. - Remember that the opcode "insertion fns" cannot be used on data, they're - only for inserting operands into insns. They also can't be used for limm - values as the insertion routines don't handle limm values. When called for - insns we return fudged reloc types (real_value - BFD_RELOC_UNUSED). When - called for data or limm values we use real reloc types. */ - -static int -get_arc_exp_reloc_type (data_p, default_type, exp, expnew) - int data_p; - int default_type; - expressionS *exp; - expressionS *expnew; -{ - /* If the expression is "symbol >> 2" we must change it to just "symbol", - as fix_new_exp can't handle it. Similarily for (symbol - symbol) >> 2. - That's ok though. What's really going on here is that we're using - ">> 2" as a special syntax for specifying BFD_RELOC_ARC_B26. */ - - if (exp->X_op == O_right_shift - && exp->X_op_symbol != NULL - && symbol_constant_p (exp->X_op_symbol) - && S_GET_VALUE (exp->X_op_symbol) == 2 - && exp->X_add_number == 0) - { - if (exp->X_add_symbol != NULL - && (symbol_constant_p (exp->X_add_symbol) - || symbol_equated_p (exp->X_add_symbol))) - { - *expnew = *exp; - expnew->X_op = O_symbol; - expnew->X_op_symbol = NULL; - return data_p ? BFD_RELOC_ARC_B26 : arc_operand_map['J']; - } - else if (exp->X_add_symbol != NULL - && (symbol_get_value_expression (exp->X_add_symbol)->X_op - == O_subtract)) - { - *expnew = *symbol_get_value_expression (exp->X_add_symbol); - return data_p ? BFD_RELOC_ARC_B26 : arc_operand_map['J']; - } - } - - *expnew = *exp; - return default_type; -} - -/* Apply a fixup to the object code. This is called for all the - fixups we generated by the call to fix_new_exp, above. In the call - above we used a reloc code which was the largest legal reloc code - plus the operand index. Here we undo that to recover the operand - index. At this point all symbol values should be fully resolved, - and we attempt to completely resolve the reloc. If we can not do - that, we determine the correct reloc code and put it back in the fixup. */ - -int -md_apply_fix3 (fixP, valueP, seg) - fixS *fixP; - valueT *valueP; - segT seg; -{ - /*char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;*/ - valueT value; - - /* FIXME FIXME FIXME: The value we are passed in *valueP includes - the symbol values. Since we are using BFD_ASSEMBLER, if we are - doing this relocation the code in write.c is going to call - bfd_perform_relocation, which is also going to use the symbol - value. That means that if the reloc is fully resolved we want to - use *valueP since bfd_perform_relocation is not being used. - However, if the reloc is not fully resolved we do not want to use - *valueP, and must use fx_offset instead. However, if the reloc - is PC relative, we do want to use *valueP since it includes the - result of md_pcrel_from. This is confusing. */ - - if (fixP->fx_addsy == (symbolS *) NULL) - { - value = *valueP; - fixP->fx_done = 1; - } - else if (fixP->fx_pcrel) - { - value = *valueP; - /* ELF relocations are against symbols. - If this symbol is in a different section then we need to leave it for - the linker to deal with. Unfortunately, md_pcrel_from can't tell, - so we have to undo it's effects here. */ - if (S_IS_DEFINED (fixP->fx_addsy) - && S_GET_SEGMENT (fixP->fx_addsy) != seg) - value += md_pcrel_from (fixP); - } - else - { - value = fixP->fx_offset; - if (fixP->fx_subsy != (symbolS *) NULL) - { - if (S_GET_SEGMENT (fixP->fx_subsy) == absolute_section) - value -= S_GET_VALUE (fixP->fx_subsy); - else - { - /* We can't actually support subtracting a symbol. */ - as_bad_where (fixP->fx_file, fixP->fx_line, - _("expression too complex")); - } - } - } - - if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED) - { - int opindex; - const struct arc_operand *operand; - char *where; - arc_insn insn; - - opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED; - - operand = &arc_operands[opindex]; - - /* Fetch the instruction, insert the fully resolved operand - value, and stuff the instruction back again. */ - where = fixP->fx_frag->fr_literal + fixP->fx_where; - if (target_big_endian) - insn = bfd_getb32 ((unsigned char *) where); - else - insn = bfd_getl32 ((unsigned char *) where); - insn = arc_insert_operand (insn, operand, -1, NULL, (offsetT) value, - fixP->fx_file, fixP->fx_line); - if (target_big_endian) - bfd_putb32 ((bfd_vma) insn, (unsigned char *) where); - else - bfd_putl32 ((bfd_vma) insn, (unsigned char *) where); - - if (fixP->fx_done) - { - /* Nothing else to do here. */ - return 1; - } - - /* Determine a BFD reloc value based on the operand information. - We are only prepared to turn a few of the operands into relocs. - !!! Note that we can't handle limm values here. Since we're using - implicit addends the addend must be inserted into the instruction, - however, the opcode insertion routines currently do nothing with - limm values. */ - if (operand->fmt == 'B') - { - assert ((operand->flags & ARC_OPERAND_RELATIVE_BRANCH) != 0 - && operand->bits == 20 - && operand->shift == 7); - fixP->fx_r_type = BFD_RELOC_ARC_B22_PCREL; - } - else if (0 && operand->fmt == 'J') - { - assert ((operand->flags & ARC_OPERAND_ABSOLUTE_BRANCH) != 0 - && operand->bits == 24 - && operand->shift == 32); - fixP->fx_r_type = BFD_RELOC_ARC_B26; - } - else if (0 && operand->fmt == 'L') - { - assert ((operand->flags & ARC_OPERAND_LIMM) != 0 - && operand->bits == 32 - && operand->shift == 32); - fixP->fx_r_type = BFD_RELOC_32; - } - else - { - as_bad_where (fixP->fx_file, fixP->fx_line, - _("unresolved expression that must be resolved")); - fixP->fx_done = 1; - return 1; - } - } - else - { - switch (fixP->fx_r_type) - { - case BFD_RELOC_8: - md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, - value, 1); - break; - case BFD_RELOC_16: - md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, - value, 2); - break; - case BFD_RELOC_32: - md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, - value, 4); - break; -#if 0 - case BFD_RELOC_64: - md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, - value, 8); - break; -#endif - case BFD_RELOC_ARC_B26: - /* If !fixP->fx_done then `value' is an implicit addend. - We must shift it right by 2 in this case as well because the - linker performs the relocation and then adds this in (as opposed - to adding this in and then shifting right by 2). */ - value >>= 2; - md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where, - value, 4); - break; - default: - abort (); - } - } - - fixP->fx_addnumber = value; - - return 1; -} - -/* Translate internal representation of relocation info to BFD target - format. */ - -arelent * -tc_gen_reloc (section, fixP) - asection *section; - fixS *fixP; -{ - arelent *reloc; - - reloc = (arelent *) xmalloc (sizeof (arelent)); - - reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); - *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy); - reloc->address = fixP->fx_frag->fr_address + fixP->fx_where; - reloc->howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type); - if (reloc->howto == (reloc_howto_type *) NULL) - { - as_bad_where (fixP->fx_file, fixP->fx_line, - _("internal error: can't export reloc type %d (`%s')"), - fixP->fx_r_type, bfd_get_reloc_code_name (fixP->fx_r_type)); - return NULL; - } - - assert (!fixP->fx_pcrel == !reloc->howto->pc_relative); - - reloc->addend = fixP->fx_addnumber; - - return reloc; -} - -/* Frobbers. */ - -#if 0 -/* Set the real name if the .rename pseudo-op was used. - Return 1 if the symbol should not be included in the symbol table. */ - -int -arc_frob_symbol (sym) - symbolS *sym; -{ - if (symbol_get_tc (sym)->real_name != (char *) NULL) - S_SET_NAME (sym, symbol_get_tc (sym)->real_name); - - return 0; -} -#endif diff --git a/contrib/binutils/gas/config/tc-arc.h b/contrib/binutils/gas/config/tc-arc.h deleted file mode 100644 index 5066201e73bbe..0000000000000 --- a/contrib/binutils/gas/config/tc-arc.h +++ /dev/null @@ -1,71 +0,0 @@ -/* tc-arc.h - Macros and type defines for the ARC. - Copyright (C) 1994, 1995, 1997, 1999 Free Software Foundation, Inc. - Contributed by Doug Evans (dje@cygnus.com). - - 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. */ - -#define TC_ARC 1 - -#define TARGET_BYTES_BIG_ENDIAN 0 - -#define LOCAL_LABELS_FB 1 - -#define TARGET_ARCH bfd_arch_arc - -#define LITTLE_ENDIAN 1234 -#define BIG_ENDIAN 4321 - -/* The endianness of the target format may change based on command - line arguments. */ -extern const char *arc_target_format; -#define DEFAULT_TARGET_FORMAT "elf32-littlearc" -#define TARGET_FORMAT arc_target_format -#define DEFAULT_BYTE_ORDER LITTLE_ENDIAN - -#define WORKING_DOT_WORD - -#define LISTING_HEADER "ARC GAS " - -#define TC_HANDLES_FX_DONE - -#define MD_APPLY_FIX3 - -/* The ARC needs to parse reloc specifiers in .word. */ - -extern void arc_parse_cons_expression (); -#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) \ -arc_parse_cons_expression (EXP, NBYTES) - -extern void arc_cons_fix_new (); -#define TC_CONS_FIX_NEW(FRAG, WHERE, NBYTES, EXP) \ -arc_cons_fix_new (FRAG, WHERE, NBYTES, EXP) - -#if 0 -/* Extra stuff that we need to keep track of for each symbol. */ -struct arc_tc_sy -{ - /* The real name, if the symbol was renamed. */ - char *real_name; -}; - -#define TC_SYMFIELD_TYPE struct arc_tc_sy - -/* Finish up the symbol. */ -extern int arc_frob_symbol PARAMS ((symbolS *)); -#define tc_frob_symbol(sym, punt) punt = arc_frob_symbol (sym) -#endif diff --git a/contrib/binutils/gas/config/tc-arm.c b/contrib/binutils/gas/config/tc-arm.c deleted file mode 100644 index 4779b3db85f6d..0000000000000 --- a/contrib/binutils/gas/config/tc-arm.c +++ /dev/null @@ -1,7204 +0,0 @@ -/* tc-arm.c -- Assemble for the ARM - Copyright (C) 1994, 95, 96, 97, 98, 1999, 2000 Free Software Foundation, Inc. - Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org) - Modified by David Taylor (dtaylor@armltd.co.uk) - - 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. */ - -#include <ctype.h> -#include <string.h> -#define NO_RELOC 0 -#include "as.h" - -/* need TARGET_CPU */ -#include "config.h" -#include "subsegs.h" -#include "obstack.h" -#include "symbols.h" -#include "listing.h" - -#ifdef OBJ_ELF -#include "elf/arm.h" -#endif - -/* Types of processor to assemble for. */ -#define ARM_1 0x00000001 -#define ARM_2 0x00000002 -#define ARM_3 0x00000004 -#define ARM_250 ARM_3 -#define ARM_6 0x00000008 -#define ARM_7 ARM_6 /* same core instruction set */ -#define ARM_8 ARM_6 /* same core instruction set */ -#define ARM_9 ARM_6 /* same core instruction set */ -#define ARM_CPU_MASK 0x0000000f - -/* The following bitmasks control CPU extensions (ARM7 onwards): */ -#define ARM_LONGMUL 0x00000010 /* allow long multiplies */ -#define ARM_HALFWORD 0x00000020 /* allow half word loads */ -#define ARM_THUMB 0x00000040 /* allow BX instruction */ -#define ARM_EXT_V5 0x00000080 /* allow CLZ etc */ -#define ARM_EXT_V5E 0x00000200 /* "El Segundo" */ - -/* Architectures are the sum of the base and extensions. */ -#define ARM_ARCH_V4 (ARM_7 | ARM_LONGMUL | ARM_HALFWORD) -#define ARM_ARCH_V4T (ARM_ARCH_V4 | ARM_THUMB) -#define ARM_ARCH_V5 (ARM_ARCH_V4 | ARM_EXT_V5) -#define ARM_ARCH_V5T (ARM_ARCH_V5 | ARM_THUMB) - -/* Some useful combinations: */ -#define ARM_ANY 0x00ffffff -#define ARM_2UP (ARM_ANY - ARM_1) -#define ARM_ALL ARM_2UP /* Not arm1 only */ -#define ARM_3UP 0x00fffffc -#define ARM_6UP 0x00fffff8 /* Includes ARM7 */ - -#define FPU_CORE 0x80000000 -#define FPU_FPA10 0x40000000 -#define FPU_FPA11 0x40000000 -#define FPU_NONE 0 - -/* Some useful combinations */ -#define FPU_ALL 0xff000000 /* Note this is ~ARM_ANY */ -#define FPU_MEMMULTI 0x7f000000 /* Not fpu_core */ - - -#ifndef CPU_DEFAULT -#if defined __thumb__ -#define CPU_DEFAULT (ARM_ARCH_V4 | ARM_THUMB) -#else -#define CPU_DEFAULT ARM_ALL -#endif -#endif - -#ifndef FPU_DEFAULT -#define FPU_DEFAULT FPU_ALL -#endif - -#define streq(a, b) (strcmp (a, b) == 0) -#define skip_whitespace(str) while (* (str) == ' ') ++ (str) - -static unsigned long cpu_variant = CPU_DEFAULT | FPU_DEFAULT; -static int target_oabi = 0; - -#if defined OBJ_COFF || defined OBJ_ELF -/* Flags stored in private area of BFD structure */ -static boolean uses_apcs_26 = false; -static boolean support_interwork = false; -static boolean uses_apcs_float = false; -static boolean pic_code = false; -#endif - -/* This array holds the chars that always start a comment. If the - pre-processor is disabled, these aren't very useful. */ -CONST char comment_chars[] = "@"; - -/* This array holds the chars that only start a comment at the beginning of - a line. If the line seems to have the form '# 123 filename' - .line and .file directives will appear in the pre-processed output. */ -/* Note that input_file.c hand checks for '#' at the beginning of the - first line of the input file. This is because the compiler outputs - #NO_APP at the beginning of its output. */ -/* Also note that comments like this one will always work. */ -CONST char line_comment_chars[] = "#"; - -#ifdef TE_LINUX -CONST char line_separator_chars[] = ";"; -#else -CONST char line_separator_chars[] = ""; -#endif - -/* Chars that can be used to separate mant - from exp in floating point numbers. */ -CONST char EXP_CHARS[] = "eE"; - -/* Chars that mean this number is a floating point constant */ -/* As in 0f12.456 */ -/* or 0d1.2345e12 */ - -CONST char FLT_CHARS[] = "rRsSfFdDxXeEpP"; - -/* Prefix characters that indicate the start of an immediate - value. */ -#define is_immediate_prefix(C) ((C) == '#' || (C) == '$') - -#ifdef OBJ_ELF -symbolS * GOT_symbol; /* Pre-defined "_GLOBAL_OFFSET_TABLE_" */ -#endif - -CONST int md_reloc_size = 8; /* Size of relocation record */ - -static int thumb_mode = 0; /* 0: assemble for ARM, 1: assemble for Thumb, - 2: assemble for Thumb even though target cpu - does not support thumb instructions. */ -typedef struct arm_fix -{ - int thumb_mode; -} arm_fix_data; - -struct arm_it -{ - CONST char * error; - unsigned long instruction; - int suffix; - int size; - struct - { - bfd_reloc_code_real_type type; - expressionS exp; - int pc_rel; - } reloc; -}; - -struct arm_it inst; - -struct asm_shift -{ - CONST char * template; - unsigned long value; -}; - -static CONST struct asm_shift shift[] = -{ - {"asl", 0}, - {"lsl", 0}, - {"lsr", 0x00000020}, - {"asr", 0x00000040}, - {"ror", 0x00000060}, - {"rrx", 0x00000060}, - {"ASL", 0}, - {"LSL", 0}, - {"LSR", 0x00000020}, - {"ASR", 0x00000040}, - {"ROR", 0x00000060}, - {"RRX", 0x00000060} -}; - -#define NO_SHIFT_RESTRICT 1 -#define SHIFT_RESTRICT 0 - -#define NUM_FLOAT_VALS 8 - -CONST char * fp_const[] = -{ - "0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0", 0 -}; - -/* Number of littlenums required to hold an extended precision number. */ -#define MAX_LITTLENUMS 6 - -LITTLENUM_TYPE fp_values[NUM_FLOAT_VALS][MAX_LITTLENUMS]; - -#define FAIL (-1) -#define SUCCESS (0) - -#define SUFF_S 1 -#define SUFF_D 2 -#define SUFF_E 3 -#define SUFF_P 4 - -#define CP_T_X 0x00008000 -#define CP_T_Y 0x00400000 -#define CP_T_Pre 0x01000000 -#define CP_T_UD 0x00800000 -#define CP_T_WB 0x00200000 - -#define CONDS_BIT (0x00100000) -#define LOAD_BIT (0x00100000) -#define TRANS_BIT (0x00200000) - -struct asm_cond -{ - CONST char * template; - unsigned long value; -}; - -/* This is to save a hash look-up in the common case. */ -#define COND_ALWAYS 0xe0000000 - -static CONST struct asm_cond conds[] = -{ - {"eq", 0x00000000}, - {"ne", 0x10000000}, - {"cs", 0x20000000}, {"hs", 0x20000000}, - {"cc", 0x30000000}, {"ul", 0x30000000}, {"lo", 0x30000000}, - {"mi", 0x40000000}, - {"pl", 0x50000000}, - {"vs", 0x60000000}, - {"vc", 0x70000000}, - {"hi", 0x80000000}, - {"ls", 0x90000000}, - {"ge", 0xa0000000}, - {"lt", 0xb0000000}, - {"gt", 0xc0000000}, - {"le", 0xd0000000}, - {"al", 0xe0000000}, - {"nv", 0xf0000000} -}; - -/* Warning: If the top bit of the set_bits is set, then the standard - instruction bitmask is ignored, and the new bitmask is taken from - the set_bits: */ -struct asm_flg -{ - CONST char * template; /* Basic flag string */ - unsigned long set_bits; /* Bits to set */ -}; - -static CONST struct asm_flg s_flag[] = -{ - {"s", CONDS_BIT}, - {NULL, 0} -}; - -static CONST struct asm_flg ldr_flags[] = -{ - {"b", 0x00400000}, - {"t", TRANS_BIT}, - {"bt", 0x00400000 | TRANS_BIT}, - {"h", 0x801000b0}, - {"sh", 0x801000f0}, - {"sb", 0x801000d0}, - {NULL, 0} -}; - -static CONST struct asm_flg str_flags[] = -{ - {"b", 0x00400000}, - {"t", TRANS_BIT}, - {"bt", 0x00400000 | TRANS_BIT}, - {"h", 0x800000b0}, - {NULL, 0} -}; - -static CONST struct asm_flg byte_flag[] = -{ - {"b", 0x00400000}, - {NULL, 0} -}; - -static CONST struct asm_flg cmp_flags[] = -{ - {"s", CONDS_BIT}, - {"p", 0x0010f000}, - {NULL, 0} -}; - -static CONST struct asm_flg ldm_flags[] = -{ - {"ed", 0x01800000}, - {"fd", 0x00800000}, - {"ea", 0x01000000}, - {"fa", 0x08000000}, - {"ib", 0x01800000}, - {"ia", 0x00800000}, - {"db", 0x01000000}, - {"da", 0x08000000}, - {NULL, 0} -}; - -static CONST struct asm_flg stm_flags[] = -{ - {"ed", 0x08000000}, - {"fd", 0x01000000}, - {"ea", 0x00800000}, - {"fa", 0x01800000}, - {"ib", 0x01800000}, - {"ia", 0x00800000}, - {"db", 0x01000000}, - {"da", 0x08000000}, - {NULL, 0} -}; - -static CONST struct asm_flg lfm_flags[] = -{ - {"fd", 0x00800000}, - {"ea", 0x01000000}, - {NULL, 0} -}; - -static CONST struct asm_flg sfm_flags[] = -{ - {"fd", 0x01000000}, - {"ea", 0x00800000}, - {NULL, 0} -}; - -static CONST struct asm_flg round_flags[] = -{ - {"p", 0x00000020}, - {"m", 0x00000040}, - {"z", 0x00000060}, - {NULL, 0} -}; - -/* The implementation of the FIX instruction is broken on some assemblers, - in that it accepts a precision specifier as well as a rounding specifier, - despite the fact that this is meaningless. To be more compatible, we - accept it as well, though of course it does not set any bits. */ -static CONST struct asm_flg fix_flags[] = -{ - {"p", 0x00000020}, - {"m", 0x00000040}, - {"z", 0x00000060}, - {"sp", 0x00000020}, - {"sm", 0x00000040}, - {"sz", 0x00000060}, - {"dp", 0x00000020}, - {"dm", 0x00000040}, - {"dz", 0x00000060}, - {"ep", 0x00000020}, - {"em", 0x00000040}, - {"ez", 0x00000060}, - {NULL, 0} -}; - -static CONST struct asm_flg except_flag[] = -{ - {"e", 0x00400000}, - {NULL, 0} -}; - -static CONST struct asm_flg cplong_flag[] = -{ - {"l", 0x00400000}, - {NULL, 0} -}; - -struct asm_psr -{ - CONST char * template; - unsigned long number; -}; - -#define PSR_FIELD_MASK 0x000f0000 - -#define PSR_FLAGS 0x00080000 -#define PSR_CONTROL 0x00010000 /* Undocumented instruction, its use is discouraged by ARM */ -#define PSR_ALL 0x00090000 - -#define CPSR_ALL 0 -#define SPSR_ALL 1 -#define CPSR_FLG 2 -#define SPSR_FLG 3 -#define CPSR_CTL 4 -#define SPSR_CTL 5 - -static CONST struct asm_psr psrs[] = -{ - /* Valid <psr>'s */ - {"cpsr", CPSR_ALL}, - {"cpsr_all", CPSR_ALL}, - {"spsr", SPSR_ALL}, - {"spsr_all", SPSR_ALL}, - - /* Valid <psrf>'s */ - {"cpsr_flg", CPSR_FLG}, - {"spsr_flg", SPSR_FLG}, - - /* Valid <psrc>'s */ - {"cpsr_c", CPSR_CTL}, - {"cpsr_ctl", CPSR_CTL}, - {"spsr_c", SPSR_CTL}, - {"spsr_ctl", SPSR_CTL} -}; - -/* Functions called by parser. */ -/* ARM instructions */ -static void do_arit PARAMS ((char *, unsigned long)); -static void do_cmp PARAMS ((char *, unsigned long)); -static void do_mov PARAMS ((char *, unsigned long)); -static void do_ldst PARAMS ((char *, unsigned long)); -static void do_ldmstm PARAMS ((char *, unsigned long)); -static void do_branch PARAMS ((char *, unsigned long)); -static void do_swi PARAMS ((char *, unsigned long)); -/* Pseudo Op codes */ -static void do_adr PARAMS ((char *, unsigned long)); -static void do_adrl PARAMS ((char *, unsigned long)); -static void do_nop PARAMS ((char *, unsigned long)); -/* ARM 2 */ -static void do_mul PARAMS ((char *, unsigned long)); -static void do_mla PARAMS ((char *, unsigned long)); -/* ARM 3 */ -static void do_swap PARAMS ((char *, unsigned long)); -/* ARM 6 */ -static void do_msr PARAMS ((char *, unsigned long)); -static void do_mrs PARAMS ((char *, unsigned long)); -/* ARM 7M */ -static void do_mull PARAMS ((char *, unsigned long)); -/* ARM THUMB */ -static void do_bx PARAMS ((char *, unsigned long)); - - -/* Coprocessor Instructions */ -static void do_cdp PARAMS ((char *, unsigned long)); -static void do_lstc PARAMS ((char *, unsigned long)); -static void do_co_reg PARAMS ((char *, unsigned long)); -static void do_fp_ctrl PARAMS ((char *, unsigned long)); -static void do_fp_ldst PARAMS ((char *, unsigned long)); -static void do_fp_ldmstm PARAMS ((char *, unsigned long)); -static void do_fp_dyadic PARAMS ((char *, unsigned long)); -static void do_fp_monadic PARAMS ((char *, unsigned long)); -static void do_fp_cmp PARAMS ((char *, unsigned long)); -static void do_fp_from_reg PARAMS ((char *, unsigned long)); -static void do_fp_to_reg PARAMS ((char *, unsigned long)); - -static void fix_new_arm PARAMS ((fragS *, int, short, expressionS *, int, int)); -static int arm_reg_parse PARAMS ((char **)); -static int arm_psr_parse PARAMS ((char **)); -static void symbol_locate PARAMS ((symbolS *, CONST char *, segT, valueT, fragS *)); -static int add_to_lit_pool PARAMS ((void)); -static unsigned validate_immediate PARAMS ((unsigned)); -static unsigned validate_immediate_twopart PARAMS ((unsigned int, unsigned int *)); -static int validate_offset_imm PARAMS ((unsigned int, int)); -static void opcode_select PARAMS ((int)); -static void end_of_line PARAMS ((char *)); -static int reg_required_here PARAMS ((char **, int)); -static int psr_required_here PARAMS ((char **, int, int)); -static int co_proc_number PARAMS ((char **)); -static int cp_opc_expr PARAMS ((char **, int, int)); -static int cp_reg_required_here PARAMS ((char **, int)); -static int fp_reg_required_here PARAMS ((char **, int)); -static int cp_address_offset PARAMS ((char **)); -static int cp_address_required_here PARAMS ((char **)); -static int my_get_float_expression PARAMS ((char **)); -static int skip_past_comma PARAMS ((char **)); -static int walk_no_bignums PARAMS ((symbolS *)); -static int negate_data_op PARAMS ((unsigned long *, unsigned long)); -static int data_op2 PARAMS ((char **)); -static int fp_op2 PARAMS ((char **)); -static long reg_list PARAMS ((char **)); -static void thumb_load_store PARAMS ((char *, int, int)); -static int decode_shift PARAMS ((char **, int)); -static int ldst_extend PARAMS ((char **, int)); -static void thumb_add_sub PARAMS ((char *, int)); -static void insert_reg PARAMS ((int)); -static void thumb_shift PARAMS ((char *, int)); -static void thumb_mov_compare PARAMS ((char *, int)); -static void set_constant_flonums PARAMS ((void)); -static valueT md_chars_to_number PARAMS ((char *, int)); -static void insert_reg_alias PARAMS ((char *, int)); -static void output_inst PARAMS ((void)); -#ifdef OBJ_ELF -static bfd_reloc_code_real_type arm_parse_reloc PARAMS ((void)); -#endif - -/* ARM instructions take 4bytes in the object file, Thumb instructions - take 2: */ -#define INSN_SIZE 4 - -/* LONGEST_INST is the longest basic instruction name without conditions or - flags. ARM7M has 4 of length 5. */ - -#define LONGEST_INST 5 - - -struct asm_opcode -{ - CONST char * template; /* Basic string to match */ - unsigned long value; /* Basic instruction code */ - - /* Compulsory suffix that must follow conds. If "", then the - instruction is not conditional and must have no suffix. */ - CONST char * comp_suffix; - - CONST struct asm_flg * flags; /* Bits to toggle if flag 'n' set */ - unsigned long variants; /* Which CPU variants this exists for */ - /* Function to call to parse args */ - void (* parms) PARAMS ((char *, unsigned long)); -}; - -static CONST struct asm_opcode insns[] = -{ -/* ARM Instructions */ - {"and", 0x00000000, NULL, s_flag, ARM_ANY, do_arit}, - {"eor", 0x00200000, NULL, s_flag, ARM_ANY, do_arit}, - {"sub", 0x00400000, NULL, s_flag, ARM_ANY, do_arit}, - {"rsb", 0x00600000, NULL, s_flag, ARM_ANY, do_arit}, - {"add", 0x00800000, NULL, s_flag, ARM_ANY, do_arit}, - {"adc", 0x00a00000, NULL, s_flag, ARM_ANY, do_arit}, - {"sbc", 0x00c00000, NULL, s_flag, ARM_ANY, do_arit}, - {"rsc", 0x00e00000, NULL, s_flag, ARM_ANY, do_arit}, - {"orr", 0x01800000, NULL, s_flag, ARM_ANY, do_arit}, - {"bic", 0x01c00000, NULL, s_flag, ARM_ANY, do_arit}, - {"tst", 0x01000000, NULL, cmp_flags, ARM_ANY, do_cmp}, - {"teq", 0x01200000, NULL, cmp_flags, ARM_ANY, do_cmp}, - {"cmp", 0x01400000, NULL, cmp_flags, ARM_ANY, do_cmp}, - {"cmn", 0x01600000, NULL, cmp_flags, ARM_ANY, do_cmp}, - {"mov", 0x01a00000, NULL, s_flag, ARM_ANY, do_mov}, - {"mvn", 0x01e00000, NULL, s_flag, ARM_ANY, do_mov}, - {"str", 0x04000000, NULL, str_flags, ARM_ANY, do_ldst}, - {"ldr", 0x04100000, NULL, ldr_flags, ARM_ANY, do_ldst}, - {"stm", 0x08000000, NULL, stm_flags, ARM_ANY, do_ldmstm}, - {"ldm", 0x08100000, NULL, ldm_flags, ARM_ANY, do_ldmstm}, - {"swi", 0x0f000000, NULL, NULL, ARM_ANY, do_swi}, -#ifdef TE_WINCE - {"bl", 0x0b000000, NULL, NULL, ARM_ANY, do_branch}, - {"b", 0x0a000000, NULL, NULL, ARM_ANY, do_branch}, -#else - {"bl", 0x0bfffffe, NULL, NULL, ARM_ANY, do_branch}, - {"b", 0x0afffffe, NULL, NULL, ARM_ANY, do_branch}, -#endif - -/* Pseudo ops */ - {"adr", 0x028f0000, NULL, NULL, ARM_ANY, do_adr}, - {"adrl", 0x028f0000, NULL, NULL, ARM_ANY, do_adrl}, - {"nop", 0x01a00000, NULL, NULL, ARM_ANY, do_nop}, - -/* ARM 2 multiplies */ - {"mul", 0x00000090, NULL, s_flag, ARM_2UP, do_mul}, - {"mla", 0x00200090, NULL, s_flag, ARM_2UP, do_mla}, - -/* ARM 3 - swp instructions */ - {"swp", 0x01000090, NULL, byte_flag, ARM_3UP, do_swap}, - -/* ARM 6 Coprocessor instructions */ - {"mrs", 0x010f0000, NULL, NULL, ARM_6UP, do_mrs}, - {"msr", 0x0120f000, NULL, NULL, ARM_6UP, do_msr}, -/* ScottB: our code uses 0x0128f000 for msr. - NickC: but this is wrong because the bits 16 and 19 are handled - by the PSR_xxx defines above. */ - -/* ARM 7M long multiplies - need signed/unsigned flags! */ - {"smull", 0x00c00090, NULL, s_flag, ARM_LONGMUL, do_mull}, - {"umull", 0x00800090, NULL, s_flag, ARM_LONGMUL, do_mull}, - {"smlal", 0x00e00090, NULL, s_flag, ARM_LONGMUL, do_mull}, - {"umlal", 0x00a00090, NULL, s_flag, ARM_LONGMUL, do_mull}, - -/* ARM THUMB interworking */ - {"bx", 0x012fff10, NULL, NULL, ARM_THUMB, do_bx}, - -/* Floating point instructions */ - {"wfs", 0x0e200110, NULL, NULL, FPU_ALL, do_fp_ctrl}, - {"rfs", 0x0e300110, NULL, NULL, FPU_ALL, do_fp_ctrl}, - {"wfc", 0x0e400110, NULL, NULL, FPU_ALL, do_fp_ctrl}, - {"rfc", 0x0e500110, NULL, NULL, FPU_ALL, do_fp_ctrl}, - {"ldf", 0x0c100100, "sdep", NULL, FPU_ALL, do_fp_ldst}, - {"stf", 0x0c000100, "sdep", NULL, FPU_ALL, do_fp_ldst}, - {"lfm", 0x0c100200, NULL, lfm_flags, FPU_MEMMULTI, do_fp_ldmstm}, - {"sfm", 0x0c000200, NULL, sfm_flags, FPU_MEMMULTI, do_fp_ldmstm}, - {"mvf", 0x0e008100, "sde", round_flags, FPU_ALL, do_fp_monadic}, - {"mnf", 0x0e108100, "sde", round_flags, FPU_ALL, do_fp_monadic}, - {"abs", 0x0e208100, "sde", round_flags, FPU_ALL, do_fp_monadic}, - {"rnd", 0x0e308100, "sde", round_flags, FPU_ALL, do_fp_monadic}, - {"sqt", 0x0e408100, "sde", round_flags, FPU_ALL, do_fp_monadic}, - {"log", 0x0e508100, "sde", round_flags, FPU_ALL, do_fp_monadic}, - {"lgn", 0x0e608100, "sde", round_flags, FPU_ALL, do_fp_monadic}, - {"exp", 0x0e708100, "sde", round_flags, FPU_ALL, do_fp_monadic}, - {"sin", 0x0e808100, "sde", round_flags, FPU_ALL, do_fp_monadic}, - {"cos", 0x0e908100, "sde", round_flags, FPU_ALL, do_fp_monadic}, - {"tan", 0x0ea08100, "sde", round_flags, FPU_ALL, do_fp_monadic}, - {"asn", 0x0eb08100, "sde", round_flags, FPU_ALL, do_fp_monadic}, - {"acs", 0x0ec08100, "sde", round_flags, FPU_ALL, do_fp_monadic}, - {"atn", 0x0ed08100, "sde", round_flags, FPU_ALL, do_fp_monadic}, - {"urd", 0x0ee08100, "sde", round_flags, FPU_ALL, do_fp_monadic}, - {"nrm", 0x0ef08100, "sde", round_flags, FPU_ALL, do_fp_monadic}, - {"adf", 0x0e000100, "sde", round_flags, FPU_ALL, do_fp_dyadic}, - {"suf", 0x0e200100, "sde", round_flags, FPU_ALL, do_fp_dyadic}, - {"rsf", 0x0e300100, "sde", round_flags, FPU_ALL, do_fp_dyadic}, - {"muf", 0x0e100100, "sde", round_flags, FPU_ALL, do_fp_dyadic}, - {"dvf", 0x0e400100, "sde", round_flags, FPU_ALL, do_fp_dyadic}, - {"rdf", 0x0e500100, "sde", round_flags, FPU_ALL, do_fp_dyadic}, - {"pow", 0x0e600100, "sde", round_flags, FPU_ALL, do_fp_dyadic}, - {"rpw", 0x0e700100, "sde", round_flags, FPU_ALL, do_fp_dyadic}, - {"rmf", 0x0e800100, "sde", round_flags, FPU_ALL, do_fp_dyadic}, - {"fml", 0x0e900100, "sde", round_flags, FPU_ALL, do_fp_dyadic}, - {"fdv", 0x0ea00100, "sde", round_flags, FPU_ALL, do_fp_dyadic}, - {"frd", 0x0eb00100, "sde", round_flags, FPU_ALL, do_fp_dyadic}, - {"pol", 0x0ec00100, "sde", round_flags, FPU_ALL, do_fp_dyadic}, - {"cmf", 0x0e90f110, NULL, except_flag, FPU_ALL, do_fp_cmp}, - {"cnf", 0x0eb0f110, NULL, except_flag, FPU_ALL, do_fp_cmp}, -/* The FPA10 data sheet suggests that the 'E' of cmfe/cnfe should not - be an optional suffix, but part of the instruction. To be compatible, - we accept either. */ - {"cmfe", 0x0ed0f110, NULL, NULL, FPU_ALL, do_fp_cmp}, - {"cnfe", 0x0ef0f110, NULL, NULL, FPU_ALL, do_fp_cmp}, - {"flt", 0x0e000110, "sde", round_flags, FPU_ALL, do_fp_from_reg}, - {"fix", 0x0e100110, NULL, fix_flags, FPU_ALL, do_fp_to_reg}, - -/* Generic copressor instructions. */ - {"cdp", 0x0e000000, NULL, NULL, ARM_2UP, do_cdp}, - {"ldc", 0x0c100000, NULL, cplong_flag, ARM_2UP, do_lstc}, - {"stc", 0x0c000000, NULL, cplong_flag, ARM_2UP, do_lstc}, - {"mcr", 0x0e000010, NULL, NULL, ARM_2UP, do_co_reg}, - {"mrc", 0x0e100010, NULL, NULL, ARM_2UP, do_co_reg}, -}; - -/* Defines for various bits that we will want to toggle. */ -#define INST_IMMEDIATE 0x02000000 -#define OFFSET_REG 0x02000000 -#define HWOFFSET_IMM 0x00400000 -#define SHIFT_BY_REG 0x00000010 -#define PRE_INDEX 0x01000000 -#define INDEX_UP 0x00800000 -#define WRITE_BACK 0x00200000 -#define LDM_TYPE_2_OR_3 0x00400000 - -#define LITERAL_MASK 0xf000f000 -#define COND_MASK 0xf0000000 -#define OPCODE_MASK 0xfe1fffff -#define DATA_OP_SHIFT 21 - -/* Codes to distinguish the arithmetic instructions. */ -#define OPCODE_AND 0 -#define OPCODE_EOR 1 -#define OPCODE_SUB 2 -#define OPCODE_RSB 3 -#define OPCODE_ADD 4 -#define OPCODE_ADC 5 -#define OPCODE_SBC 6 -#define OPCODE_RSC 7 -#define OPCODE_TST 8 -#define OPCODE_TEQ 9 -#define OPCODE_CMP 10 -#define OPCODE_CMN 11 -#define OPCODE_ORR 12 -#define OPCODE_MOV 13 -#define OPCODE_BIC 14 -#define OPCODE_MVN 15 - -static void do_t_nop PARAMS ((char *)); -static void do_t_arit PARAMS ((char *)); -static void do_t_add PARAMS ((char *)); -static void do_t_asr PARAMS ((char *)); -static void do_t_branch9 PARAMS ((char *)); -static void do_t_branch12 PARAMS ((char *)); -static void do_t_branch23 PARAMS ((char *)); -static void do_t_bx PARAMS ((char *)); -static void do_t_compare PARAMS ((char *)); -static void do_t_ldmstm PARAMS ((char *)); -static void do_t_ldr PARAMS ((char *)); -static void do_t_ldrb PARAMS ((char *)); -static void do_t_ldrh PARAMS ((char *)); -static void do_t_lds PARAMS ((char *)); -static void do_t_lsl PARAMS ((char *)); -static void do_t_lsr PARAMS ((char *)); -static void do_t_mov PARAMS ((char *)); -static void do_t_push_pop PARAMS ((char *)); -static void do_t_str PARAMS ((char *)); -static void do_t_strb PARAMS ((char *)); -static void do_t_strh PARAMS ((char *)); -static void do_t_sub PARAMS ((char *)); -static void do_t_swi PARAMS ((char *)); -static void do_t_adr PARAMS ((char *)); - -#define T_OPCODE_MUL 0x4340 -#define T_OPCODE_TST 0x4200 -#define T_OPCODE_CMN 0x42c0 -#define T_OPCODE_NEG 0x4240 -#define T_OPCODE_MVN 0x43c0 - -#define T_OPCODE_ADD_R3 0x1800 -#define T_OPCODE_SUB_R3 0x1a00 -#define T_OPCODE_ADD_HI 0x4400 -#define T_OPCODE_ADD_ST 0xb000 -#define T_OPCODE_SUB_ST 0xb080 -#define T_OPCODE_ADD_SP 0xa800 -#define T_OPCODE_ADD_PC 0xa000 -#define T_OPCODE_ADD_I8 0x3000 -#define T_OPCODE_SUB_I8 0x3800 -#define T_OPCODE_ADD_I3 0x1c00 -#define T_OPCODE_SUB_I3 0x1e00 - -#define T_OPCODE_ASR_R 0x4100 -#define T_OPCODE_LSL_R 0x4080 -#define T_OPCODE_LSR_R 0x40c0 -#define T_OPCODE_ASR_I 0x1000 -#define T_OPCODE_LSL_I 0x0000 -#define T_OPCODE_LSR_I 0x0800 - -#define T_OPCODE_MOV_I8 0x2000 -#define T_OPCODE_CMP_I8 0x2800 -#define T_OPCODE_CMP_LR 0x4280 -#define T_OPCODE_MOV_HR 0x4600 -#define T_OPCODE_CMP_HR 0x4500 - -#define T_OPCODE_LDR_PC 0x4800 -#define T_OPCODE_LDR_SP 0x9800 -#define T_OPCODE_STR_SP 0x9000 -#define T_OPCODE_LDR_IW 0x6800 -#define T_OPCODE_STR_IW 0x6000 -#define T_OPCODE_LDR_IH 0x8800 -#define T_OPCODE_STR_IH 0x8000 -#define T_OPCODE_LDR_IB 0x7800 -#define T_OPCODE_STR_IB 0x7000 -#define T_OPCODE_LDR_RW 0x5800 -#define T_OPCODE_STR_RW 0x5000 -#define T_OPCODE_LDR_RH 0x5a00 -#define T_OPCODE_STR_RH 0x5200 -#define T_OPCODE_LDR_RB 0x5c00 -#define T_OPCODE_STR_RB 0x5400 - -#define T_OPCODE_PUSH 0xb400 -#define T_OPCODE_POP 0xbc00 - -#define T_OPCODE_BRANCH 0xe7fe - -static int thumb_reg PARAMS ((char ** str, int hi_lo)); - -#define THUMB_SIZE 2 /* Size of thumb instruction. */ -#define THUMB_REG_LO 0x1 -#define THUMB_REG_HI 0x2 -#define THUMB_REG_ANY 0x3 - -#define THUMB_H1 0x0080 -#define THUMB_H2 0x0040 - -#define THUMB_ASR 0 -#define THUMB_LSL 1 -#define THUMB_LSR 2 - -#define THUMB_MOVE 0 -#define THUMB_COMPARE 1 - -#define THUMB_LOAD 0 -#define THUMB_STORE 1 - -#define THUMB_PP_PC_LR 0x0100 - -/* These three are used for immediate shifts, do not alter. */ -#define THUMB_WORD 2 -#define THUMB_HALFWORD 1 -#define THUMB_BYTE 0 - -struct thumb_opcode -{ - CONST char * template; /* Basic string to match */ - unsigned long value; /* Basic instruction code */ - int size; - unsigned long variants; /* Which CPU variants this exists for */ - void (* parms) PARAMS ((char *)); /* Function to call to parse args */ -}; - -static CONST struct thumb_opcode tinsns[] = -{ - {"adc", 0x4140, 2, ARM_THUMB, do_t_arit}, - {"add", 0x0000, 2, ARM_THUMB, do_t_add}, - {"and", 0x4000, 2, ARM_THUMB, do_t_arit}, - {"asr", 0x0000, 2, ARM_THUMB, do_t_asr}, - {"b", T_OPCODE_BRANCH, 2, ARM_THUMB, do_t_branch12}, - {"beq", 0xd0fe, 2, ARM_THUMB, do_t_branch9}, - {"bne", 0xd1fe, 2, ARM_THUMB, do_t_branch9}, - {"bcs", 0xd2fe, 2, ARM_THUMB, do_t_branch9}, - {"bhs", 0xd2fe, 2, ARM_THUMB, do_t_branch9}, - {"bcc", 0xd3fe, 2, ARM_THUMB, do_t_branch9}, - {"bul", 0xd3fe, 2, ARM_THUMB, do_t_branch9}, - {"blo", 0xd3fe, 2, ARM_THUMB, do_t_branch9}, - {"bmi", 0xd4fe, 2, ARM_THUMB, do_t_branch9}, - {"bpl", 0xd5fe, 2, ARM_THUMB, do_t_branch9}, - {"bvs", 0xd6fe, 2, ARM_THUMB, do_t_branch9}, - {"bvc", 0xd7fe, 2, ARM_THUMB, do_t_branch9}, - {"bhi", 0xd8fe, 2, ARM_THUMB, do_t_branch9}, - {"bls", 0xd9fe, 2, ARM_THUMB, do_t_branch9}, - {"bge", 0xdafe, 2, ARM_THUMB, do_t_branch9}, - {"blt", 0xdbfe, 2, ARM_THUMB, do_t_branch9}, - {"bgt", 0xdcfe, 2, ARM_THUMB, do_t_branch9}, - {"ble", 0xddfe, 2, ARM_THUMB, do_t_branch9}, - {"bal", 0xdefe, 2, ARM_THUMB, do_t_branch9}, - {"bic", 0x4380, 2, ARM_THUMB, do_t_arit}, - {"bl", 0xf7fffffe, 4, ARM_THUMB, do_t_branch23}, - {"bx", 0x4700, 2, ARM_THUMB, do_t_bx}, - {"cmn", T_OPCODE_CMN, 2, ARM_THUMB, do_t_arit}, - {"cmp", 0x0000, 2, ARM_THUMB, do_t_compare}, - {"eor", 0x4040, 2, ARM_THUMB, do_t_arit}, - {"ldmia", 0xc800, 2, ARM_THUMB, do_t_ldmstm}, - {"ldr", 0x0000, 2, ARM_THUMB, do_t_ldr}, - {"ldrb", 0x0000, 2, ARM_THUMB, do_t_ldrb}, - {"ldrh", 0x0000, 2, ARM_THUMB, do_t_ldrh}, - {"ldrsb", 0x5600, 2, ARM_THUMB, do_t_lds}, - {"ldrsh", 0x5e00, 2, ARM_THUMB, do_t_lds}, - {"ldsb", 0x5600, 2, ARM_THUMB, do_t_lds}, - {"ldsh", 0x5e00, 2, ARM_THUMB, do_t_lds}, - {"lsl", 0x0000, 2, ARM_THUMB, do_t_lsl}, - {"lsr", 0x0000, 2, ARM_THUMB, do_t_lsr}, - {"mov", 0x0000, 2, ARM_THUMB, do_t_mov}, - {"mul", T_OPCODE_MUL, 2, ARM_THUMB, do_t_arit}, - {"mvn", T_OPCODE_MVN, 2, ARM_THUMB, do_t_arit}, - {"neg", T_OPCODE_NEG, 2, ARM_THUMB, do_t_arit}, - {"orr", 0x4300, 2, ARM_THUMB, do_t_arit}, - {"pop", 0xbc00, 2, ARM_THUMB, do_t_push_pop}, - {"push", 0xb400, 2, ARM_THUMB, do_t_push_pop}, - {"ror", 0x41c0, 2, ARM_THUMB, do_t_arit}, - {"sbc", 0x4180, 2, ARM_THUMB, do_t_arit}, - {"stmia", 0xc000, 2, ARM_THUMB, do_t_ldmstm}, - {"str", 0x0000, 2, ARM_THUMB, do_t_str}, - {"strb", 0x0000, 2, ARM_THUMB, do_t_strb}, - {"strh", 0x0000, 2, ARM_THUMB, do_t_strh}, - {"swi", 0xdf00, 2, ARM_THUMB, do_t_swi}, - {"sub", 0x0000, 2, ARM_THUMB, do_t_sub}, - {"tst", T_OPCODE_TST, 2, ARM_THUMB, do_t_arit}, - /* Pseudo ops: */ - {"adr", 0x0000, 2, ARM_THUMB, do_t_adr}, - {"nop", 0x46C0, 2, ARM_THUMB, do_t_nop}, /* mov r8,r8 */ -}; - -struct reg_entry -{ - CONST char * name; - int number; -}; - -#define int_register(reg) ((reg) >= 0 && (reg) <= 15) -#define cp_register(reg) ((reg) >= 32 && (reg) <= 47) -#define fp_register(reg) ((reg) >= 16 && (reg) <= 23) - -#define REG_PC 15 -#define REG_LR 14 -#define REG_SP 13 - -/* These are the standard names. Users can add aliases with .req */ -static CONST struct reg_entry reg_table[] = -{ - /* Processor Register Numbers. */ - {"r0", 0}, {"r1", 1}, {"r2", 2}, {"r3", 3}, - {"r4", 4}, {"r5", 5}, {"r6", 6}, {"r7", 7}, - {"r8", 8}, {"r9", 9}, {"r10", 10}, {"r11", 11}, - {"r12", 12}, {"r13", REG_SP},{"r14", REG_LR},{"r15", REG_PC}, - /* APCS conventions. */ - {"a1", 0}, {"a2", 1}, {"a3", 2}, {"a4", 3}, - {"v1", 4}, {"v2", 5}, {"v3", 6}, {"v4", 7}, {"v5", 8}, - {"v6", 9}, {"sb", 9}, {"v7", 10}, {"sl", 10}, - {"fp", 11}, {"ip", 12}, {"sp", REG_SP},{"lr", REG_LR},{"pc", REG_PC}, - /* ATPCS additions to APCS conventions. */ - {"wr", 7}, {"v8", 11}, - /* FP Registers. */ - {"f0", 16}, {"f1", 17}, {"f2", 18}, {"f3", 19}, - {"f4", 20}, {"f5", 21}, {"f6", 22}, {"f7", 23}, - {"c0", 32}, {"c1", 33}, {"c2", 34}, {"c3", 35}, - {"c4", 36}, {"c5", 37}, {"c6", 38}, {"c7", 39}, - {"c8", 40}, {"c9", 41}, {"c10", 42}, {"c11", 43}, - {"c12", 44}, {"c13", 45}, {"c14", 46}, {"c15", 47}, - {"cr0", 32}, {"cr1", 33}, {"cr2", 34}, {"cr3", 35}, - {"cr4", 36}, {"cr5", 37}, {"cr6", 38}, {"cr7", 39}, - {"cr8", 40}, {"cr9", 41}, {"cr10", 42}, {"cr11", 43}, - {"cr12", 44}, {"cr13", 45}, {"cr14", 46}, {"cr15", 47}, - /* ATPCS additions to float register names. */ - {"s0",16}, {"s1",17}, {"s2",18}, {"s3",19}, - {"s4",20}, {"s5",21}, {"s6",22}, {"s7",23}, - {"d0",16}, {"d1",17}, {"d2",18}, {"d3",19}, - {"d4",20}, {"d5",21}, {"d6",22}, {"d7",23}, - /* FIXME: At some point we need to add VFP register names. */ - /* Array terminator. */ - {NULL, 0} -}; - -#define BAD_ARGS _("Bad arguments to instruction") -#define BAD_PC _("r15 not allowed here") -#define BAD_FLAGS _("Instruction should not have flags") -#define BAD_COND _("Instruction is not conditional") - -static struct hash_control * arm_ops_hsh = NULL; -static struct hash_control * arm_tops_hsh = NULL; -static struct hash_control * arm_cond_hsh = NULL; -static struct hash_control * arm_shift_hsh = NULL; -static struct hash_control * arm_reg_hsh = NULL; -static struct hash_control * arm_psr_hsh = NULL; - -/* This table describes all the machine specific pseudo-ops the assembler - has to support. The fields are: - pseudo-op name without dot - function to call to execute this pseudo-op - Integer arg to pass to the function. */ - -static void s_req PARAMS ((int)); -static void s_align PARAMS ((int)); -static void s_bss PARAMS ((int)); -static void s_even PARAMS ((int)); -static void s_ltorg PARAMS ((int)); -static void s_arm PARAMS ((int)); -static void s_thumb PARAMS ((int)); -static void s_code PARAMS ((int)); -static void s_force_thumb PARAMS ((int)); -static void s_thumb_func PARAMS ((int)); -static void s_thumb_set PARAMS ((int)); -static void arm_s_text PARAMS ((int)); -static void arm_s_data PARAMS ((int)); -#ifdef OBJ_ELF -static void arm_s_section PARAMS ((int)); -static void s_arm_elf_cons PARAMS ((int)); -#endif - -static int my_get_expression PARAMS ((expressionS *, char **)); - -CONST pseudo_typeS md_pseudo_table[] = -{ - { "req", s_req, 0 }, /* Never called becasue '.req' does not start line */ - { "bss", s_bss, 0 }, - { "align", s_align, 0 }, - { "arm", s_arm, 0 }, - { "thumb", s_thumb, 0 }, - { "code", s_code, 0 }, - { "force_thumb", s_force_thumb, 0 }, - { "thumb_func", s_thumb_func, 0 }, - { "thumb_set", s_thumb_set, 0 }, - { "even", s_even, 0 }, - { "ltorg", s_ltorg, 0 }, - { "pool", s_ltorg, 0 }, - /* Allow for the effect of section changes. */ - { "text", arm_s_text, 0 }, - { "data", arm_s_data, 0 }, -#ifdef OBJ_ELF - { "section", arm_s_section, 0 }, - { "section.s", arm_s_section, 0 }, - { "sect", arm_s_section, 0 }, - { "sect.s", arm_s_section, 0 }, - { "word", s_arm_elf_cons, 4 }, - { "long", s_arm_elf_cons, 4 }, -#else - { "word", cons, 4}, -#endif - { "extend", float_cons, 'x' }, - { "ldouble", float_cons, 'x' }, - { "packed", float_cons, 'p' }, - { 0, 0, 0 } -}; - -/* Stuff needed to resolve the label ambiguity - As: - ... - label: <insn> - may differ from: - ... - label: - <insn> -*/ - -symbolS * last_label_seen; -static int label_is_thumb_function_name = false; - -/* Literal stuff */ - -#define MAX_LITERAL_POOL_SIZE 1024 - -typedef struct literalS -{ - struct expressionS exp; - struct arm_it * inst; -} literalT; - -literalT literals[MAX_LITERAL_POOL_SIZE]; -int next_literal_pool_place = 0; /* Next free entry in the pool */ -int lit_pool_num = 1; /* Next literal pool number */ -symbolS * current_poolP = NULL; - -static int -add_to_lit_pool () -{ - int lit_count = 0; - - if (current_poolP == NULL) - current_poolP = symbol_create (FAKE_LABEL_NAME, undefined_section, - (valueT) 0, &zero_address_frag); - - /* Check if this literal value is already in the pool: */ - while (lit_count < next_literal_pool_place) - { - if (literals[lit_count].exp.X_op == inst.reloc.exp.X_op - && inst.reloc.exp.X_op == O_constant - && literals[lit_count].exp.X_add_number - == inst.reloc.exp.X_add_number - && literals[lit_count].exp.X_unsigned == inst.reloc.exp.X_unsigned) - break; - lit_count++; - } - - if (lit_count == next_literal_pool_place) /* new entry */ - { - if (next_literal_pool_place > MAX_LITERAL_POOL_SIZE) - { - inst.error = _("Literal Pool Overflow"); - return FAIL; - } - - literals[next_literal_pool_place].exp = inst.reloc.exp; - lit_count = next_literal_pool_place++; - } - - inst.reloc.exp.X_op = O_symbol; - inst.reloc.exp.X_add_number = (lit_count) * 4 - 8; - inst.reloc.exp.X_add_symbol = current_poolP; - - return SUCCESS; -} - -/* Can't use symbol_new here, so have to create a symbol and then at - a later date assign it a value. Thats what these functions do. */ -static void -symbol_locate (symbolP, name, segment, valu, frag) - symbolS * symbolP; - CONST char * name; /* It is copied, the caller can modify */ - segT segment; /* Segment identifier (SEG_<something>) */ - valueT valu; /* Symbol value */ - fragS * frag; /* Associated fragment */ -{ - unsigned int name_length; - char * preserved_copy_of_name; - - name_length = strlen (name) + 1; /* +1 for \0 */ - obstack_grow (¬es, name, name_length); - preserved_copy_of_name = obstack_finish (¬es); -#ifdef STRIP_UNDERSCORE - if (preserved_copy_of_name[0] == '_') - preserved_copy_of_name++; -#endif - -#ifdef tc_canonicalize_symbol_name - preserved_copy_of_name = - tc_canonicalize_symbol_name (preserved_copy_of_name); -#endif - - S_SET_NAME (symbolP, preserved_copy_of_name); - - S_SET_SEGMENT (symbolP, segment); - S_SET_VALUE (symbolP, valu); - symbol_clear_list_pointers(symbolP); - - symbol_set_frag (symbolP, frag); - - /* Link to end of symbol chain. */ - { - extern int symbol_table_frozen; - if (symbol_table_frozen) - abort (); - } - - symbol_append (symbolP, symbol_lastP, & symbol_rootP, & symbol_lastP); - - obj_symbol_new_hook (symbolP); - -#ifdef tc_symbol_new_hook - tc_symbol_new_hook (symbolP); -#endif - -#ifdef DEBUG_SYMS - verify_symbol_chain (symbol_rootP, symbol_lastP); -#endif /* DEBUG_SYMS */ -} - -/* Check that an immediate is valid, and if so, - convert it to the right format. */ -static unsigned int -validate_immediate (val) - unsigned int val; -{ - unsigned int a; - unsigned int i; - -#define rotate_left(v, n) (v << n | v >> (32 - n)) - - for (i = 0; i < 32; i += 2) - if ((a = rotate_left (val, i)) <= 0xff) - return a | (i << 7); /* 12-bit pack: [shift-cnt,const] */ - - return FAIL; -} - -/* Check to see if an immediate can be computed as two seperate immediate - values, added together. We already know that this value cannot be - computed by just one ARM instruction. */ -static unsigned int -validate_immediate_twopart (val, highpart) - unsigned int val; - unsigned int * highpart; -{ - unsigned int a; - unsigned int i; - - for (i = 0; i < 32; i += 2) - if (((a = rotate_left (val, i)) & 0xff) != 0) - { - if (a & 0xff00) - { - if (a & ~ 0xffff) - continue; - * highpart = (a >> 8) | ((i + 24) << 7); - } - else if (a & 0xff0000) - { - if (a & 0xff000000) - continue; - - * highpart = (a >> 16) | ((i + 16) << 7); - } - else - { - assert (a & 0xff000000); - - * highpart = (a >> 24) | ((i + 8) << 7); - } - - return (a & 0xff) | (i << 7); - } - - return FAIL; -} - -static int -validate_offset_imm (val, hwse) - unsigned int val; - int hwse; -{ - if ((hwse && val > 255) || val > 4095) - return FAIL; - return val; -} - - -static void -s_req (a) - int a ATTRIBUTE_UNUSED; -{ - as_bad (_("Invalid syntax for .req directive.")); -} - -static void -s_bss (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - /* We don't support putting frags in the BSS segment, we fake it by - marking in_bss, then looking at s_skip for clues?.. */ - subseg_set (bss_section, 0); - demand_empty_rest_of_line (); -} - -static void -s_even (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - if (!need_pass_2) /* Never make frag if expect extra pass. */ - frag_align (1, 0, 0); - - record_alignment (now_seg, 1); - - demand_empty_rest_of_line (); -} - -static void -s_ltorg (ignored) - int ignored ATTRIBUTE_UNUSED; -{ - int lit_count = 0; - char sym_name[20]; - - if (current_poolP == NULL) - return; - - /* Align pool as you have word accesses */ - /* Only make a frag if we have to ... */ - if (!need_pass_2) - frag_align (2, 0, 0); - - record_alignment (now_seg, 2); - - sprintf (sym_name, "$$lit_\002%x", lit_pool_num++); - - symbol_locate (current_poolP, sym_name, now_seg, - (valueT) frag_now_fix (), frag_now); - symbol_table_insert (current_poolP); - - ARM_SET_THUMB (current_poolP, thumb_mode); - -#if defined OBJ_COFF || defined OBJ_ELF - ARM_SET_INTERWORK (current_poolP, support_interwork); -#endif - - while (lit_count < next_literal_pool_place) - /* First output the expression in the instruction to the pool. */ - emit_expr (&(literals[lit_count++].exp), 4); /* .word */ - - next_literal_pool_place = 0; - current_poolP = NULL; -} - -static void -s_align (unused) /* Same as s_align_ptwo but align 0 => align 2 */ - int unused ATTRIBUTE_UNUSED; -{ - register int temp; - register long temp_fill; - long max_alignment = 15; - - temp = get_absolute_expression (); - if (temp > max_alignment) - as_bad (_("Alignment too large: %d. assumed."), temp = max_alignment); - else if (temp < 0) - { - as_bad (_("Alignment negative. 0 assumed.")); - temp = 0; - } - - if (*input_line_pointer == ',') - { - input_line_pointer++; - temp_fill = get_absolute_expression (); - } - else - temp_fill = 0; - - if (!temp) - temp = 2; - - /* Only make a frag if we HAVE to. . . */ - if (temp && !need_pass_2) - frag_align (temp, (int) temp_fill, 0); - demand_empty_rest_of_line (); - - record_alignment (now_seg, temp); -} - -static void -s_force_thumb (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - /* If we are not already in thumb mode go into it, EVEN if - the target processor does not support thumb instructions. - This is used by gcc/config/arm/lib1funcs.asm for example - to compile interworking support functions even if the - target processor should not support interworking. */ - - if (! thumb_mode) - { - thumb_mode = 2; - - record_alignment (now_seg, 1); - } - - demand_empty_rest_of_line (); -} - -static void -s_thumb_func (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - /* The following label is the name/address of the start of a Thumb function. - We need to know this for the interworking support. */ - - label_is_thumb_function_name = true; - - demand_empty_rest_of_line (); -} - -/* Perform a .set directive, but also mark the alias as - being a thumb function. */ - -static void -s_thumb_set (equiv) - int equiv; -{ - /* XXX the following is a duplicate of the code for s_set() in read.c - We cannot just call that code as we need to get at the symbol that - is created. */ - register char * name; - register char delim; - register char * end_name; - register symbolS * symbolP; - - /* - * Especial apologies for the random logic: - * this just grew, and could be parsed much more simply! - * Dean in haste. - */ - name = input_line_pointer; - delim = get_symbol_end (); - end_name = input_line_pointer; - *end_name = delim; - - SKIP_WHITESPACE (); - - if (*input_line_pointer != ',') - { - *end_name = 0; - as_bad (_("Expected comma after name \"%s\""), name); - *end_name = delim; - ignore_rest_of_line (); - return; - } - - input_line_pointer++; - *end_name = 0; - - if (name[0] == '.' && name[1] == '\0') - { - /* XXX - this should not happen to .thumb_set */ - abort (); - } - - if ((symbolP = symbol_find (name)) == NULL - && (symbolP = md_undefined_symbol (name)) == NULL) - { -#ifndef NO_LISTING - /* When doing symbol listings, play games with dummy fragments living - outside the normal fragment chain to record the file and line info - for this symbol. */ - if (listing & LISTING_SYMBOLS) - { - extern struct list_info_struct * listing_tail; - fragS * dummy_frag = (fragS *) xmalloc (sizeof(fragS)); - memset (dummy_frag, 0, sizeof(fragS)); - dummy_frag->fr_type = rs_fill; - dummy_frag->line = listing_tail; - symbolP = symbol_new (name, undefined_section, 0, dummy_frag); - dummy_frag->fr_symbol = symbolP; - } - else -#endif - symbolP = symbol_new (name, undefined_section, 0, &zero_address_frag); - -#ifdef OBJ_COFF - /* "set" symbols are local unless otherwise specified. */ - SF_SET_LOCAL (symbolP); -#endif /* OBJ_COFF */ - } /* make a new symbol */ - - symbol_table_insert (symbolP); - - * end_name = delim; - - if (equiv - && S_IS_DEFINED (symbolP) - && S_GET_SEGMENT (symbolP) != reg_section) - as_bad (_("symbol `%s' already defined"), S_GET_NAME (symbolP)); - - pseudo_set (symbolP); - - demand_empty_rest_of_line (); - - /* XXX Now we come to the Thumb specific bit of code. */ - - THUMB_SET_FUNC (symbolP, 1); - ARM_SET_THUMB (symbolP, 1); -#if defined OBJ_ELF || defined OBJ_COFF - ARM_SET_INTERWORK (symbolP, support_interwork); -#endif -} - -/* If we change section we must dump the literal pool first. */ -static void -arm_s_text (ignore) - int ignore; -{ - if (now_seg != text_section) - s_ltorg (0); - -#ifdef OBJ_ELF - obj_elf_text (ignore); -#else - s_text (ignore); -#endif -} - -static void -arm_s_data (ignore) - int ignore; -{ - if (flag_readonly_data_in_text) - { - if (now_seg != text_section) - s_ltorg (0); - } - else if (now_seg != data_section) - s_ltorg (0); - -#ifdef OBJ_ELF - obj_elf_data (ignore); -#else - s_data (ignore); -#endif -} - -#ifdef OBJ_ELF -static void -arm_s_section (ignore) - int ignore; -{ - s_ltorg (0); - - obj_elf_section (ignore); -} -#endif - -static void -opcode_select (width) - int width; -{ - switch (width) - { - case 16: - if (! thumb_mode) - { - if (! (cpu_variant & ARM_THUMB)) - as_bad (_("selected processor does not support THUMB opcodes")); - thumb_mode = 1; - /* No need to force the alignment, since we will have been - coming from ARM mode, which is word-aligned. */ - record_alignment (now_seg, 1); - } - break; - - case 32: - if (thumb_mode) - { - if ((cpu_variant & ARM_ANY) == ARM_THUMB) - as_bad (_("selected processor does not support ARM opcodes")); - thumb_mode = 0; - if (!need_pass_2) - frag_align (2, 0, 0); - record_alignment (now_seg, 1); - } - break; - - default: - as_bad (_("invalid instruction size selected (%d)"), width); - } -} - -static void -s_arm (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - opcode_select (32); - demand_empty_rest_of_line (); -} - -static void -s_thumb (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - opcode_select (16); - demand_empty_rest_of_line (); -} - -static void -s_code (unused) - int unused ATTRIBUTE_UNUSED; -{ - register int temp; - - temp = get_absolute_expression (); - switch (temp) - { - case 16: - case 32: - opcode_select (temp); - break; - - default: - as_bad (_("invalid operand to .code directive (%d) (expecting 16 or 32)"), temp); - } -} - -static void -end_of_line (str) - char * str; -{ - skip_whitespace (str); - - if (* str != '\0') - inst.error = _("Garbage following instruction"); -} - -static int -skip_past_comma (str) - char ** str; -{ - char *p = *str, c; - int comma = 0; - - while ((c = *p) == ' ' || c == ',') - { - p++; - if (c == ',' && comma++) - return FAIL; - } - - if (c == '\0') - return FAIL; - - *str = p; - return comma ? SUCCESS : FAIL; -} - -/* A standard register must be given at this point. - Shift is the place to put it in inst.instruction. - Restores input start point on err. - Returns the reg#, or FAIL. */ -static int -reg_required_here (str, shift) - char ** str; - int shift; -{ - static char buff [128]; /* XXX */ - int reg; - char * start = *str; - - if ((reg = arm_reg_parse (str)) != FAIL && int_register (reg)) - { - if (shift >= 0) - inst.instruction |= reg << shift; - return reg; - } - - /* Restore the start point, we may have got a reg of the wrong class. */ - *str = start; - - /* In the few cases where we might be able to accept something else - this error can be overridden. */ - sprintf (buff, _("Register expected, not '%.100s'"), start); - inst.error = buff; - - return FAIL; -} - -static int -psr_required_here (str, cpsr, spsr) - char ** str; - int cpsr; - int spsr; -{ - int psr; - char * start = *str; - psr = arm_psr_parse (str); - - if (psr == cpsr || psr == spsr) - { - if (psr == spsr) - inst.instruction |= 1 << 22; - - return SUCCESS; - } - - /* In the few cases where we might be able to accept something else - this error can be overridden. */ - inst.error = _("<psr(f)> expected"); - - /* Restore the start point. */ - *str = start; - return FAIL; -} - -static int -co_proc_number (str) - char ** str; -{ - int processor, pchar; - - skip_whitespace (* str); - - /* The data sheet seems to imply that just a number on its own is valid - here, but the RISC iX assembler seems to accept a prefix 'p'. We will - accept either. */ - if (**str == 'p' || **str == 'P') - (*str)++; - - pchar = *(*str)++; - if (pchar >= '0' && pchar <= '9') - { - processor = pchar - '0'; - if (**str >= '0' && **str <= '9') - { - processor = processor * 10 + *(*str)++ - '0'; - if (processor > 15) - { - inst.error = _("Illegal co-processor number"); - return FAIL; - } - } - } - else - { - inst.error = _("Bad or missing co-processor number"); - return FAIL; - } - - inst.instruction |= processor << 8; - return SUCCESS; -} - -static int -cp_opc_expr (str, where, length) - char ** str; - int where; - int length; -{ - expressionS expr; - - skip_whitespace (* str); - - memset (&expr, '\0', sizeof (expr)); - - if (my_get_expression (&expr, str)) - return FAIL; - if (expr.X_op != O_constant) - { - inst.error = _("bad or missing expression"); - return FAIL; - } - - if ((expr.X_add_number & ((1 << length) - 1)) != expr.X_add_number) - { - inst.error = _("immediate co-processor expression too large"); - return FAIL; - } - - inst.instruction |= expr.X_add_number << where; - return SUCCESS; -} - -static int -cp_reg_required_here (str, where) - char ** str; - int where; -{ - int reg; - char * start = *str; - - if ((reg = arm_reg_parse (str)) != FAIL && cp_register (reg)) - { - reg &= 15; - inst.instruction |= reg << where; - return reg; - } - - /* In the few cases where we might be able to accept something else - this error can be overridden. */ - inst.error = _("Co-processor register expected"); - - /* Restore the start point. */ - *str = start; - return FAIL; -} - -static int -fp_reg_required_here (str, where) - char ** str; - int where; -{ - int reg; - char * start = *str; - - if ((reg = arm_reg_parse (str)) != FAIL && fp_register (reg)) - { - reg &= 7; - inst.instruction |= reg << where; - return reg; - } - - /* In the few cases where we might be able to accept something else - this error can be overridden. */ - inst.error = _("Floating point register expected"); - - /* Restore the start point. */ - *str = start; - return FAIL; -} - -static int -cp_address_offset (str) - char ** str; -{ - int offset; - - skip_whitespace (* str); - - if (! is_immediate_prefix (**str)) - { - inst.error = _("immediate expression expected"); - return FAIL; - } - - (*str)++; - - if (my_get_expression (& inst.reloc.exp, str)) - return FAIL; - - if (inst.reloc.exp.X_op == O_constant) - { - offset = inst.reloc.exp.X_add_number; - - if (offset & 3) - { - inst.error = _("co-processor address must be word aligned"); - return FAIL; - } - - if (offset > 1023 || offset < -1023) - { - inst.error = _("offset too large"); - return FAIL; - } - - if (offset >= 0) - inst.instruction |= INDEX_UP; - else - offset = -offset; - - inst.instruction |= offset >> 2; - } - else - inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM; - - return SUCCESS; -} - -static int -cp_address_required_here (str) - char ** str; -{ - char * p = * str; - int pre_inc = 0; - int write_back = 0; - - if (*p == '[') - { - int reg; - - p++; - skip_whitespace (p); - - if ((reg = reg_required_here (& p, 16)) == FAIL) - return FAIL; - - skip_whitespace (p); - - if (*p == ']') - { - p++; - - if (skip_past_comma (& p) == SUCCESS) - { - /* [Rn], #expr */ - write_back = WRITE_BACK; - - if (reg == REG_PC) - { - inst.error = _("pc may not be used in post-increment"); - return FAIL; - } - - if (cp_address_offset (& p) == FAIL) - return FAIL; - } - else - pre_inc = PRE_INDEX | INDEX_UP; - } - else - { - /* '['Rn, #expr']'[!] */ - - if (skip_past_comma (& p) == FAIL) - { - inst.error = _("pre-indexed expression expected"); - return FAIL; - } - - pre_inc = PRE_INDEX; - - if (cp_address_offset (& p) == FAIL) - return FAIL; - - skip_whitespace (p); - - if (*p++ != ']') - { - inst.error = _("missing ]"); - return FAIL; - } - - skip_whitespace (p); - - if (*p == '!') - { - if (reg == REG_PC) - { - inst.error = _("pc may not be used with write-back"); - return FAIL; - } - - p++; - write_back = WRITE_BACK; - } - } - } - else - { - if (my_get_expression (&inst.reloc.exp, &p)) - return FAIL; - - inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM; - inst.reloc.exp.X_add_number -= 8; /* PC rel adjust */ - inst.reloc.pc_rel = 1; - inst.instruction |= (REG_PC << 16); - pre_inc = PRE_INDEX; - } - - inst.instruction |= write_back | pre_inc; - *str = p; - return SUCCESS; -} - -static void -do_nop (str, flags) - char * str; - unsigned long flags; -{ - /* Do nothing really. */ - inst.instruction |= flags; /* This is pointless. */ - end_of_line (str); - return; -} - -static void -do_mrs (str, flags) - char *str; - unsigned long flags; -{ - /* Only one syntax. */ - skip_whitespace (str); - - if (reg_required_here (&str, 12) == FAIL) - { - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (&str) == FAIL - || psr_required_here (& str, CPSR_ALL, SPSR_ALL) == FAIL) - { - inst.error = _("<psr> expected"); - return; - } - - inst.instruction |= flags; - end_of_line (str); - return; -} - -/* Three possible forms: "<psr>, Rm", "<psrf>, Rm", "<psrf>, #expression". */ -static void -do_msr (str, flags) - char * str; - unsigned long flags; -{ - int reg; - - skip_whitespace (str); - - if (psr_required_here (&str, CPSR_ALL, SPSR_ALL) == SUCCESS) - { - inst.instruction |= PSR_ALL; - - /* Sytax should be "<psr>, Rm" */ - if (skip_past_comma (&str) == FAIL - || (reg = reg_required_here (&str, 0)) == FAIL) - { - inst.error = BAD_ARGS; - return; - } - } - else - { - if (psr_required_here (& str, CPSR_FLG, SPSR_FLG) == SUCCESS) - inst.instruction |= PSR_FLAGS; - else if (psr_required_here (& str, CPSR_CTL, SPSR_CTL) == SUCCESS) - inst.instruction |= PSR_CONTROL; - else - { - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (&str) == FAIL) - { - inst.error = BAD_ARGS; - return; - } - - /* Syntax could be "<psrf>, rm", "<psrf>, #expression" */ - - if ((reg = reg_required_here (& str, 0)) != FAIL) - ; - /* Immediate expression. */ - else if (is_immediate_prefix (* str)) - { - str ++; - inst.error = NULL; - - if (my_get_expression (& inst.reloc.exp, & str)) - { - inst.error = _("Register or shift expression expected"); - return; - } - - if (inst.reloc.exp.X_add_symbol) - { - inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE; - inst.reloc.pc_rel = 0; - } - else - { - unsigned value = validate_immediate (inst.reloc.exp.X_add_number); - if (value == (unsigned) FAIL) - { - inst.error = _("Invalid constant"); - return; - } - - inst.instruction |= value; - } - - flags |= INST_IMMEDIATE; - } - else - { - inst.error = _("Error: unrecognised syntax for second argument to msr instruction"); - return; - } - } - - inst.error = NULL; - inst.instruction |= flags; - end_of_line (str); - return; -} - -/* Long Multiply Parser - UMULL RdLo, RdHi, Rm, Rs - SMULL RdLo, RdHi, Rm, Rs - UMLAL RdLo, RdHi, Rm, Rs - SMLAL RdLo, RdHi, Rm, Rs -*/ -static void -do_mull (str, flags) - char * str; - unsigned long flags; -{ - int rdlo, rdhi, rm, rs; - - /* Only one format "rdlo, rdhi, rm, rs" */ - skip_whitespace (str); - - if ((rdlo = reg_required_here (&str, 12)) == FAIL) - { - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (&str) == FAIL - || (rdhi = reg_required_here (&str, 16)) == FAIL) - { - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (&str) == FAIL - || (rm = reg_required_here (&str, 0)) == FAIL) - { - inst.error = BAD_ARGS; - return; - } - - /* rdhi, rdlo and rm must all be different */ - if (rdlo == rdhi || rdlo == rm || rdhi == rm) - as_tsktsk (_("rdhi, rdlo and rm must all be different")); - - if (skip_past_comma (&str) == FAIL - || (rs = reg_required_here (&str, 8)) == FAIL) - { - inst.error = BAD_ARGS; - return; - } - - if (rdhi == REG_PC || rdhi == REG_PC || rdhi == REG_PC || rdhi == REG_PC) - { - inst.error = BAD_PC; - return; - } - - inst.instruction |= flags; - end_of_line (str); - return; -} - -static void -do_mul (str, flags) - char * str; - unsigned long flags; -{ - int rd, rm; - - /* Only one format "rd, rm, rs" */ - skip_whitespace (str); - - if ((rd = reg_required_here (&str, 16)) == FAIL) - { - inst.error = BAD_ARGS; - return; - } - - if (rd == REG_PC) - { - inst.error = BAD_PC; - return; - } - - if (skip_past_comma (&str) == FAIL - || (rm = reg_required_here (&str, 0)) == FAIL) - { - inst.error = BAD_ARGS; - return; - } - - if (rm == REG_PC) - { - inst.error = BAD_PC; - return; - } - - if (rm == rd) - as_tsktsk (_("rd and rm should be different in mul")); - - if (skip_past_comma (&str) == FAIL - || (rm = reg_required_here (&str, 8)) == FAIL) - { - inst.error = BAD_ARGS; - return; - } - - if (rm == REG_PC) - { - inst.error = BAD_PC; - return; - } - - inst.instruction |= flags; - end_of_line (str); - return; -} - -static void -do_mla (str, flags) - char * str; - unsigned long flags; -{ - int rd, rm; - - /* Only one format "rd, rm, rs, rn" */ - skip_whitespace (str); - - if ((rd = reg_required_here (&str, 16)) == FAIL) - { - inst.error = BAD_ARGS; - return; - } - - if (rd == REG_PC) - { - inst.error = BAD_PC; - return; - } - - if (skip_past_comma (&str) == FAIL - || (rm = reg_required_here (&str, 0)) == FAIL) - { - inst.error = BAD_ARGS; - return; - } - - if (rm == REG_PC) - { - inst.error = BAD_PC; - return; - } - - if (rm == rd) - as_tsktsk (_("rd and rm should be different in mla")); - - if (skip_past_comma (&str) == FAIL - || (rd = reg_required_here (&str, 8)) == FAIL - || skip_past_comma (&str) == FAIL - || (rm = reg_required_here (&str, 12)) == FAIL) - { - inst.error = BAD_ARGS; - return; - } - - if (rd == REG_PC || rm == REG_PC) - { - inst.error = BAD_PC; - return; - } - - inst.instruction |= flags; - end_of_line (str); - return; -} - -/* Returns the index into fp_values of a floating point number, or -1 if - not in the table. */ -static int -my_get_float_expression (str) - char ** str; -{ - LITTLENUM_TYPE words[MAX_LITTLENUMS]; - char * save_in; - expressionS exp; - int i; - int j; - - memset (words, 0, MAX_LITTLENUMS * sizeof (LITTLENUM_TYPE)); - /* Look for a raw floating point number */ - if ((save_in = atof_ieee (*str, 'x', words)) != NULL - && (is_end_of_line [(int)(*save_in)] || *save_in == '\0')) - { - for (i = 0; i < NUM_FLOAT_VALS; i++) - { - for (j = 0; j < MAX_LITTLENUMS; j++) - { - if (words[j] != fp_values[i][j]) - break; - } - - if (j == MAX_LITTLENUMS) - { - *str = save_in; - return i; - } - } - } - - /* Try and parse a more complex expression, this will probably fail - unless the code uses a floating point prefix (eg "0f") */ - save_in = input_line_pointer; - input_line_pointer = *str; - if (expression (&exp) == absolute_section - && exp.X_op == O_big - && exp.X_add_number < 0) - { - /* FIXME: 5 = X_PRECISION, should be #define'd where we can use it. - Ditto for 15. */ - if (gen_to_words (words, 5, (long)15) == 0) - { - for (i = 0; i < NUM_FLOAT_VALS; i++) - { - for (j = 0; j < MAX_LITTLENUMS; j++) - { - if (words[j] != fp_values[i][j]) - break; - } - - if (j == MAX_LITTLENUMS) - { - *str = input_line_pointer; - input_line_pointer = save_in; - return i; - } - } - } - } - - *str = input_line_pointer; - input_line_pointer = save_in; - return -1; -} - -/* Return true if anything in the expression is a bignum */ -static int -walk_no_bignums (sp) - symbolS * sp; -{ - if (symbol_get_value_expression (sp)->X_op == O_big) - return 1; - - if (symbol_get_value_expression (sp)->X_add_symbol) - { - return (walk_no_bignums (symbol_get_value_expression (sp)->X_add_symbol) - || (symbol_get_value_expression (sp)->X_op_symbol - && walk_no_bignums (symbol_get_value_expression (sp)->X_op_symbol))); - } - - return 0; -} - -static int -my_get_expression (ep, str) - expressionS * ep; - char ** str; -{ - char * save_in; - segT seg; - - save_in = input_line_pointer; - input_line_pointer = *str; - seg = expression (ep); - -#ifdef OBJ_AOUT - if (seg != absolute_section - && seg != text_section - && seg != data_section - && seg != bss_section - && seg != undefined_section) - { - inst.error = _("bad_segment"); - *str = input_line_pointer; - input_line_pointer = save_in; - return 1; - } -#endif - - /* Get rid of any bignums now, so that we don't generate an error for which - we can't establish a line number later on. Big numbers are never valid - in instructions, which is where this routine is always called. */ - if (ep->X_op == O_big - || (ep->X_add_symbol - && (walk_no_bignums (ep->X_add_symbol) - || (ep->X_op_symbol - && walk_no_bignums (ep->X_op_symbol))))) - { - inst.error = _("Invalid constant"); - *str = input_line_pointer; - input_line_pointer = save_in; - return 1; - } - - *str = input_line_pointer; - input_line_pointer = save_in; - return 0; -} - -/* unrestrict should be one if <shift> <register> is permitted for this - instruction */ - -static int -decode_shift (str, unrestrict) - char ** str; - int unrestrict; -{ - struct asm_shift * shft; - char * p; - char c; - - skip_whitespace (* str); - - for (p = *str; isalpha (*p); p++) - ; - - if (p == *str) - { - inst.error = _("Shift expression expected"); - return FAIL; - } - - c = *p; - *p = '\0'; - shft = (struct asm_shift *) hash_find (arm_shift_hsh, *str); - *p = c; - if (shft) - { - if (!strncmp (*str, "rrx", 3) - || !strncmp (*str, "RRX", 3)) - { - *str = p; - inst.instruction |= shft->value; - return SUCCESS; - } - - skip_whitespace (p); - - if (unrestrict && reg_required_here (&p, 8) != FAIL) - { - inst.instruction |= shft->value | SHIFT_BY_REG; - *str = p; - return SUCCESS; - } - else if (is_immediate_prefix (* p)) - { - inst.error = NULL; - p++; - if (my_get_expression (&inst.reloc.exp, &p)) - return FAIL; - - /* Validate some simple #expressions */ - if (inst.reloc.exp.X_op == O_constant) - { - unsigned num = inst.reloc.exp.X_add_number; - - /* Reject operations greater than 32, or lsl #32 */ - if (num > 32 || (num == 32 && shft->value == 0)) - { - inst.error = _("Invalid immediate shift"); - return FAIL; - } - - /* Shifts of zero should be converted to lsl (which is zero)*/ - if (num == 0) - { - *str = p; - return SUCCESS; - } - - /* Shifts of 32 are encoded as 0, for those shifts that - support it. */ - if (num == 32) - num = 0; - - inst.instruction |= (num << 7) | shft->value; - *str = p; - return SUCCESS; - } - - inst.reloc.type = BFD_RELOC_ARM_SHIFT_IMM; - inst.reloc.pc_rel = 0; - inst.instruction |= shft->value; - *str = p; - return SUCCESS; - } - else - { - inst.error = unrestrict ? _("shift requires register or #expression") - : _("shift requires #expression"); - *str = p; - return FAIL; - } - } - - inst.error = _("Shift expression expected"); - return FAIL; -} - -/* Do those data_ops which can take a negative immediate constant */ -/* by altering the instuction. A bit of a hack really */ -/* MOV <-> MVN - AND <-> BIC - ADC <-> SBC - by inverting the second operand, and - ADD <-> SUB - CMP <-> CMN - by negating the second operand. -*/ -static int -negate_data_op (instruction, value) - unsigned long * instruction; - unsigned long value; -{ - int op, new_inst; - unsigned long negated, inverted; - - negated = validate_immediate (-value); - inverted = validate_immediate (~value); - - op = (*instruction >> DATA_OP_SHIFT) & 0xf; - switch (op) - { - /* First negates */ - case OPCODE_SUB: /* ADD <-> SUB */ - new_inst = OPCODE_ADD; - value = negated; - break; - - case OPCODE_ADD: - new_inst = OPCODE_SUB; - value = negated; - break; - - case OPCODE_CMP: /* CMP <-> CMN */ - new_inst = OPCODE_CMN; - value = negated; - break; - - case OPCODE_CMN: - new_inst = OPCODE_CMP; - value = negated; - break; - - /* Now Inverted ops */ - case OPCODE_MOV: /* MOV <-> MVN */ - new_inst = OPCODE_MVN; - value = inverted; - break; - - case OPCODE_MVN: - new_inst = OPCODE_MOV; - value = inverted; - break; - - case OPCODE_AND: /* AND <-> BIC */ - new_inst = OPCODE_BIC; - value = inverted; - break; - - case OPCODE_BIC: - new_inst = OPCODE_AND; - value = inverted; - break; - - case OPCODE_ADC: /* ADC <-> SBC */ - new_inst = OPCODE_SBC; - value = inverted; - break; - - case OPCODE_SBC: - new_inst = OPCODE_ADC; - value = inverted; - break; - - /* We cannot do anything */ - default: - return FAIL; - } - - if (value == (unsigned) FAIL) - return FAIL; - - *instruction &= OPCODE_MASK; - *instruction |= new_inst << DATA_OP_SHIFT; - return value; -} - -static int -data_op2 (str) - char ** str; -{ - int value; - expressionS expr; - - skip_whitespace (* str); - - if (reg_required_here (str, 0) != FAIL) - { - if (skip_past_comma (str) == SUCCESS) - /* Shift operation on register. */ - return decode_shift (str, NO_SHIFT_RESTRICT); - - return SUCCESS; - } - else - { - /* Immediate expression */ - if (is_immediate_prefix (**str)) - { - (*str)++; - inst.error = NULL; - - if (my_get_expression (&inst.reloc.exp, str)) - return FAIL; - - if (inst.reloc.exp.X_add_symbol) - { - inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE; - inst.reloc.pc_rel = 0; - } - else - { - if (skip_past_comma (str) == SUCCESS) - { - /* #x, y -- ie explicit rotation by Y */ - if (my_get_expression (&expr, str)) - return FAIL; - - if (expr.X_op != O_constant) - { - inst.error = _("Constant expression expected"); - return FAIL; - } - - /* Rotate must be a multiple of 2 */ - if (((unsigned) expr.X_add_number) > 30 - || (expr.X_add_number & 1) != 0 - || ((unsigned) inst.reloc.exp.X_add_number) > 255) - { - inst.error = _("Invalid constant"); - return FAIL; - } - inst.instruction |= INST_IMMEDIATE; - inst.instruction |= inst.reloc.exp.X_add_number; - inst.instruction |= expr.X_add_number << 7; - return SUCCESS; - } - - /* Implicit rotation, select a suitable one */ - value = validate_immediate (inst.reloc.exp.X_add_number); - - if (value == FAIL) - { - /* Can't be done, perhaps the code reads something like - "add Rd, Rn, #-n", where "sub Rd, Rn, #n" would be ok */ - if ((value = negate_data_op (&inst.instruction, - inst.reloc.exp.X_add_number)) - == FAIL) - { - inst.error = _("Invalid constant"); - return FAIL; - } - } - - inst.instruction |= value; - } - - inst.instruction |= INST_IMMEDIATE; - return SUCCESS; - } - - (*str)++; - inst.error = _("Register or shift expression expected"); - return FAIL; - } -} - -static int -fp_op2 (str) - char ** str; -{ - skip_whitespace (* str); - - if (fp_reg_required_here (str, 0) != FAIL) - return SUCCESS; - else - { - /* Immediate expression */ - if (*((*str)++) == '#') - { - int i; - - inst.error = NULL; - - skip_whitespace (* str); - - /* First try and match exact strings, this is to guarantee that - some formats will work even for cross assembly */ - - for (i = 0; fp_const[i]; i++) - { - if (strncmp (*str, fp_const[i], strlen (fp_const[i])) == 0) - { - char *start = *str; - - *str += strlen (fp_const[i]); - if (is_end_of_line[(int)**str] || **str == '\0') - { - inst.instruction |= i + 8; - return SUCCESS; - } - *str = start; - } - } - - /* Just because we didn't get a match doesn't mean that the - constant isn't valid, just that it is in a format that we - don't automatically recognize. Try parsing it with - the standard expression routines. */ - if ((i = my_get_float_expression (str)) >= 0) - { - inst.instruction |= i + 8; - return SUCCESS; - } - - inst.error = _("Invalid floating point immediate expression"); - return FAIL; - } - inst.error = _("Floating point register or immediate expression expected"); - return FAIL; - } -} - -static void -do_arit (str, flags) - char * str; - unsigned long flags; -{ - skip_whitespace (str); - - if (reg_required_here (&str, 12) == FAIL - || skip_past_comma (&str) == FAIL - || reg_required_here (&str, 16) == FAIL - || skip_past_comma (&str) == FAIL - || data_op2 (&str) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - inst.instruction |= flags; - end_of_line (str); - return; -} - -static void -do_adr (str, flags) - char * str; - unsigned long flags; -{ - /* This is a pseudo-op of the form "adr rd, label" to be converted - into a relative address of the form "add rd, pc, #label-.-8". */ - skip_whitespace (str); - - if (reg_required_here (&str, 12) == FAIL - || skip_past_comma (&str) == FAIL - || my_get_expression (&inst.reloc.exp, &str)) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - /* Frag hacking will turn this into a sub instruction if the offset turns - out to be negative. */ - inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE; - inst.reloc.exp.X_add_number -= 8; /* PC relative adjust. */ - inst.reloc.pc_rel = 1; - inst.instruction |= flags; - end_of_line (str); - return; -} - -static void -do_adrl (str, flags) - char * str; - unsigned long flags; -{ - /* This is a pseudo-op of the form "adrl rd, label" to be converted - into a relative address of the form: - add rd, pc, #low(label-.-8)" - add rd, rd, #high(label-.-8)" */ - - skip_whitespace (str); - - if (reg_required_here (& str, 12) == FAIL - || skip_past_comma (& str) == FAIL - || my_get_expression (& inst.reloc.exp, & str)) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - end_of_line (str); - - /* Frag hacking will turn this into a sub instruction if the offset turns - out to be negative. */ - inst.reloc.type = BFD_RELOC_ARM_ADRL_IMMEDIATE; - inst.reloc.exp.X_add_number -= 8; /* PC relative adjust */ - inst.reloc.pc_rel = 1; - inst.instruction |= flags; - inst.size = INSN_SIZE * 2; - - return; -} - -static void -do_cmp (str, flags) - char * str; - unsigned long flags; -{ - skip_whitespace (str); - - if (reg_required_here (&str, 16) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (&str) == FAIL - || data_op2 (&str) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - inst.instruction |= flags; - if ((flags & 0x0000f000) == 0) - inst.instruction |= CONDS_BIT; - - end_of_line (str); - return; -} - -static void -do_mov (str, flags) - char * str; - unsigned long flags; -{ - skip_whitespace (str); - - if (reg_required_here (&str, 12) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (&str) == FAIL - || data_op2 (&str) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - inst.instruction |= flags; - end_of_line (str); - return; -} - -static int -ldst_extend (str, hwse) - char ** str; - int hwse; -{ - int add = INDEX_UP; - - switch (**str) - { - case '#': - case '$': - (*str)++; - if (my_get_expression (& inst.reloc.exp, str)) - return FAIL; - - if (inst.reloc.exp.X_op == O_constant) - { - int value = inst.reloc.exp.X_add_number; - - if ((hwse && (value < -255 || value > 255)) - || (value < -4095 || value > 4095)) - { - inst.error = _("address offset too large"); - return FAIL; - } - - if (value < 0) - { - value = -value; - add = 0; - } - - /* Halfword and signextension instructions have the - immediate value split across bits 11..8 and bits 3..0 */ - if (hwse) - inst.instruction |= add | HWOFFSET_IMM | ((value >> 4) << 8) | (value & 0xF); - else - inst.instruction |= add | value; - } - else - { - if (hwse) - { - inst.instruction |= HWOFFSET_IMM; - inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM8; - } - else - inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM; - inst.reloc.pc_rel = 0; - } - return SUCCESS; - - case '-': - add = 0; /* and fall through */ - case '+': - (*str)++; /* and fall through */ - default: - if (reg_required_here (str, 0) == FAIL) - return FAIL; - - if (hwse) - inst.instruction |= add; - else - { - inst.instruction |= add | OFFSET_REG; - if (skip_past_comma (str) == SUCCESS) - return decode_shift (str, SHIFT_RESTRICT); - } - - return SUCCESS; - } -} - -static void -do_ldst (str, flags) - char * str; - unsigned long flags; -{ - int halfword = 0; - int pre_inc = 0; - int conflict_reg; - int value; - - /* This is not ideal, but it is the simplest way of dealing with the - ARM7T halfword instructions (since they use a different - encoding, but the same mnemonic): */ - halfword = (flags & 0x80000000) != 0; - if (halfword) - { - /* This is actually a load/store of a halfword, or a - signed-extension load */ - if ((cpu_variant & ARM_HALFWORD) == 0) - { - inst.error - = _("Processor does not support halfwords or signed bytes"); - return; - } - - inst.instruction = (inst.instruction & COND_MASK) - | (flags & ~COND_MASK); - - flags = 0; - } - - skip_whitespace (str); - - if ((conflict_reg = reg_required_here (& str, 12)) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (& str) == FAIL) - { - inst.error = _("Address expected"); - return; - } - - if (*str == '[') - { - int reg; - - str++; - - skip_whitespace (str); - - if ((reg = reg_required_here (&str, 16)) == FAIL) - return; - - /* Conflicts can occur on stores as well as loads. */ - conflict_reg = (conflict_reg == reg); - - skip_whitespace (str); - - if (*str == ']') - { - str ++; - - if (skip_past_comma (&str) == SUCCESS) - { - /* [Rn],... (post inc) */ - if (ldst_extend (&str, halfword) == FAIL) - return; - if (conflict_reg) - as_warn (_("%s register same as write-back base"), - (inst.instruction & LOAD_BIT) ? _("destination") : _("source") ); - } - else - { - /* [Rn] */ - if (halfword) - inst.instruction |= HWOFFSET_IMM; - - skip_whitespace (str); - - if (*str == '!') - { - if (conflict_reg) - as_warn (_("%s register same as write-back base"), - (inst.instruction & LOAD_BIT) ? _("destination") : _("source") ); - str++; - inst.instruction |= WRITE_BACK; - } - - flags |= INDEX_UP; - if (! (flags & TRANS_BIT)) - pre_inc = 1; - } - } - else - { - /* [Rn,...] */ - if (skip_past_comma (&str) == FAIL) - { - inst.error = _("pre-indexed expression expected"); - return; - } - - pre_inc = 1; - if (ldst_extend (&str, halfword) == FAIL) - return; - - skip_whitespace (str); - - if (*str++ != ']') - { - inst.error = _("missing ]"); - return; - } - - skip_whitespace (str); - - if (*str == '!') - { - if (conflict_reg) - as_warn (_("%s register same as write-back base"), - (inst.instruction & LOAD_BIT) ? _("destination") : _("source") ); - str++; - inst.instruction |= WRITE_BACK; - } - } - } - else if (*str == '=') - { - /* Parse an "ldr Rd, =expr" instruction; this is another pseudo op */ - str++; - - skip_whitespace (str); - - if (my_get_expression (&inst.reloc.exp, &str)) - return; - - if (inst.reloc.exp.X_op != O_constant - && inst.reloc.exp.X_op != O_symbol) - { - inst.error = _("Constant expression expected"); - return; - } - - if (inst.reloc.exp.X_op == O_constant - && (value = validate_immediate(inst.reloc.exp.X_add_number)) != FAIL) - { - /* This can be done with a mov instruction */ - inst.instruction &= LITERAL_MASK; - inst.instruction |= INST_IMMEDIATE | (OPCODE_MOV << DATA_OP_SHIFT); - inst.instruction |= (flags & COND_MASK) | (value & 0xfff); - end_of_line(str); - return; - } - else - { - /* Insert into literal pool */ - if (add_to_lit_pool () == FAIL) - { - if (!inst.error) - inst.error = _("literal pool insertion failed"); - return; - } - - /* Change the instruction exp to point to the pool */ - if (halfword) - { - inst.instruction |= HWOFFSET_IMM; - inst.reloc.type = BFD_RELOC_ARM_HWLITERAL; - } - else - inst.reloc.type = BFD_RELOC_ARM_LITERAL; - inst.reloc.pc_rel = 1; - inst.instruction |= (REG_PC << 16); - pre_inc = 1; - } - } - else - { - if (my_get_expression (&inst.reloc.exp, &str)) - return; - - if (halfword) - { - inst.instruction |= HWOFFSET_IMM; - inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM8; - } - else - inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM; -#ifndef TE_WINCE - inst.reloc.exp.X_add_number -= 8; /* PC rel adjust */ -#endif - inst.reloc.pc_rel = 1; - inst.instruction |= (REG_PC << 16); - pre_inc = 1; - } - - if (pre_inc && (flags & TRANS_BIT)) - inst.error = _("Pre-increment instruction with translate"); - - inst.instruction |= flags | (pre_inc ? PRE_INDEX : 0); - end_of_line (str); - return; -} - -static long -reg_list (strp) - char ** strp; -{ - char * str = *strp; - long range = 0; - int another_range; - - /* We come back here if we get ranges concatenated by '+' or '|' */ - do - { - another_range = 0; - - if (*str == '{') - { - int in_range = 0; - int cur_reg = -1; - - str++; - do - { - int reg; - - skip_whitespace (str); - - if ((reg = reg_required_here (& str, -1)) == FAIL) - return FAIL; - - if (in_range) - { - int i; - - if (reg <= cur_reg) - { - inst.error = _("Bad range in register list"); - return FAIL; - } - - for (i = cur_reg + 1; i < reg; i++) - { - if (range & (1 << i)) - as_tsktsk - (_("Warning: Duplicated register (r%d) in register list"), - i); - else - range |= 1 << i; - } - in_range = 0; - } - - if (range & (1 << reg)) - as_tsktsk (_("Warning: Duplicated register (r%d) in register list"), - reg); - else if (reg <= cur_reg) - as_tsktsk (_("Warning: Register range not in ascending order")); - - range |= 1 << reg; - cur_reg = reg; - } while (skip_past_comma (&str) != FAIL - || (in_range = 1, *str++ == '-')); - str--; - skip_whitespace (str); - - if (*str++ != '}') - { - inst.error = _("Missing `}'"); - return FAIL; - } - } - else - { - expressionS expr; - - if (my_get_expression (&expr, &str)) - return FAIL; - - if (expr.X_op == O_constant) - { - if (expr.X_add_number - != (expr.X_add_number & 0x0000ffff)) - { - inst.error = _("invalid register mask"); - return FAIL; - } - - if ((range & expr.X_add_number) != 0) - { - int regno = range & expr.X_add_number; - - regno &= -regno; - regno = (1 << regno) - 1; - as_tsktsk - (_("Warning: Duplicated register (r%d) in register list"), - regno); - } - - range |= expr.X_add_number; - } - else - { - if (inst.reloc.type != 0) - { - inst.error = _("expression too complex"); - return FAIL; - } - - memcpy (&inst.reloc.exp, &expr, sizeof (expressionS)); - inst.reloc.type = BFD_RELOC_ARM_MULTI; - inst.reloc.pc_rel = 0; - } - } - - skip_whitespace (str); - - if (*str == '|' || *str == '+') - { - str++; - another_range = 1; - } - } while (another_range); - - *strp = str; - return range; -} - -static void -do_ldmstm (str, flags) - char * str; - unsigned long flags; -{ - int base_reg; - long range; - - skip_whitespace (str); - - if ((base_reg = reg_required_here (&str, 16)) == FAIL) - return; - - if (base_reg == REG_PC) - { - inst.error = _("r15 not allowed as base register"); - return; - } - - skip_whitespace (str); - - if (*str == '!') - { - flags |= WRITE_BACK; - str++; - } - - if (skip_past_comma (&str) == FAIL - || (range = reg_list (&str)) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } - - if (*str == '^') - { - str++; - flags |= LDM_TYPE_2_OR_3; - } - - inst.instruction |= flags | range; - end_of_line (str); - return; -} - -static void -do_swi (str, flags) - char * str; - unsigned long flags; -{ - skip_whitespace (str); - - /* Allow optional leading '#'. */ - if (is_immediate_prefix (*str)) - str++; - - if (my_get_expression (& inst.reloc.exp, & str)) - return; - - inst.reloc.type = BFD_RELOC_ARM_SWI; - inst.reloc.pc_rel = 0; - inst.instruction |= flags; - - end_of_line (str); - - return; -} - -static void -do_swap (str, flags) - char * str; - unsigned long flags; -{ - int reg; - - skip_whitespace (str); - - if ((reg = reg_required_here (&str, 12)) == FAIL) - return; - - if (reg == REG_PC) - { - inst.error = _("r15 not allowed in swap"); - return; - } - - if (skip_past_comma (&str) == FAIL - || (reg = reg_required_here (&str, 0)) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - if (reg == REG_PC) - { - inst.error = _("r15 not allowed in swap"); - return; - } - - if (skip_past_comma (&str) == FAIL - || *str++ != '[') - { - inst.error = BAD_ARGS; - return; - } - - skip_whitespace (str); - - if ((reg = reg_required_here (&str, 16)) == FAIL) - return; - - if (reg == REG_PC) - { - inst.error = BAD_PC; - return; - } - - skip_whitespace (str); - - if (*str++ != ']') - { - inst.error = _("missing ]"); - return; - } - - inst.instruction |= flags; - end_of_line (str); - return; -} - -static void -do_branch (str, flags) - char * str; - unsigned long flags ATTRIBUTE_UNUSED; -{ - if (my_get_expression (&inst.reloc.exp, &str)) - return; - -#ifdef OBJ_ELF - { - char * save_in; - - /* ScottB: February 5, 1998 */ - /* Check to see of PLT32 reloc required for the instruction. */ - - /* arm_parse_reloc() works on input_line_pointer. - We actually want to parse the operands to the branch instruction - passed in 'str'. Save the input pointer and restore it later. */ - save_in = input_line_pointer; - input_line_pointer = str; - if (inst.reloc.exp.X_op == O_symbol - && *str == '(' - && arm_parse_reloc () == BFD_RELOC_ARM_PLT32) - { - inst.reloc.type = BFD_RELOC_ARM_PLT32; - inst.reloc.pc_rel = 0; - /* Modify str to point to after parsed operands, otherwise - end_of_line() will complain about the (PLT) left in str. */ - str = input_line_pointer; - } - else - { - inst.reloc.type = BFD_RELOC_ARM_PCREL_BRANCH; - inst.reloc.pc_rel = 1; - } - input_line_pointer = save_in; - } -#else - inst.reloc.type = BFD_RELOC_ARM_PCREL_BRANCH; - inst.reloc.pc_rel = 1; -#endif /* OBJ_ELF */ - - end_of_line (str); - return; -} - -static void -do_bx (str, flags) - char * str; - unsigned long flags ATTRIBUTE_UNUSED; -{ - int reg; - - skip_whitespace (str); - - if ((reg = reg_required_here (&str, 0)) == FAIL) - { - inst.error = BAD_ARGS; - return; - } - - if (reg == REG_PC) - inst.error = BAD_PC; - - end_of_line (str); -} - -static void -do_cdp (str, flags) - char * str; - unsigned long flags ATTRIBUTE_UNUSED; -{ - /* Co-processor data operation. - Format: CDP{cond} CP#,<expr>,CRd,CRn,CRm{,<expr>} */ - skip_whitespace (str); - - if (co_proc_number (&str) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (&str) == FAIL - || cp_opc_expr (&str, 20,4) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (&str) == FAIL - || cp_reg_required_here (&str, 12) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (&str) == FAIL - || cp_reg_required_here (&str, 16) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (&str) == FAIL - || cp_reg_required_here (&str, 0) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (&str) == SUCCESS) - { - if (cp_opc_expr (&str, 5, 3) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - } - - end_of_line (str); - return; -} - -static void -do_lstc (str, flags) - char * str; - unsigned long flags; -{ - /* Co-processor register load/store. - Format: <LDC|STC{cond}[L] CP#,CRd,<address> */ - - skip_whitespace (str); - - if (co_proc_number (&str) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (&str) == FAIL - || cp_reg_required_here (&str, 12) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (&str) == FAIL - || cp_address_required_here (&str) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } - - inst.instruction |= flags; - end_of_line (str); - return; -} - -static void -do_co_reg (str, flags) - char * str; - unsigned long flags; -{ - /* Co-processor register transfer. - Format: <MCR|MRC>{cond} CP#,<expr1>,Rd,CRn,CRm{,<expr2>} */ - - skip_whitespace (str); - - if (co_proc_number (&str) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (&str) == FAIL - || cp_opc_expr (&str, 21, 3) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (&str) == FAIL - || reg_required_here (&str, 12) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (&str) == FAIL - || cp_reg_required_here (&str, 16) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (&str) == FAIL - || cp_reg_required_here (&str, 0) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (&str) == SUCCESS) - { - if (cp_opc_expr (&str, 5, 3) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - } - if (flags) - { - inst.error = BAD_COND; - } - - end_of_line (str); - return; -} - -static void -do_fp_ctrl (str, flags) - char * str; - unsigned long flags ATTRIBUTE_UNUSED; -{ - /* FP control registers. - Format: <WFS|RFS|WFC|RFC>{cond} Rn */ - - skip_whitespace (str); - - if (reg_required_here (&str, 12) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - end_of_line (str); - return; -} - -static void -do_fp_ldst (str, flags) - char * str; - unsigned long flags ATTRIBUTE_UNUSED; -{ - skip_whitespace (str); - - switch (inst.suffix) - { - case SUFF_S: - break; - case SUFF_D: - inst.instruction |= CP_T_X; - break; - case SUFF_E: - inst.instruction |= CP_T_Y; - break; - case SUFF_P: - inst.instruction |= CP_T_X | CP_T_Y; - break; - default: - abort (); - } - - if (fp_reg_required_here (&str, 12) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (&str) == FAIL - || cp_address_required_here (&str) == FAIL) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - end_of_line (str); -} - -static void -do_fp_ldmstm (str, flags) - char * str; - unsigned long flags; -{ - int num_regs; - - skip_whitespace (str); - - if (fp_reg_required_here (&str, 12) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } - - /* Get Number of registers to transfer */ - if (skip_past_comma (&str) == FAIL - || my_get_expression (&inst.reloc.exp, &str)) - { - if (! inst.error) - inst.error = _("constant expression expected"); - return; - } - - if (inst.reloc.exp.X_op != O_constant) - { - inst.error = _("Constant value required for number of registers"); - return; - } - - num_regs = inst.reloc.exp.X_add_number; - - if (num_regs < 1 || num_regs > 4) - { - inst.error = _("number of registers must be in the range [1:4]"); - return; - } - - switch (num_regs) - { - case 1: - inst.instruction |= CP_T_X; - break; - case 2: - inst.instruction |= CP_T_Y; - break; - case 3: - inst.instruction |= CP_T_Y | CP_T_X; - break; - case 4: - break; - default: - abort (); - } - - if (flags) - { - int reg; - int write_back; - int offset; - - /* The instruction specified "ea" or "fd", so we can only accept - [Rn]{!}. The instruction does not really support stacking or - unstacking, so we have to emulate these by setting appropriate - bits and offsets. */ - if (skip_past_comma (&str) == FAIL - || *str != '[') - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } - - str++; - skip_whitespace (str); - - if ((reg = reg_required_here (&str, 16)) == FAIL) - return; - - skip_whitespace (str); - - if (*str != ']') - { - inst.error = BAD_ARGS; - return; - } - - str++; - if (*str == '!') - { - write_back = 1; - str++; - if (reg == REG_PC) - { - inst.error = _("R15 not allowed as base register with write-back"); - return; - } - } - else - write_back = 0; - - if (flags & CP_T_Pre) - { - /* Pre-decrement */ - offset = 3 * num_regs; - if (write_back) - flags |= CP_T_WB; - } - else - { - /* Post-increment */ - if (write_back) - { - flags |= CP_T_WB; - offset = 3 * num_regs; - } - else - { - /* No write-back, so convert this into a standard pre-increment - instruction -- aesthetically more pleasing. */ - flags = CP_T_Pre | CP_T_UD; - offset = 0; - } - } - - inst.instruction |= flags | offset; - } - else if (skip_past_comma (&str) == FAIL - || cp_address_required_here (&str) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } - - end_of_line (str); -} - -static void -do_fp_dyadic (str, flags) - char * str; - unsigned long flags; -{ - skip_whitespace (str); - - switch (inst.suffix) - { - case SUFF_S: - break; - case SUFF_D: - inst.instruction |= 0x00000080; - break; - case SUFF_E: - inst.instruction |= 0x00080000; - break; - default: - abort (); - } - - if (fp_reg_required_here (&str, 12) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (&str) == FAIL - || fp_reg_required_here (&str, 16) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (&str) == FAIL - || fp_op2 (&str) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } - - inst.instruction |= flags; - end_of_line (str); - return; -} - -static void -do_fp_monadic (str, flags) - char * str; - unsigned long flags; -{ - skip_whitespace (str); - - switch (inst.suffix) - { - case SUFF_S: - break; - case SUFF_D: - inst.instruction |= 0x00000080; - break; - case SUFF_E: - inst.instruction |= 0x00080000; - break; - default: - abort (); - } - - if (fp_reg_required_here (&str, 12) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (&str) == FAIL - || fp_op2 (&str) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } - - inst.instruction |= flags; - end_of_line (str); - return; -} - -static void -do_fp_cmp (str, flags) - char * str; - unsigned long flags; -{ - skip_whitespace (str); - - if (fp_reg_required_here (&str, 16) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (&str) == FAIL - || fp_op2 (&str) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } - - inst.instruction |= flags; - end_of_line (str); - return; -} - -static void -do_fp_from_reg (str, flags) - char * str; - unsigned long flags; -{ - skip_whitespace (str); - - switch (inst.suffix) - { - case SUFF_S: - break; - case SUFF_D: - inst.instruction |= 0x00000080; - break; - case SUFF_E: - inst.instruction |= 0x00080000; - break; - default: - abort (); - } - - if (fp_reg_required_here (&str, 16) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (&str) == FAIL - || reg_required_here (&str, 12) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } - - inst.instruction |= flags; - end_of_line (str); - return; -} - -static void -do_fp_to_reg (str, flags) - char * str; - unsigned long flags; -{ - skip_whitespace (str); - - if (reg_required_here (&str, 12) == FAIL) - return; - - if (skip_past_comma (&str) == FAIL - || fp_reg_required_here (&str, 0) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } - - inst.instruction |= flags; - end_of_line (str); - return; -} - -/* Thumb specific routines */ - -/* Parse and validate that a register is of the right form, this saves - repeated checking of this information in many similar cases. - Unlike the 32-bit case we do not insert the register into the opcode - here, since the position is often unknown until the full instruction - has been parsed. */ -static int -thumb_reg (strp, hi_lo) - char ** strp; - int hi_lo; -{ - int reg; - - if ((reg = reg_required_here (strp, -1)) == FAIL) - return FAIL; - - switch (hi_lo) - { - case THUMB_REG_LO: - if (reg > 7) - { - inst.error = _("lo register required"); - return FAIL; - } - break; - - case THUMB_REG_HI: - if (reg < 8) - { - inst.error = _("hi register required"); - return FAIL; - } - break; - - default: - break; - } - - return reg; -} - -/* Parse an add or subtract instruction, SUBTRACT is non-zero if the opcode - was SUB. */ -static void -thumb_add_sub (str, subtract) - char * str; - int subtract; -{ - int Rd, Rs, Rn = FAIL; - - skip_whitespace (str); - - if ((Rd = thumb_reg (&str, THUMB_REG_ANY)) == FAIL - || skip_past_comma (&str) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } - - if (is_immediate_prefix (*str)) - { - Rs = Rd; - str++; - if (my_get_expression (&inst.reloc.exp, &str)) - return; - } - else - { - if ((Rs = thumb_reg (&str, THUMB_REG_ANY)) == FAIL) - return; - - if (skip_past_comma (&str) == FAIL) - { - /* Two operand format, shuffle the registers and pretend there - are 3 */ - Rn = Rs; - Rs = Rd; - } - else if (is_immediate_prefix (*str)) - { - str++; - if (my_get_expression (&inst.reloc.exp, &str)) - return; - } - else if ((Rn = thumb_reg (&str, THUMB_REG_ANY)) == FAIL) - return; - } - - /* We now have Rd and Rs set to registers, and Rn set to a register or FAIL; - for the latter case, EXPR contains the immediate that was found. */ - if (Rn != FAIL) - { - /* All register format. */ - if (Rd > 7 || Rs > 7 || Rn > 7) - { - if (Rs != Rd) - { - inst.error = _("dest and source1 must be the same register"); - return; - } - - /* Can't do this for SUB */ - if (subtract) - { - inst.error = _("subtract valid only on lo regs"); - return; - } - - inst.instruction = (T_OPCODE_ADD_HI - | (Rd > 7 ? THUMB_H1 : 0) - | (Rn > 7 ? THUMB_H2 : 0)); - inst.instruction |= (Rd & 7) | ((Rn & 7) << 3); - } - else - { - inst.instruction = subtract ? T_OPCODE_SUB_R3 : T_OPCODE_ADD_R3; - inst.instruction |= Rd | (Rs << 3) | (Rn << 6); - } - } - else - { - /* Immediate expression, now things start to get nasty. */ - - /* First deal with HI regs, only very restricted cases allowed: - Adjusting SP, and using PC or SP to get an address. */ - if ((Rd > 7 && (Rd != REG_SP || Rs != REG_SP)) - || (Rs > 7 && Rs != REG_SP && Rs != REG_PC)) - { - inst.error = _("invalid Hi register with immediate"); - return; - } - - if (inst.reloc.exp.X_op != O_constant) - { - /* Value isn't known yet, all we can do is store all the fragments - we know about in the instruction and let the reloc hacking - work it all out. */ - inst.instruction = (subtract ? 0x8000 : 0) | (Rd << 4) | Rs; - inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD; - } - else - { - int offset = inst.reloc.exp.X_add_number; - - if (subtract) - offset = -offset; - - if (offset < 0) - { - offset = -offset; - subtract = 1; - - /* Quick check, in case offset is MIN_INT */ - if (offset < 0) - { - inst.error = _("immediate value out of range"); - return; - } - } - else - subtract = 0; - - if (Rd == REG_SP) - { - if (offset & ~0x1fc) - { - inst.error = _("invalid immediate value for stack adjust"); - return; - } - inst.instruction = subtract ? T_OPCODE_SUB_ST : T_OPCODE_ADD_ST; - inst.instruction |= offset >> 2; - } - else if (Rs == REG_PC || Rs == REG_SP) - { - if (subtract - || (offset & ~0x3fc)) - { - inst.error = _("invalid immediate for address calculation"); - return; - } - inst.instruction = (Rs == REG_PC ? T_OPCODE_ADD_PC - : T_OPCODE_ADD_SP); - inst.instruction |= (Rd << 8) | (offset >> 2); - } - else if (Rs == Rd) - { - if (offset & ~0xff) - { - inst.error = _("immediate value out of range"); - return; - } - inst.instruction = subtract ? T_OPCODE_SUB_I8 : T_OPCODE_ADD_I8; - inst.instruction |= (Rd << 8) | offset; - } - else - { - if (offset & ~0x7) - { - inst.error = _("immediate value out of range"); - return; - } - inst.instruction = subtract ? T_OPCODE_SUB_I3 : T_OPCODE_ADD_I3; - inst.instruction |= Rd | (Rs << 3) | (offset << 6); - } - } - } - - end_of_line (str); -} - -static void -thumb_shift (str, shift) - char * str; - int shift; -{ - int Rd, Rs, Rn = FAIL; - - skip_whitespace (str); - - if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL - || skip_past_comma (&str) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } - - if (is_immediate_prefix (*str)) - { - /* Two operand immediate format, set Rs to Rd. */ - Rs = Rd; - str ++; - if (my_get_expression (&inst.reloc.exp, &str)) - return; - } - else - { - if ((Rs = thumb_reg (&str, THUMB_REG_LO)) == FAIL) - return; - - if (skip_past_comma (&str) == FAIL) - { - /* Two operand format, shuffle the registers and pretend there - are 3 */ - Rn = Rs; - Rs = Rd; - } - else if (is_immediate_prefix (*str)) - { - str++; - if (my_get_expression (&inst.reloc.exp, &str)) - return; - } - else if ((Rn = thumb_reg (&str, THUMB_REG_LO)) == FAIL) - return; - } - - /* We now have Rd and Rs set to registers, and Rn set to a register or FAIL; - for the latter case, EXPR contains the immediate that was found. */ - - if (Rn != FAIL) - { - if (Rs != Rd) - { - inst.error = _("source1 and dest must be same register"); - return; - } - - switch (shift) - { - case THUMB_ASR: inst.instruction = T_OPCODE_ASR_R; break; - case THUMB_LSL: inst.instruction = T_OPCODE_LSL_R; break; - case THUMB_LSR: inst.instruction = T_OPCODE_LSR_R; break; - } - - inst.instruction |= Rd | (Rn << 3); - } - else - { - switch (shift) - { - case THUMB_ASR: inst.instruction = T_OPCODE_ASR_I; break; - case THUMB_LSL: inst.instruction = T_OPCODE_LSL_I; break; - case THUMB_LSR: inst.instruction = T_OPCODE_LSR_I; break; - } - - if (inst.reloc.exp.X_op != O_constant) - { - /* Value isn't known yet, create a dummy reloc and let reloc - hacking fix it up */ - - inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT; - } - else - { - unsigned shift_value = inst.reloc.exp.X_add_number; - - if (shift_value > 32 || (shift_value == 32 && shift == THUMB_LSL)) - { - inst.error = _("Invalid immediate for shift"); - return; - } - - /* Shifts of zero are handled by converting to LSL */ - if (shift_value == 0) - inst.instruction = T_OPCODE_LSL_I; - - /* Shifts of 32 are encoded as a shift of zero */ - if (shift_value == 32) - shift_value = 0; - - inst.instruction |= shift_value << 6; - } - - inst.instruction |= Rd | (Rs << 3); - } - - end_of_line (str); -} - -static void -thumb_mov_compare (str, move) - char * str; - int move; -{ - int Rd, Rs = FAIL; - - skip_whitespace (str); - - if ((Rd = thumb_reg (&str, THUMB_REG_ANY)) == FAIL - || skip_past_comma (&str) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } - - if (is_immediate_prefix (*str)) - { - str++; - if (my_get_expression (&inst.reloc.exp, &str)) - return; - } - else if ((Rs = thumb_reg (&str, THUMB_REG_ANY)) == FAIL) - return; - - if (Rs != FAIL) - { - if (Rs < 8 && Rd < 8) - { - if (move == THUMB_MOVE) - /* A move of two lowregs is encoded as ADD Rd, Rs, #0 - since a MOV instruction produces unpredictable results */ - inst.instruction = T_OPCODE_ADD_I3; - else - inst.instruction = T_OPCODE_CMP_LR; - inst.instruction |= Rd | (Rs << 3); - } - else - { - if (move == THUMB_MOVE) - inst.instruction = T_OPCODE_MOV_HR; - else - inst.instruction = T_OPCODE_CMP_HR; - - if (Rd > 7) - inst.instruction |= THUMB_H1; - - if (Rs > 7) - inst.instruction |= THUMB_H2; - - inst.instruction |= (Rd & 7) | ((Rs & 7) << 3); - } - } - else - { - if (Rd > 7) - { - inst.error = _("only lo regs allowed with immediate"); - return; - } - - if (move == THUMB_MOVE) - inst.instruction = T_OPCODE_MOV_I8; - else - inst.instruction = T_OPCODE_CMP_I8; - - inst.instruction |= Rd << 8; - - if (inst.reloc.exp.X_op != O_constant) - inst.reloc.type = BFD_RELOC_ARM_THUMB_IMM; - else - { - unsigned value = inst.reloc.exp.X_add_number; - - if (value > 255) - { - inst.error = _("invalid immediate"); - return; - } - - inst.instruction |= value; - } - } - - end_of_line (str); -} - -static void -thumb_load_store (str, load_store, size) - char * str; - int load_store; - int size; -{ - int Rd, Rb, Ro = FAIL; - - skip_whitespace (str); - - if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL - || skip_past_comma (&str) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } - - if (*str == '[') - { - str++; - if ((Rb = thumb_reg (&str, THUMB_REG_ANY)) == FAIL) - return; - - if (skip_past_comma (&str) != FAIL) - { - if (is_immediate_prefix (*str)) - { - str++; - if (my_get_expression (&inst.reloc.exp, &str)) - return; - } - else if ((Ro = thumb_reg (&str, THUMB_REG_LO)) == FAIL) - return; - } - else - { - inst.reloc.exp.X_op = O_constant; - inst.reloc.exp.X_add_number = 0; - } - - if (*str != ']') - { - inst.error = _("expected ']'"); - return; - } - str++; - } - else if (*str == '=') - { - /* Parse an "ldr Rd, =expr" instruction; this is another pseudo op */ - str++; - - skip_whitespace (str); - - if (my_get_expression (& inst.reloc.exp, & str)) - return; - - end_of_line (str); - - if ( inst.reloc.exp.X_op != O_constant - && inst.reloc.exp.X_op != O_symbol) - { - inst.error = "Constant expression expected"; - return; - } - - if (inst.reloc.exp.X_op == O_constant - && ((inst.reloc.exp.X_add_number & ~0xFF) == 0)) - { - /* This can be done with a mov instruction */ - - inst.instruction = T_OPCODE_MOV_I8 | (Rd << 8); - inst.instruction |= inst.reloc.exp.X_add_number; - return; - } - - /* Insert into literal pool */ - if (add_to_lit_pool () == FAIL) - { - if (!inst.error) - inst.error = "literal pool insertion failed"; - return; - } - - inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET; - inst.reloc.pc_rel = 1; - inst.instruction = T_OPCODE_LDR_PC | (Rd << 8); - inst.reloc.exp.X_add_number += 4; /* Adjust ARM pipeline offset to Thumb */ - - return; - } - else - { - if (my_get_expression (&inst.reloc.exp, &str)) - return; - - inst.instruction = T_OPCODE_LDR_PC | (Rd << 8); - inst.reloc.pc_rel = 1; - inst.reloc.exp.X_add_number -= 4; /* Pipeline offset */ - inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET; - end_of_line (str); - return; - } - - if (Rb == REG_PC || Rb == REG_SP) - { - if (size != THUMB_WORD) - { - inst.error = _("byte or halfword not valid for base register"); - return; - } - else if (Rb == REG_PC && load_store != THUMB_LOAD) - { - inst.error = _("R15 based store not allowed"); - return; - } - else if (Ro != FAIL) - { - inst.error = _("Invalid base register for register offset"); - return; - } - - if (Rb == REG_PC) - inst.instruction = T_OPCODE_LDR_PC; - else if (load_store == THUMB_LOAD) - inst.instruction = T_OPCODE_LDR_SP; - else - inst.instruction = T_OPCODE_STR_SP; - - inst.instruction |= Rd << 8; - if (inst.reloc.exp.X_op == O_constant) - { - unsigned offset = inst.reloc.exp.X_add_number; - - if (offset & ~0x3fc) - { - inst.error = _("invalid offset"); - return; - } - - inst.instruction |= offset >> 2; - } - else - inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET; - } - else if (Rb > 7) - { - inst.error = _("invalid base register in load/store"); - return; - } - else if (Ro == FAIL) - { - /* Immediate offset */ - if (size == THUMB_WORD) - inst.instruction = (load_store == THUMB_LOAD - ? T_OPCODE_LDR_IW : T_OPCODE_STR_IW); - else if (size == THUMB_HALFWORD) - inst.instruction = (load_store == THUMB_LOAD - ? T_OPCODE_LDR_IH : T_OPCODE_STR_IH); - else - inst.instruction = (load_store == THUMB_LOAD - ? T_OPCODE_LDR_IB : T_OPCODE_STR_IB); - - inst.instruction |= Rd | (Rb << 3); - - if (inst.reloc.exp.X_op == O_constant) - { - unsigned offset = inst.reloc.exp.X_add_number; - - if (offset & ~(0x1f << size)) - { - inst.error = _("Invalid offset"); - return; - } - inst.instruction |= (offset >> size) << 6; - } - else - inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET; - } - else - { - /* Register offset */ - if (size == THUMB_WORD) - inst.instruction = (load_store == THUMB_LOAD - ? T_OPCODE_LDR_RW : T_OPCODE_STR_RW); - else if (size == THUMB_HALFWORD) - inst.instruction = (load_store == THUMB_LOAD - ? T_OPCODE_LDR_RH : T_OPCODE_STR_RH); - else - inst.instruction = (load_store == THUMB_LOAD - ? T_OPCODE_LDR_RB : T_OPCODE_STR_RB); - - inst.instruction |= Rd | (Rb << 3) | (Ro << 6); - } - - end_of_line (str); -} - -static void -do_t_nop (str) - char * str; -{ - /* Do nothing */ - end_of_line (str); - return; -} - -/* Handle the Format 4 instructions that do not have equivalents in other - formats. That is, ADC, AND, EOR, SBC, ROR, TST, NEG, CMN, ORR, MUL, - BIC and MVN. */ -static void -do_t_arit (str) - char * str; -{ - int Rd, Rs, Rn; - - skip_whitespace (str); - - if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL - || skip_past_comma (&str) == FAIL - || (Rs = thumb_reg (&str, THUMB_REG_LO)) == FAIL) - { - inst.error = BAD_ARGS; - return; - } - - if (skip_past_comma (&str) != FAIL) - { - /* Three operand format not allowed for TST, CMN, NEG and MVN. - (It isn't allowed for CMP either, but that isn't handled by this - function.) */ - if (inst.instruction == T_OPCODE_TST - || inst.instruction == T_OPCODE_CMN - || inst.instruction == T_OPCODE_NEG - || inst.instruction == T_OPCODE_MVN) - { - inst.error = BAD_ARGS; - return; - } - - if ((Rn = thumb_reg (&str, THUMB_REG_LO)) == FAIL) - return; - - if (Rs != Rd) - { - inst.error = _("dest and source1 one must be the same register"); - return; - } - Rs = Rn; - } - - if (inst.instruction == T_OPCODE_MUL - && Rs == Rd) - as_tsktsk (_("Rs and Rd must be different in MUL")); - - inst.instruction |= Rd | (Rs << 3); - end_of_line (str); -} - -static void -do_t_add (str) - char * str; -{ - thumb_add_sub (str, 0); -} - -static void -do_t_asr (str) - char * str; -{ - thumb_shift (str, THUMB_ASR); -} - -static void -do_t_branch9 (str) - char * str; -{ - if (my_get_expression (&inst.reloc.exp, &str)) - return; - inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH9; - inst.reloc.pc_rel = 1; - end_of_line (str); -} - -static void -do_t_branch12 (str) - char * str; -{ - if (my_get_expression (&inst.reloc.exp, &str)) - return; - inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH12; - inst.reloc.pc_rel = 1; - end_of_line (str); -} - -/* Find the real, Thumb encoded start of a Thumb function. */ - -static symbolS * -find_real_start (symbolP) - symbolS * symbolP; -{ - char * real_start; - const char * name = S_GET_NAME (symbolP); - symbolS * new_target; - - /* This definiton must agree with the one in gcc/config/arm/thumb.c */ -#define STUB_NAME ".real_start_of" - - if (name == NULL) - abort(); - - /* Names that start with '.' are local labels, not function entry points. - The compiler may generate BL instructions to these labels because it - needs to perform a branch to a far away location. */ - if (name[0] == '.') - return symbolP; - - real_start = malloc (strlen (name) + strlen (STUB_NAME) + 1); - sprintf (real_start, "%s%s", STUB_NAME, name); - - new_target = symbol_find (real_start); - - if (new_target == NULL) - { - as_warn ("Failed to find real start of function: %s\n", name); - new_target = symbolP; - } - - free (real_start); - - return new_target; -} - - -static void -do_t_branch23 (str) - char * str; -{ - if (my_get_expression (& inst.reloc.exp, & str)) - return; - - inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH23; - inst.reloc.pc_rel = 1; - end_of_line (str); - - /* If the destination of the branch is a defined symbol which does not have - the THUMB_FUNC attribute, then we must be calling a function which has - the (interfacearm) attribute. We look for the Thumb entry point to that - function and change the branch to refer to that function instead. */ - if ( inst.reloc.exp.X_op == O_symbol - && inst.reloc.exp.X_add_symbol != NULL - && S_IS_DEFINED (inst.reloc.exp.X_add_symbol) - && ! THUMB_IS_FUNC (inst.reloc.exp.X_add_symbol)) - inst.reloc.exp.X_add_symbol = find_real_start (inst.reloc.exp.X_add_symbol); -} - -static void -do_t_bx (str) - char * str; -{ - int reg; - - skip_whitespace (str); - - if ((reg = thumb_reg (&str, THUMB_REG_ANY)) == FAIL) - return; - - /* This sets THUMB_H2 from the top bit of reg. */ - inst.instruction |= reg << 3; - - /* ??? FIXME: Should add a hacky reloc here if reg is REG_PC. The reloc - should cause the alignment to be checked once it is known. This is - because BX PC only works if the instruction is word aligned. */ - - end_of_line (str); -} - -static void -do_t_compare (str) - char * str; -{ - thumb_mov_compare (str, THUMB_COMPARE); -} - -static void -do_t_ldmstm (str) - char * str; -{ - int Rb; - long range; - - skip_whitespace (str); - - if ((Rb = thumb_reg (&str, THUMB_REG_LO)) == FAIL) - return; - - if (*str != '!') - as_warn (_("Inserted missing '!': load/store multiple always writes back base register")); - else - str++; - - if (skip_past_comma (&str) == FAIL - || (range = reg_list (&str)) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } - - if (inst.reloc.type != BFD_RELOC_NONE) - { - /* This really doesn't seem worth it. */ - inst.reloc.type = BFD_RELOC_NONE; - inst.error = _("Expression too complex"); - return; - } - - if (range & ~0xff) - { - inst.error = _("only lo-regs valid in load/store multiple"); - return; - } - - inst.instruction |= (Rb << 8) | range; - end_of_line (str); -} - -static void -do_t_ldr (str) - char * str; -{ - thumb_load_store (str, THUMB_LOAD, THUMB_WORD); -} - -static void -do_t_ldrb (str) - char * str; -{ - thumb_load_store (str, THUMB_LOAD, THUMB_BYTE); -} - -static void -do_t_ldrh (str) - char * str; -{ - thumb_load_store (str, THUMB_LOAD, THUMB_HALFWORD); -} - -static void -do_t_lds (str) - char * str; -{ - int Rd, Rb, Ro; - - skip_whitespace (str); - - if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL - || skip_past_comma (&str) == FAIL - || *str++ != '[' - || (Rb = thumb_reg (&str, THUMB_REG_LO)) == FAIL - || skip_past_comma (&str) == FAIL - || (Ro = thumb_reg (&str, THUMB_REG_LO)) == FAIL - || *str++ != ']') - { - if (! inst.error) - inst.error = _("Syntax: ldrs[b] Rd, [Rb, Ro]"); - return; - } - - inst.instruction |= Rd | (Rb << 3) | (Ro << 6); - end_of_line (str); -} - -static void -do_t_lsl (str) - char * str; -{ - thumb_shift (str, THUMB_LSL); -} - -static void -do_t_lsr (str) - char * str; -{ - thumb_shift (str, THUMB_LSR); -} - -static void -do_t_mov (str) - char * str; -{ - thumb_mov_compare (str, THUMB_MOVE); -} - -static void -do_t_push_pop (str) - char * str; -{ - long range; - - skip_whitespace (str); - - if ((range = reg_list (&str)) == FAIL) - { - if (! inst.error) - inst.error = BAD_ARGS; - return; - } - - if (inst.reloc.type != BFD_RELOC_NONE) - { - /* This really doesn't seem worth it. */ - inst.reloc.type = BFD_RELOC_NONE; - inst.error = _("Expression too complex"); - return; - } - - if (range & ~0xff) - { - if ((inst.instruction == T_OPCODE_PUSH - && (range & ~0xff) == 1 << REG_LR) - || (inst.instruction == T_OPCODE_POP - && (range & ~0xff) == 1 << REG_PC)) - { - inst.instruction |= THUMB_PP_PC_LR; - range &= 0xff; - } - else - { - inst.error = _("invalid register list to push/pop instruction"); - return; - } - } - - inst.instruction |= range; - end_of_line (str); -} - -static void -do_t_str (str) - char * str; -{ - thumb_load_store (str, THUMB_STORE, THUMB_WORD); -} - -static void -do_t_strb (str) - char * str; -{ - thumb_load_store (str, THUMB_STORE, THUMB_BYTE); -} - -static void -do_t_strh (str) - char * str; -{ - thumb_load_store (str, THUMB_STORE, THUMB_HALFWORD); -} - -static void -do_t_sub (str) - char * str; -{ - thumb_add_sub (str, 1); -} - -static void -do_t_swi (str) - char * str; -{ - skip_whitespace (str); - - if (my_get_expression (&inst.reloc.exp, &str)) - return; - - inst.reloc.type = BFD_RELOC_ARM_SWI; - end_of_line (str); - return; -} - -static void -do_t_adr (str) - char * str; -{ - int reg; - - /* This is a pseudo-op of the form "adr rd, label" to be converted - into a relative address of the form "add rd, pc, #label-.-4". */ - skip_whitespace (str); - - /* Store Rd in temporary location inside instruction. */ - if ((reg = reg_required_here (&str, 4)) == FAIL - || (reg > 7) /* For Thumb reg must be r0..r7. */ - || skip_past_comma (&str) == FAIL - || my_get_expression (&inst.reloc.exp, &str)) - { - if (!inst.error) - inst.error = BAD_ARGS; - return; - } - - inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD; - inst.reloc.exp.X_add_number -= 4; /* PC relative adjust. */ - inst.reloc.pc_rel = 1; - inst.instruction |= REG_PC; /* Rd is already placed into the instruction. */ - - end_of_line (str); -} - -static void -insert_reg (entry) - int entry; -{ - int len = strlen (reg_table[entry].name) + 2; - char * buf = (char *) xmalloc (len); - char * buf2 = (char *) xmalloc (len); - int i = 0; - -#ifdef REGISTER_PREFIX - buf[i++] = REGISTER_PREFIX; -#endif - - strcpy (buf + i, reg_table[entry].name); - - for (i = 0; buf[i]; i++) - buf2[i] = islower (buf[i]) ? toupper (buf[i]) : buf[i]; - - buf2[i] = '\0'; - - hash_insert (arm_reg_hsh, buf, (PTR) ®_table[entry]); - hash_insert (arm_reg_hsh, buf2, (PTR) ®_table[entry]); -} - -static void -insert_reg_alias (str, regnum) - char *str; - int regnum; -{ - struct reg_entry *new = - (struct reg_entry *)xmalloc (sizeof (struct reg_entry)); - char *name = xmalloc (strlen (str) + 1); - strcpy (name, str); - - new->name = name; - new->number = regnum; - - hash_insert (arm_reg_hsh, name, (PTR) new); -} - -static void -set_constant_flonums () -{ - int i; - - for (i = 0; i < NUM_FLOAT_VALS; i++) - if (atof_ieee ((char *)fp_const[i], 'x', fp_values[i]) == NULL) - abort (); -} - -void -md_begin () -{ - unsigned mach; - unsigned int i; - - if ( (arm_ops_hsh = hash_new ()) == NULL - || (arm_tops_hsh = hash_new ()) == NULL - || (arm_cond_hsh = hash_new ()) == NULL - || (arm_shift_hsh = hash_new ()) == NULL - || (arm_reg_hsh = hash_new ()) == NULL - || (arm_psr_hsh = hash_new ()) == NULL) - as_fatal (_("Virtual memory exhausted")); - - for (i = 0; i < sizeof (insns) / sizeof (struct asm_opcode); i++) - hash_insert (arm_ops_hsh, insns[i].template, (PTR) (insns + i)); - for (i = 0; i < sizeof (tinsns) / sizeof (struct thumb_opcode); i++) - hash_insert (arm_tops_hsh, tinsns[i].template, (PTR) (tinsns + i)); - for (i = 0; i < sizeof (conds) / sizeof (struct asm_cond); i++) - hash_insert (arm_cond_hsh, conds[i].template, (PTR) (conds + i)); - for (i = 0; i < sizeof (shift) / sizeof (struct asm_shift); i++) - hash_insert (arm_shift_hsh, shift[i].template, (PTR) (shift + i)); - for (i = 0; i < sizeof (psrs) / sizeof (struct asm_psr); i++) - hash_insert (arm_psr_hsh, psrs[i].template, (PTR) (psrs + i)); - - for (i = 0; reg_table[i].name; i++) - insert_reg (i); - - set_constant_flonums (); - -#if defined OBJ_COFF || defined OBJ_ELF - { - unsigned int flags = 0; - - /* Set the flags in the private structure. */ - if (uses_apcs_26) flags |= F_APCS26; - if (support_interwork) flags |= F_INTERWORK; - if (uses_apcs_float) flags |= F_APCS_FLOAT; - if (pic_code) flags |= F_PIC; - if ((cpu_variant & FPU_ALL) == FPU_NONE) flags |= F_SOFT_FLOAT; - - bfd_set_private_flags (stdoutput, flags); - } -#endif - - /* Record the CPU type as well. */ - switch (cpu_variant & ARM_CPU_MASK) - { - case ARM_2: - mach = bfd_mach_arm_2; - break; - - case ARM_3: /* Also ARM_250. */ - mach = bfd_mach_arm_2a; - break; - - default: - case ARM_6 | ARM_3 | ARM_2: /* Actually no CPU type defined. */ - mach = bfd_mach_arm_4; - break; - - case ARM_7: /* Also ARM_6. */ - mach = bfd_mach_arm_3; - break; - } - - /* Catch special cases. */ - if (cpu_variant != (FPU_DEFAULT | CPU_DEFAULT)) - { - if (cpu_variant & (ARM_EXT_V5 & ARM_THUMB)) - mach = bfd_mach_arm_5T; - else if (cpu_variant & ARM_EXT_V5) - mach = bfd_mach_arm_5; - else if (cpu_variant & ARM_THUMB) - mach = bfd_mach_arm_4T; - else if ((cpu_variant & ARM_ARCH_V4) == ARM_ARCH_V4) - mach = bfd_mach_arm_4; - else if (cpu_variant & ARM_LONGMUL) - mach = bfd_mach_arm_3M; - } - - bfd_set_arch_mach (stdoutput, TARGET_ARCH, mach); -} - -/* Turn an integer of n bytes (in val) into a stream of bytes appropriate - for use in the a.out file, and stores them in the array pointed to by buf. - This knows about the endian-ness of the target machine and does - THE RIGHT THING, whatever it is. Possible values for n are 1 (byte) - 2 (short) and 4 (long) Floating numbers are put out as a series of - LITTLENUMS (shorts, here at least). */ -void -md_number_to_chars (buf, val, n) - char * buf; - valueT val; - int n; -{ - if (target_big_endian) - number_to_chars_bigendian (buf, val, n); - else - number_to_chars_littleendian (buf, val, n); -} - -static valueT -md_chars_to_number (buf, n) - char * buf; - int n; -{ - valueT result = 0; - unsigned char * where = (unsigned char *) buf; - - if (target_big_endian) - { - while (n--) - { - result <<= 8; - result |= (*where++ & 255); - } - } - else - { - while (n--) - { - result <<= 8; - result |= (where[n] & 255); - } - } - - return result; -} - -/* Turn a string in input_line_pointer into a floating point constant - of type TYPE, and store the appropriate bytes in *litP. The number - of LITTLENUMS emitted is stored in *sizeP . An error message is - returned, or NULL on OK. - - Note that fp constants aren't represent in the normal way on the ARM. - In big endian mode, things are as expected. However, in little endian - mode fp constants are big-endian word-wise, and little-endian byte-wise - within the words. For example, (double) 1.1 in big endian mode is - the byte sequence 3f f1 99 99 99 99 99 9a, and in little endian mode is - the byte sequence 99 99 f1 3f 9a 99 99 99. - - ??? The format of 12 byte floats is uncertain according to gcc's arm.h. */ - -char * -md_atof (type, litP, sizeP) - char type; - char * litP; - int * sizeP; -{ - int prec; - LITTLENUM_TYPE words[MAX_LITTLENUMS]; - char *t; - int i; - - switch (type) - { - case 'f': - case 'F': - case 's': - case 'S': - prec = 2; - break; - - case 'd': - case 'D': - case 'r': - case 'R': - prec = 4; - break; - - case 'x': - case 'X': - prec = 6; - break; - - case 'p': - case 'P': - prec = 6; - break; - - default: - *sizeP = 0; - return _("Bad call to MD_ATOF()"); - } - - t = atof_ieee (input_line_pointer, type, words); - if (t) - input_line_pointer = t; - *sizeP = prec * 2; - - if (target_big_endian) - { - for (i = 0; i < prec; i++) - { - md_number_to_chars (litP, (valueT) words[i], 2); - litP += 2; - } - } - else - { - /* For a 4 byte float the order of elements in `words' is 1 0. For an - 8 byte float the order is 1 0 3 2. */ - for (i = 0; i < prec; i += 2) - { - md_number_to_chars (litP, (valueT) words[i + 1], 2); - md_number_to_chars (litP + 2, (valueT) words[i], 2); - litP += 4; - } - } - - return 0; -} - -/* The knowledge of the PC's pipeline offset is built into the insns themselves. */ -long -md_pcrel_from (fixP) - fixS * fixP; -{ - if ( fixP->fx_addsy - && S_GET_SEGMENT (fixP->fx_addsy) == undefined_section - && fixP->fx_subsy == NULL) - return 0; - - if (fixP->fx_pcrel && (fixP->fx_r_type == BFD_RELOC_ARM_THUMB_ADD)) - { - /* PC relative addressing on the Thumb is slightly odd - as the bottom two bits of the PC are forced to zero - for the calculation. */ - return (fixP->fx_where + fixP->fx_frag->fr_address) & ~3; - } - -#ifdef TE_WINCE - /* The pattern was adjusted to accomodate CE's off-by-one fixups, - so we un-adjust here to compensate for the accomodation. */ - return fixP->fx_where + fixP->fx_frag->fr_address + 8; -#else - return fixP->fx_where + fixP->fx_frag->fr_address; -#endif -} - -/* Round up a section size to the appropriate boundary. */ -valueT -md_section_align (segment, size) - segT segment ATTRIBUTE_UNUSED; - valueT size; -{ -#ifdef OBJ_ELF - return size; -#else - /* Round all sects to multiple of 4 */ - return (size + 3) & ~3; -#endif -} - -/* Under ELF we need to default _GLOBAL_OFFSET_TABLE. Otherwise - we have no need to default values of symbols. */ - -/* ARGSUSED */ -symbolS * -md_undefined_symbol (name) - char * name; -{ -#ifdef OBJ_ELF - if (name[0] == '_' && name[1] == 'G' - && streq (name, GLOBAL_OFFSET_TABLE_NAME)) - { - if (!GOT_symbol) - { - if (symbol_find (name)) - as_bad ("GOT already in the symbol table"); - - GOT_symbol = symbol_new (name, undefined_section, - (valueT)0, & zero_address_frag); - } - - return GOT_symbol; - } -#endif - - return 0; -} - -/* arm_reg_parse () := if it looks like a register, return its token and - advance the pointer. */ - -static int -arm_reg_parse (ccp) - register char ** ccp; -{ - char * start = * ccp; - char c; - char * p; - struct reg_entry * reg; - -#ifdef REGISTER_PREFIX - if (*start != REGISTER_PREFIX) - return FAIL; - p = start + 1; -#else - p = start; -#ifdef OPTIONAL_REGISTER_PREFIX - if (*p == OPTIONAL_REGISTER_PREFIX) - p++, start++; -#endif -#endif - if (!isalpha (*p) || !is_name_beginner (*p)) - return FAIL; - - c = *p++; - while (isalpha (c) || isdigit (c) || c == '_') - c = *p++; - - *--p = 0; - reg = (struct reg_entry *) hash_find (arm_reg_hsh, start); - *p = c; - - if (reg) - { - *ccp = p; - return reg->number; - } - - return FAIL; -} - -static int -arm_psr_parse (ccp) - register char ** ccp; -{ - char * start = * ccp; - char c; - char * p; - CONST struct asm_psr * psr; - - p = start; - c = *p++; - while (isalpha (c) || c == '_') - c = *p++; - - *--p = 0; - psr = (CONST struct asm_psr *) hash_find (arm_psr_hsh, start); - *p = c; - - if (psr) - { - *ccp = p; - return psr->number; - } - - return FAIL; -} - -int -md_apply_fix3 (fixP, val, seg) - fixS * fixP; - valueT * val; - segT seg; -{ - offsetT value = * val; - offsetT newval; - unsigned int newimm; - unsigned long temp; - int sign; - char * buf = fixP->fx_where + fixP->fx_frag->fr_literal; - arm_fix_data * arm_data = (arm_fix_data *) fixP->tc_fix_data; - - assert (fixP->fx_r_type < BFD_RELOC_UNUSED); - - /* Note whether this will delete the relocation. */ -#if 0 /* patch from REarnshaw to JDavis (disabled for the moment, since it doesn't work fully) */ - if ((fixP->fx_addsy == 0 || symbol_constant_p (fixP->fx_addsy)) - && !fixP->fx_pcrel) -#else - if (fixP->fx_addsy == 0 && !fixP->fx_pcrel) -#endif - fixP->fx_done = 1; - - /* If this symbol is in a different section then we need to leave it for - the linker to deal with. Unfortunately, md_pcrel_from can't tell, - so we have to undo it's effects here. */ - if (fixP->fx_pcrel) - { - if (fixP->fx_addsy != NULL - && S_IS_DEFINED (fixP->fx_addsy) - && S_GET_SEGMENT (fixP->fx_addsy) != seg) - { - if (target_oabi - && (fixP->fx_r_type == BFD_RELOC_ARM_PCREL_BRANCH - )) - value = 0; - else - value += md_pcrel_from (fixP); - } - } - - fixP->fx_addnumber = value; /* Remember value for emit_reloc. */ - - switch (fixP->fx_r_type) - { - case BFD_RELOC_ARM_IMMEDIATE: - newimm = validate_immediate (value); - temp = md_chars_to_number (buf, INSN_SIZE); - - /* If the instruction will fail, see if we can fix things up by - changing the opcode. */ - if (newimm == (unsigned int) FAIL - && (newimm = negate_data_op (&temp, value)) == (unsigned int) FAIL) - { - as_bad_where (fixP->fx_file, fixP->fx_line, - _("invalid constant (%lx) after fixup"), - (unsigned long) value); - break; - } - - newimm |= (temp & 0xfffff000); - md_number_to_chars (buf, (valueT) newimm, INSN_SIZE); - break; - - case BFD_RELOC_ARM_ADRL_IMMEDIATE: - { - unsigned int highpart = 0; - unsigned int newinsn = 0xe1a00000; /* nop */ - newimm = validate_immediate (value); - temp = md_chars_to_number (buf, INSN_SIZE); - - /* If the instruction will fail, see if we can fix things up by - changing the opcode. */ - if (newimm == (unsigned int) FAIL - && (newimm = negate_data_op (& temp, value)) == (unsigned int) FAIL) - { - /* No ? OK - try using two ADD instructions to generate the value. */ - newimm = validate_immediate_twopart (value, & highpart); - - /* Yes - then make sure that the second instruction is also an add. */ - if (newimm != (unsigned int) FAIL) - newinsn = temp; - /* Still No ? Try using a negated value. */ - else if (validate_immediate_twopart (- value, & highpart) != (unsigned int) FAIL) - temp = newinsn = (temp & OPCODE_MASK) | OPCODE_SUB << DATA_OP_SHIFT; - /* Otherwise - give up. */ - else - { - as_bad_where (fixP->fx_file, fixP->fx_line, - _("Unable to compute ADRL instructions for PC offset of 0x%x"), value); - break; - } - - /* Replace the first operand in the 2nd instruction (which is the PC) - with the destination register. We have already added in the PC in the - first instruction and we do not want to do it again. */ - newinsn &= ~ 0xf0000; - newinsn |= ((newinsn & 0x0f000) << 4); - } - - newimm |= (temp & 0xfffff000); - md_number_to_chars (buf, (valueT) newimm, INSN_SIZE); - - highpart |= (newinsn & 0xfffff000); - md_number_to_chars (buf + INSN_SIZE, (valueT) highpart, INSN_SIZE); - } - break; - - case BFD_RELOC_ARM_OFFSET_IMM: - sign = value >= 0; - - if (value < 0) - value = - value; - - if (validate_offset_imm (value, 0) == FAIL) - { - as_bad_where (fixP->fx_file, fixP->fx_line, - _("bad immediate value for offset (%ld)"), (long) value); - break; - } - - newval = md_chars_to_number (buf, INSN_SIZE); - newval &= 0xff7ff000; - newval |= value | (sign ? INDEX_UP : 0); - md_number_to_chars (buf, newval, INSN_SIZE); - break; - - case BFD_RELOC_ARM_OFFSET_IMM8: - case BFD_RELOC_ARM_HWLITERAL: - sign = value >= 0; - - if (value < 0) - value = - value; - - if (validate_offset_imm (value, 1) == FAIL) - { - if (fixP->fx_r_type == BFD_RELOC_ARM_HWLITERAL) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("invalid literal constant: pool needs to be closer")); - else - as_bad (_("bad immediate value for half-word offset (%ld)"), - (long) value); - break; - } - - newval = md_chars_to_number (buf, INSN_SIZE); - newval &= 0xff7ff0f0; - newval |= ((value >> 4) << 8) | (value & 0xf) | (sign ? INDEX_UP : 0); - md_number_to_chars (buf, newval, INSN_SIZE); - break; - - case BFD_RELOC_ARM_LITERAL: - sign = value >= 0; - - if (value < 0) - value = - value; - - if (validate_offset_imm (value, 0) == FAIL) - { - as_bad_where (fixP->fx_file, fixP->fx_line, - _("invalid literal constant: pool needs to be closer")); - break; - } - - newval = md_chars_to_number (buf, INSN_SIZE); - newval &= 0xff7ff000; - newval |= value | (sign ? INDEX_UP : 0); - md_number_to_chars (buf, newval, INSN_SIZE); - break; - - case BFD_RELOC_ARM_SHIFT_IMM: - newval = md_chars_to_number (buf, INSN_SIZE); - if (((unsigned long) value) > 32 - || (value == 32 - && (((newval & 0x60) == 0) || (newval & 0x60) == 0x60))) - { - as_bad_where (fixP->fx_file, fixP->fx_line, - _("shift expression is too large")); - break; - } - - if (value == 0) - newval &= ~0x60; /* Shifts of zero must be done as lsl */ - else if (value == 32) - value = 0; - newval &= 0xfffff07f; - newval |= (value & 0x1f) << 7; - md_number_to_chars (buf, newval , INSN_SIZE); - break; - - case BFD_RELOC_ARM_SWI: - if (arm_data->thumb_mode) - { - if (((unsigned long) value) > 0xff) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("Invalid swi expression")); - newval = md_chars_to_number (buf, THUMB_SIZE) & 0xff00; - newval |= value; - md_number_to_chars (buf, newval, THUMB_SIZE); - } - else - { - if (((unsigned long) value) > 0x00ffffff) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("Invalid swi expression")); - newval = md_chars_to_number (buf, INSN_SIZE) & 0xff000000; - newval |= value; - md_number_to_chars (buf, newval , INSN_SIZE); - } - break; - - case BFD_RELOC_ARM_MULTI: - if (((unsigned long) value) > 0xffff) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("Invalid expression in load/store multiple")); - newval = value | md_chars_to_number (buf, INSN_SIZE); - md_number_to_chars (buf, newval, INSN_SIZE); - break; - - case BFD_RELOC_ARM_PCREL_BRANCH: - newval = md_chars_to_number (buf, INSN_SIZE); - - /* Sign-extend a 24-bit number. */ -#define SEXT24(x) ((((x) & 0xffffff) ^ (~ 0x7fffff)) + 0x800000) - -#ifdef OBJ_ELF - if (! target_oabi) - value = fixP->fx_offset; -#endif - - /* We are going to store value (shifted right by two) in the - instruction, in a 24 bit, signed field. Thus we need to check - that none of the top 8 bits of the shifted value (top 7 bits of - the unshifted, unsigned value) are set, or that they are all set. */ - if ((value & 0xfe000000UL) != 0 - && ((value & 0xfe000000UL) != 0xfe000000UL)) - { -#ifdef OBJ_ELF - /* Normally we would be stuck at this point, since we cannot store - the absolute address that is the destination of the branch in the - 24 bits of the branch instruction. If however, we happen to know - that the destination of the branch is in the same section as the - branch instruciton itself, then we can compute the relocation for - ourselves and not have to bother the linker with it. - - FIXME: The tests for OBJ_ELF and ! target_oabi are only here - because I have not worked out how to do this for OBJ_COFF or - target_oabi. */ - if (! target_oabi - && fixP->fx_addsy != NULL - && S_IS_DEFINED (fixP->fx_addsy) - && S_GET_SEGMENT (fixP->fx_addsy) == seg) - { - /* Get pc relative value to go into the branch. */ - value = * val; - - /* Permit a backward branch provided that enough bits are set. - Allow a forwards branch, provided that enough bits are clear. */ - if ((value & 0xfe000000UL) == 0xfe000000UL - || (value & 0xfe000000UL) == 0) - fixP->fx_done = 1; - } - - if (! fixP->fx_done) -#endif - as_bad_where (fixP->fx_file, fixP->fx_line, - _("gas can't handle same-section branch dest >= 0x04000000")); - } - - value >>= 2; - value += SEXT24 (newval); - - if ((value & 0xff000000UL) != 0 - && ((value & 0xff000000UL) != 0xff000000UL)) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("out of range branch")); - - newval = (value & 0x00ffffff) | (newval & 0xff000000); - md_number_to_chars (buf, newval, INSN_SIZE); - break; - - - case BFD_RELOC_THUMB_PCREL_BRANCH9: /* conditional branch */ - newval = md_chars_to_number (buf, THUMB_SIZE); - { - addressT diff = (newval & 0xff) << 1; - if (diff & 0x100) - diff |= ~0xff; - - value += diff; - if ((value & ~0xff) && ((value & ~0xff) != ~0xff)) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("Branch out of range")); - newval = (newval & 0xff00) | ((value & 0x1ff) >> 1); - } - md_number_to_chars (buf, newval, THUMB_SIZE); - break; - - case BFD_RELOC_THUMB_PCREL_BRANCH12: /* unconditional branch */ - newval = md_chars_to_number (buf, THUMB_SIZE); - { - addressT diff = (newval & 0x7ff) << 1; - if (diff & 0x800) - diff |= ~0x7ff; - - value += diff; - if ((value & ~0x7ff) && ((value & ~0x7ff) != ~0x7ff)) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("Branch out of range")); - newval = (newval & 0xf800) | ((value & 0xfff) >> 1); - } - md_number_to_chars (buf, newval, THUMB_SIZE); - break; - - case BFD_RELOC_THUMB_PCREL_BRANCH23: - { - offsetT newval2; - addressT diff; - - newval = md_chars_to_number (buf, THUMB_SIZE); - newval2 = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE); - diff = ((newval & 0x7ff) << 12) | ((newval2 & 0x7ff) << 1); - if (diff & 0x400000) - diff |= ~0x3fffff; -#ifdef OBJ_ELF - value = fixP->fx_offset; -#endif - value += diff; - if ((value & ~0x3fffff) && ((value & ~0x3fffff) != ~0x3fffff)) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("Branch with link out of range")); - - newval = (newval & 0xf800) | ((value & 0x7fffff) >> 12); - newval2 = (newval2 & 0xf800) | ((value & 0xfff) >> 1); - md_number_to_chars (buf, newval, THUMB_SIZE); - md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE); - } - break; - - case BFD_RELOC_8: - if (fixP->fx_done || fixP->fx_pcrel) - md_number_to_chars (buf, value, 1); -#ifdef OBJ_ELF - else if (!target_oabi) - { - value = fixP->fx_offset; - md_number_to_chars (buf, value, 1); - } -#endif - break; - - case BFD_RELOC_16: - if (fixP->fx_done || fixP->fx_pcrel) - md_number_to_chars (buf, value, 2); -#ifdef OBJ_ELF - else if (!target_oabi) - { - value = fixP->fx_offset; - md_number_to_chars (buf, value, 2); - } -#endif - break; - -#ifdef OBJ_ELF - case BFD_RELOC_ARM_GOT32: - case BFD_RELOC_ARM_GOTOFF: - md_number_to_chars (buf, 0, 4); - break; -#endif - - case BFD_RELOC_RVA: - case BFD_RELOC_32: - if (fixP->fx_done || fixP->fx_pcrel) - md_number_to_chars (buf, value, 4); -#ifdef OBJ_ELF - else if (!target_oabi) - { - value = fixP->fx_offset; - md_number_to_chars (buf, value, 4); - } -#endif - break; - -#ifdef OBJ_ELF - case BFD_RELOC_ARM_PLT32: - /* It appears the instruction is fully prepared at this point. */ - break; -#endif - - case BFD_RELOC_ARM_GOTPC: - md_number_to_chars (buf, value, 4); - break; - - case BFD_RELOC_ARM_CP_OFF_IMM: - sign = value >= 0; - if (value < -1023 || value > 1023 || (value & 3)) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("Illegal value for co-processor offset")); - if (value < 0) - value = -value; - newval = md_chars_to_number (buf, INSN_SIZE) & 0xff7fff00; - newval |= (value >> 2) | (sign ? INDEX_UP : 0); - md_number_to_chars (buf, newval , INSN_SIZE); - break; - - case BFD_RELOC_ARM_THUMB_OFFSET: - newval = md_chars_to_number (buf, THUMB_SIZE); - /* Exactly what ranges, and where the offset is inserted depends on - the type of instruction, we can establish this from the top 4 bits */ - switch (newval >> 12) - { - case 4: /* PC load */ - /* Thumb PC loads are somewhat odd, bit 1 of the PC is - forced to zero for these loads, so we will need to round - up the offset if the instruction address is not word - aligned (since the final address produced must be, and - we can only describe word-aligned immediate offsets). */ - - if ((fixP->fx_frag->fr_address + fixP->fx_where + value) & 3) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("Invalid offset, target not word aligned (0x%08X)"), - (unsigned int)(fixP->fx_frag->fr_address + fixP->fx_where + value)); - - if ((value + 2) & ~0x3fe) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("Invalid offset, value too big (0x%08X)"), value); - - /* Round up, since pc will be rounded down. */ - newval |= (value + 2) >> 2; - break; - - case 9: /* SP load/store */ - if (value & ~0x3fc) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("Invalid offset, value too big (0x%08X)"), value); - newval |= value >> 2; - break; - - case 6: /* Word load/store */ - if (value & ~0x7c) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("Invalid offset, value too big (0x%08X)"), value); - newval |= value << 4; /* 6 - 2 */ - break; - - case 7: /* Byte load/store */ - if (value & ~0x1f) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("Invalid offset, value too big (0x%08X)"), value); - newval |= value << 6; - break; - - case 8: /* Halfword load/store */ - if (value & ~0x3e) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("Invalid offset, value too big (0x%08X)"), value); - newval |= value << 5; /* 6 - 1 */ - break; - - default: - as_bad_where (fixP->fx_file, fixP->fx_line, - "Unable to process relocation for thumb opcode: %lx", - (unsigned long) newval); - break; - } - md_number_to_chars (buf, newval, THUMB_SIZE); - break; - - case BFD_RELOC_ARM_THUMB_ADD: - /* This is a complicated relocation, since we use it for all of - the following immediate relocations: - 3bit ADD/SUB - 8bit ADD/SUB - 9bit ADD/SUB SP word-aligned - 10bit ADD PC/SP word-aligned - - The type of instruction being processed is encoded in the - instruction field: - 0x8000 SUB - 0x00F0 Rd - 0x000F Rs - */ - newval = md_chars_to_number (buf, THUMB_SIZE); - { - int rd = (newval >> 4) & 0xf; - int rs = newval & 0xf; - int subtract = newval & 0x8000; - - if (rd == REG_SP) - { - if (value & ~0x1fc) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("Invalid immediate for stack address calculation")); - newval = subtract ? T_OPCODE_SUB_ST : T_OPCODE_ADD_ST; - newval |= value >> 2; - } - else if (rs == REG_PC || rs == REG_SP) - { - if (subtract || - value & ~0x3fc) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("Invalid immediate for address calculation (value = 0x%08lX)"), - (unsigned long) value); - newval = (rs == REG_PC ? T_OPCODE_ADD_PC : T_OPCODE_ADD_SP); - newval |= rd << 8; - newval |= value >> 2; - } - else if (rs == rd) - { - if (value & ~0xff) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("Invalid 8bit immediate")); - newval = subtract ? T_OPCODE_SUB_I8 : T_OPCODE_ADD_I8; - newval |= (rd << 8) | value; - } - else - { - if (value & ~0x7) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("Invalid 3bit immediate")); - newval = subtract ? T_OPCODE_SUB_I3 : T_OPCODE_ADD_I3; - newval |= rd | (rs << 3) | (value << 6); - } - } - md_number_to_chars (buf, newval , THUMB_SIZE); - break; - - case BFD_RELOC_ARM_THUMB_IMM: - newval = md_chars_to_number (buf, THUMB_SIZE); - switch (newval >> 11) - { - case 0x04: /* 8bit immediate MOV */ - case 0x05: /* 8bit immediate CMP */ - if (value < 0 || value > 255) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("Invalid immediate: %ld is too large"), - (long) value); - newval |= value; - break; - - default: - abort (); - } - md_number_to_chars (buf, newval , THUMB_SIZE); - break; - - case BFD_RELOC_ARM_THUMB_SHIFT: - /* 5bit shift value (0..31) */ - if (value < 0 || value > 31) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("Illegal Thumb shift value: %ld"), (long) value); - newval = md_chars_to_number (buf, THUMB_SIZE) & 0xf03f; - newval |= value << 6; - md_number_to_chars (buf, newval , THUMB_SIZE); - break; - - case BFD_RELOC_VTABLE_INHERIT: - case BFD_RELOC_VTABLE_ENTRY: - fixP->fx_done = 0; - return 1; - - case BFD_RELOC_NONE: - default: - as_bad_where (fixP->fx_file, fixP->fx_line, - _("Bad relocation fixup type (%d)"), fixP->fx_r_type); - } - - return 1; -} - -/* Translate internal representation of relocation info to BFD target - format. */ -arelent * -tc_gen_reloc (section, fixp) - asection * section ATTRIBUTE_UNUSED; - fixS * fixp; -{ - arelent * reloc; - bfd_reloc_code_real_type code; - - reloc = (arelent *) xmalloc (sizeof (arelent)); - - reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); - *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); - reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; - - /* @@ Why fx_addnumber sometimes and fx_offset other times? */ -#ifndef OBJ_ELF - if (fixp->fx_pcrel == 0) - reloc->addend = fixp->fx_offset; - else - reloc->addend = fixp->fx_offset = reloc->address; -#else /* OBJ_ELF */ - reloc->addend = fixp->fx_offset; -#endif - - switch (fixp->fx_r_type) - { - case BFD_RELOC_8: - if (fixp->fx_pcrel) - { - code = BFD_RELOC_8_PCREL; - break; - } - - case BFD_RELOC_16: - if (fixp->fx_pcrel) - { - code = BFD_RELOC_16_PCREL; - break; - } - - case BFD_RELOC_32: - if (fixp->fx_pcrel) - { - code = BFD_RELOC_32_PCREL; - break; - } - - case BFD_RELOC_ARM_PCREL_BRANCH: - case BFD_RELOC_RVA: - case BFD_RELOC_THUMB_PCREL_BRANCH9: - case BFD_RELOC_THUMB_PCREL_BRANCH12: - case BFD_RELOC_THUMB_PCREL_BRANCH23: - case BFD_RELOC_VTABLE_ENTRY: - case BFD_RELOC_VTABLE_INHERIT: - code = fixp->fx_r_type; - break; - - case BFD_RELOC_ARM_LITERAL: - case BFD_RELOC_ARM_HWLITERAL: - /* If this is called then the a literal has been referenced across - a section boundary - possibly due to an implicit dump */ - as_bad_where (fixp->fx_file, fixp->fx_line, - _("Literal referenced across section boundary (Implicit dump?)")); - return NULL; - -#ifdef OBJ_ELF - case BFD_RELOC_ARM_GOT32: - case BFD_RELOC_ARM_GOTOFF: - case BFD_RELOC_ARM_PLT32: - code = fixp->fx_r_type; - break; -#endif - - case BFD_RELOC_ARM_IMMEDIATE: - as_bad_where (fixp->fx_file, fixp->fx_line, - _("Internal_relocation (type %d) not fixed up (IMMEDIATE)"), - fixp->fx_r_type); - return NULL; - - case BFD_RELOC_ARM_ADRL_IMMEDIATE: - as_bad_where (fixp->fx_file, fixp->fx_line, - _("ADRL used for a symbol not defined in the same file"), - fixp->fx_r_type); - return NULL; - - case BFD_RELOC_ARM_OFFSET_IMM: - as_bad_where (fixp->fx_file, fixp->fx_line, - _("Internal_relocation (type %d) not fixed up (OFFSET_IMM)"), - fixp->fx_r_type); - return NULL; - - default: - { - char * type; - switch (fixp->fx_r_type) - { - case BFD_RELOC_ARM_IMMEDIATE: type = "IMMEDIATE"; break; - case BFD_RELOC_ARM_OFFSET_IMM: type = "OFFSET_IMM"; break; - case BFD_RELOC_ARM_OFFSET_IMM8: type = "OFFSET_IMM8"; break; - case BFD_RELOC_ARM_SHIFT_IMM: type = "SHIFT_IMM"; break; - case BFD_RELOC_ARM_SWI: type = "SWI"; break; - case BFD_RELOC_ARM_MULTI: type = "MULTI"; break; - case BFD_RELOC_ARM_CP_OFF_IMM: type = "CP_OFF_IMM"; break; - case BFD_RELOC_ARM_THUMB_ADD: type = "THUMB_ADD"; break; - case BFD_RELOC_ARM_THUMB_SHIFT: type = "THUMB_SHIFT"; break; - case BFD_RELOC_ARM_THUMB_IMM: type = "THUMB_IMM"; break; - case BFD_RELOC_ARM_THUMB_OFFSET: type = "THUMB_OFFSET"; break; - default: type = _("<unknown>"); break; - } - as_bad_where (fixp->fx_file, fixp->fx_line, - _("Can not represent %s relocation in this object file format (%d)"), - type, fixp->fx_pcrel); - return NULL; - } - } - -#ifdef OBJ_ELF - if (code == BFD_RELOC_32_PCREL - && GOT_symbol - && fixp->fx_addsy == GOT_symbol) - { - code = BFD_RELOC_ARM_GOTPC; - reloc->addend = fixp->fx_offset = reloc->address; - } -#endif - - reloc->howto = bfd_reloc_type_lookup (stdoutput, code); - - if (reloc->howto == NULL) - { - as_bad_where (fixp->fx_file, fixp->fx_line, - _("Can not represent %s relocation in this object file format"), - bfd_get_reloc_code_name (code)); - return NULL; - } - - /* HACK: Since arm ELF uses Rel instead of Rela, encode the - vtable entry to be used in the relocation's section offset. */ - if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY) - reloc->address = fixp->fx_offset; - - return reloc; -} - -int -md_estimate_size_before_relax (fragP, segtype) - fragS * fragP ATTRIBUTE_UNUSED; - segT segtype ATTRIBUTE_UNUSED; -{ - as_fatal (_("md_estimate_size_before_relax\n")); - return 1; -} - -static void -output_inst PARAMS ((void)) -{ - char * to = NULL; - - if (inst.error) - { - as_bad (inst.error); - return; - } - - to = frag_more (inst.size); - - if (thumb_mode && (inst.size > THUMB_SIZE)) - { - assert (inst.size == (2 * THUMB_SIZE)); - md_number_to_chars (to, inst.instruction >> 16, THUMB_SIZE); - md_number_to_chars (to + THUMB_SIZE, inst.instruction, THUMB_SIZE); - } - else if (inst.size > INSN_SIZE) - { - assert (inst.size == (2 * INSN_SIZE)); - md_number_to_chars (to, inst.instruction, INSN_SIZE); - md_number_to_chars (to + INSN_SIZE, inst.instruction, INSN_SIZE); - } - else - md_number_to_chars (to, inst.instruction, inst.size); - - if (inst.reloc.type != BFD_RELOC_NONE) - fix_new_arm (frag_now, to - frag_now->fr_literal, - inst.size, & inst.reloc.exp, inst.reloc.pc_rel, - inst.reloc.type); - - return; -} - -void -md_assemble (str) - char * str; -{ - char c; - char * p; - char * q; - char * start; - - /* Align the instruction. - This may not be the right thing to do but ... */ - /* arm_align (2, 0); */ - listing_prev_line (); /* Defined in listing.h */ - - /* Align the previous label if needed. */ - if (last_label_seen != NULL) - { - symbol_set_frag (last_label_seen, frag_now); - S_SET_VALUE (last_label_seen, (valueT) frag_now_fix ()); - S_SET_SEGMENT (last_label_seen, now_seg); - } - - memset (&inst, '\0', sizeof (inst)); - inst.reloc.type = BFD_RELOC_NONE; - - skip_whitespace (str); - - /* Scan up to the end of the op-code, which must end in white space or - end of string. */ - for (start = p = str; *p != '\0'; p++) - if (*p == ' ') - break; - - if (p == str) - { - as_bad (_("No operator -- statement `%s'\n"), str); - return; - } - - if (thumb_mode) - { - CONST struct thumb_opcode * opcode; - - c = *p; - *p = '\0'; - opcode = (CONST struct thumb_opcode *) hash_find (arm_tops_hsh, str); - *p = c; - - if (opcode) - { - /* Check that this instruction is supported for this CPU. */ - if (thumb_mode == 1 && (opcode->variants & cpu_variant) == 0) - { - as_bad (_("selected processor does not support this opcode")); - return; - } - - inst.instruction = opcode->value; - inst.size = opcode->size; - (*opcode->parms)(p); - output_inst (); - return; - } - } - else - { - CONST struct asm_opcode * opcode; - unsigned long cond_code; - - inst.size = INSN_SIZE; - /* p now points to the end of the opcode, probably white space, but we - have to break the opcode up in case it contains condionals and flags; - keep trying with progressively smaller basic instructions until one - matches, or we run out of opcode. */ - q = (p - str > LONGEST_INST) ? str + LONGEST_INST : p; - for (; q != str; q--) - { - c = *q; - *q = '\0'; - opcode = (CONST struct asm_opcode *) hash_find (arm_ops_hsh, str); - *q = c; - - if (opcode && opcode->template) - { - unsigned long flag_bits = 0; - char * r; - - /* Check that this instruction is supported for this CPU. */ - if ((opcode->variants & cpu_variant) == 0) - goto try_shorter; - - inst.instruction = opcode->value; - if (q == p) /* Just a simple opcode. */ - { - if (opcode->comp_suffix) - { - if (*opcode->comp_suffix != '\0') - as_bad (_("Opcode `%s' must have suffix from list: <%s>"), - str, opcode->comp_suffix); - else - /* Not a conditional instruction. */ - (*opcode->parms)(q, 0); - } - else - { - /* A conditional instruction with default condition. */ - inst.instruction |= COND_ALWAYS; - (*opcode->parms)(q, 0); - } - output_inst (); - return; - } - - /* Not just a simple opcode. Check if extra is a conditional. */ - r = q; - if (p - r >= 2) - { - CONST struct asm_cond *cond; - char d = *(r + 2); - - *(r + 2) = '\0'; - cond = (CONST struct asm_cond *) hash_find (arm_cond_hsh, r); - *(r + 2) = d; - if (cond) - { - if (cond->value == 0xf0000000) - as_tsktsk ( -_("Warning: Use of the 'nv' conditional is deprecated\n")); - - cond_code = cond->value; - r += 2; - } - else - cond_code = COND_ALWAYS; - } - else - cond_code = COND_ALWAYS; - - /* Apply the conditional, or complain it's not allowed. */ - if (opcode->comp_suffix && *opcode->comp_suffix == '\0') - { - /* Instruction isn't conditional */ - if (cond_code != COND_ALWAYS) - { - as_bad (_("Opcode `%s' is unconditional\n"), str); - return; - } - } - else - /* Instruction is conditional: set the condition into it. */ - inst.instruction |= cond_code; - - - /* If there is a compulsory suffix, it should come here, before - any optional flags. */ - if (opcode->comp_suffix && *opcode->comp_suffix != '\0') - { - CONST char *s = opcode->comp_suffix; - - while (*s) - { - inst.suffix++; - if (*r == *s) - break; - s++; - } - - if (*s == '\0') - { - as_bad (_("Opcode `%s' must have suffix from <%s>\n"), str, - opcode->comp_suffix); - return; - } - - r++; - } - - /* The remainder, if any should now be flags for the instruction; - Scan these checking each one found with the opcode. */ - if (r != p) - { - char d; - CONST struct asm_flg *flag = opcode->flags; - - if (flag) - { - int flagno; - - d = *p; - *p = '\0'; - - for (flagno = 0; flag[flagno].template; flagno++) - { - if (streq (r, flag[flagno].template)) - { - flag_bits |= flag[flagno].set_bits; - break; - } - } - - *p = d; - if (! flag[flagno].template) - goto try_shorter; - } - else - goto try_shorter; - } - - (*opcode->parms) (p, flag_bits); - output_inst (); - return; - } - - try_shorter: - ; - } - } - - /* It wasn't an instruction, but it might be a register alias of the form - alias .req reg */ - q = p; - skip_whitespace (q); - - c = *p; - *p = '\0'; - - if (*q && !strncmp (q, ".req ", 4)) - { - int reg; - char * copy_of_str = str; - char * r; - - q += 4; - skip_whitespace (q); - - for (r = q; *r != '\0'; r++) - if (*r == ' ') - break; - - if (r != q) - { - int regnum; - char d = *r; - - *r = '\0'; - regnum = arm_reg_parse (& q); - *r = d; - - reg = arm_reg_parse (& str); - - if (reg == FAIL) - { - if (regnum != FAIL) - insert_reg_alias (str, regnum); - else - as_warn (_("register '%s' does not exist\n"), q); - } - else if (regnum != FAIL) - { - if (reg != regnum) - as_warn (_("ignoring redefinition of register alias '%s'"), - copy_of_str ); - - /* Do not warn about redefinitions to the same alias. */ - } - else - as_warn (_("ignoring redefinition of register alias '%s' to non-existant register '%s'"), - copy_of_str, q); - } - else - as_warn (_("ignoring incomplete .req pseuso op")); - - *p = c; - return; - } - - *p = c; - as_bad (_("bad instruction `%s'"), start); -} - -/* - * md_parse_option - * Invocation line includes a switch not recognized by the base assembler. - * See if it's a processor-specific option. These are: - * Cpu variants, the arm part is optional: - * -m[arm]1 Currently not supported. - * -m[arm]2, -m[arm]250 Arm 2 and Arm 250 processor - * -m[arm]3 Arm 3 processor - * -m[arm]6[xx], Arm 6 processors - * -m[arm]7[xx][t][[d]m] Arm 7 processors - * -m[arm]8[10] Arm 8 processors - * -m[arm]9[20][tdmi] Arm 9 processors - * -mstrongarm[110[0]] StrongARM processors - * -m[arm]v[2345] Arm architectures - * -mall All (except the ARM1) - * FP variants: - * -mfpa10, -mfpa11 FPA10 and 11 co-processor instructions - * -mfpe-old (No float load/store multiples) - * -mno-fpu Disable all floating point instructions - * Run-time endian selection: - * -EB big endian cpu - * -EL little endian cpu - * ARM Procedure Calling Standard: - * -mapcs-32 32 bit APCS - * -mapcs-26 26 bit APCS - * -mapcs-float Pass floats in float regs - * -mapcs-reentrant Position independent code - * -mthumb-interwork Code supports Arm/Thumb interworking - * -moabi Old ELF ABI - */ - -CONST char * md_shortopts = "m:k"; -struct option md_longopts[] = -{ -#ifdef ARM_BI_ENDIAN -#define OPTION_EB (OPTION_MD_BASE + 0) - {"EB", no_argument, NULL, OPTION_EB}, -#define OPTION_EL (OPTION_MD_BASE + 1) - {"EL", no_argument, NULL, OPTION_EL}, -#ifdef OBJ_ELF -#define OPTION_OABI (OPTION_MD_BASE +2) - {"oabi", no_argument, NULL, OPTION_OABI}, -#endif -#endif - {NULL, no_argument, NULL, 0} -}; -size_t md_longopts_size = sizeof (md_longopts); - -int -md_parse_option (c, arg) - int c; - char * arg; -{ - char * str = arg; - - switch (c) - { -#ifdef ARM_BI_ENDIAN - case OPTION_EB: - target_big_endian = 1; - break; - case OPTION_EL: - target_big_endian = 0; - break; -#endif - - case 'm': - switch (*str) - { - case 'f': - if (streq (str, "fpa10")) - cpu_variant = (cpu_variant & ~FPU_ALL) | FPU_FPA10; - else if (streq (str, "fpa11")) - cpu_variant = (cpu_variant & ~FPU_ALL) | FPU_FPA11; - else if (streq (str, "fpe-old")) - cpu_variant = (cpu_variant & ~FPU_ALL) | FPU_CORE; - else - goto bad; - break; - - case 'n': - if (streq (str, "no-fpu")) - cpu_variant &= ~FPU_ALL; - break; - -#ifdef OBJ_ELF - case 'o': - if (streq (str, "oabi")) - target_oabi = true; - break; -#endif - - case 't': - /* Limit assembler to generating only Thumb instructions: */ - if (streq (str, "thumb")) - { - cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_THUMB; - cpu_variant = (cpu_variant & ~FPU_ALL) | FPU_NONE; - thumb_mode = 1; - } - else if (streq (str, "thumb-interwork")) - { - if ((cpu_variant & ARM_THUMB) == 0) - cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_ARCH_V4T; -#if defined OBJ_COFF || defined OBJ_ELF - support_interwork = true; -#endif - } - else - goto bad; - break; - - default: - if (streq (str, "all")) - { - cpu_variant = ARM_ALL | FPU_ALL; - return 1; - } -#if defined OBJ_COFF || defined OBJ_ELF - if (! strncmp (str, "apcs-", 5)) - { - /* GCC passes on all command line options starting "-mapcs-..." - to us, so we must parse them here. */ - - str += 5; - - if (streq (str, "32")) - { - uses_apcs_26 = false; - return 1; - } - else if (streq (str, "26")) - { - uses_apcs_26 = true; - return 1; - } - else if (streq (str, "frame")) - { - /* Stack frames are being generated - does not affect - linkage of code. */ - return 1; - } - else if (streq (str, "stack-check")) - { - /* Stack checking is being performed - does not affect - linkage, but does require that the functions - __rt_stkovf_split_small and __rt_stkovf_split_big be - present in the final link. */ - - return 1; - } - else if (streq (str, "float")) - { - /* Floating point arguments are being passed in the floating - point registers. This does affect linking, since this - version of the APCS is incompatible with the version that - passes floating points in the integer registers. */ - - uses_apcs_float = true; - return 1; - } - else if (streq (str, "reentrant")) - { - /* Reentrant code has been generated. This does affect - linking, since there is no point in linking reentrant/ - position independent code with absolute position code. */ - pic_code = true; - return 1; - } - - as_bad (_("Unrecognised APCS switch -m%s"), arg); - return 0; - } -#endif - /* Strip off optional "arm" */ - if (! strncmp (str, "arm", 3)) - str += 3; - - switch (*str) - { - case '1': - if (streq (str, "1")) - cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_1; - else - goto bad; - break; - - case '2': - if (streq (str, "2")) - cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_2; - else if (streq (str, "250")) - cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_250; - else - goto bad; - break; - - case '3': - if (streq (str, "3")) - cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_3; - else - goto bad; - break; - - case '6': - switch (strtol (str, NULL, 10)) - { - case 6: - case 60: - case 600: - case 610: - case 620: - cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_6; - break; - default: - goto bad; - } - break; - - case '7': - switch (strtol (str, & str, 10)) /* Eat the processor name */ - { - case 7: - case 70: - case 700: - case 710: - case 720: - case 7100: - case 7500: - break; - default: - goto bad; - } - cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_7; - for (; *str; str++) - { - switch (* str) - { - case 't': - cpu_variant |= (ARM_THUMB | ARM_ARCH_V4); - break; - - case 'm': - cpu_variant |= ARM_LONGMUL; - break; - - case 'f': /* fe => fp enabled cpu. */ - if (str[1] == 'e') - ++ str; - else - goto bad; - - case 'c': /* Left over from 710c processor name. */ - case 'd': /* Debug */ - case 'i': /* Embedded ICE */ - /* Included for completeness in ARM processor naming. */ - break; - - default: - goto bad; - } - } - break; - - case '8': - if (streq (str, "8") || streq (str, "810")) - cpu_variant = (cpu_variant & ~ARM_ANY) - | ARM_8 | ARM_ARCH_V4 | ARM_LONGMUL; - else - goto bad; - break; - - case '9': - if (streq (str, "9")) - cpu_variant = (cpu_variant & ~ARM_ANY) - | ARM_9 | ARM_ARCH_V4 | ARM_LONGMUL | ARM_THUMB; - else if (streq (str, "920")) - cpu_variant = (cpu_variant & ~ARM_ANY) - | ARM_9 | ARM_ARCH_V4 | ARM_LONGMUL; - else if (streq (str, "920t")) - cpu_variant = (cpu_variant & ~ARM_ANY) - | ARM_9 | ARM_ARCH_V4 | ARM_LONGMUL | ARM_THUMB; - else if (streq (str, "9tdmi")) - cpu_variant = (cpu_variant & ~ARM_ANY) - | ARM_9 | ARM_ARCH_V4 | ARM_LONGMUL | ARM_THUMB; - else - goto bad; - break; - - - case 's': - if (streq (str, "strongarm") - || streq (str, "strongarm110") - || streq (str, "strongarm1100")) - cpu_variant = (cpu_variant & ~ARM_ANY) - | ARM_8 | ARM_ARCH_V4 | ARM_LONGMUL; - else - goto bad; - break; - - case 'v': - /* Select variant based on architecture rather than processor. */ - switch (*++str) - { - case '2': - switch (*++str) - { - case 'a': - cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_3; - break; - case 0: - cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_2; - break; - default: - as_bad (_("Invalid architecture variant -m%s"), arg); - break; - } - break; - - case '3': - cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_7; - - switch (*++str) - { - case 'm': cpu_variant |= ARM_LONGMUL; break; - case 0: break; - default: - as_bad (_("Invalid architecture variant -m%s"), arg); - break; - } - break; - - case '4': - cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_ARCH_V4; - - switch (*++str) - { - case 't': cpu_variant |= ARM_THUMB; break; - case 0: break; - default: - as_bad (_("Invalid architecture variant -m%s"), arg); - break; - } - break; - - case '5': - cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_ARCH_V5; - switch (*++str) - { - case 't': cpu_variant |= ARM_THUMB; break; - case 'e': cpu_variant |= ARM_EXT_V5E; break; - case 0: break; - default: - as_bad (_("Invalid architecture variant -m%s"), arg); - break; - } - break; - - default: - as_bad (_("Invalid architecture variant -m%s"), arg); - break; - } - break; - - default: - bad: - as_bad (_("Invalid processor variant -m%s"), arg); - return 0; - } - } - break; - -#if defined OBJ_ELF || defined OBJ_COFF - case 'k': - pic_code = 1; - break; -#endif - - default: - return 0; - } - - return 1; -} - -void -md_show_usage (fp) - FILE * fp; -{ - fprintf (fp, _("\ - ARM Specific Assembler Options:\n\ - -m[arm][<processor name>] select processor variant\n\ - -m[arm]v[2|2a|3|3m|4|4t|5[t][e]] select architecture variant\n\ - -mthumb only allow Thumb instructions\n\ - -mthumb-interwork mark the assembled code as supporting interworking\n\ - -mall allow any instruction\n\ - -mfpa10, -mfpa11 select floating point architecture\n\ - -mfpe-old don't allow floating-point multiple instructions\n\ - -mno-fpu don't allow any floating-point instructions.\n\ - -k generate PIC code.\n")); -#if defined OBJ_COFF || defined OBJ_ELF - fprintf (fp, _("\ - -mapcs-32, -mapcs-26 specify which ARM Procedure Calling Standard to use\n\ - -mapcs-float floating point args are passed in FP regs\n\ - -mapcs-reentrant the code is position independent/reentrant\n")); - #endif -#ifdef OBJ_ELF - fprintf (fp, _("\ - -moabi support the old ELF ABI\n")); -#endif -#ifdef ARM_BI_ENDIAN - fprintf (fp, _("\ - -EB assemble code for a big endian cpu\n\ - -EL assemble code for a little endian cpu\n")); -#endif -} - -/* We need to be able to fix up arbitrary expressions in some statements. - This is so that we can handle symbols that are an arbitrary distance from - the pc. The most common cases are of the form ((+/-sym -/+ . - 8) & mask), - which returns part of an address in a form which will be valid for - a data instruction. We do this by pushing the expression into a symbol - in the expr_section, and creating a fix for that. */ - -static void -fix_new_arm (frag, where, size, exp, pc_rel, reloc) - fragS * frag; - int where; - short int size; - expressionS * exp; - int pc_rel; - int reloc; -{ - fixS * new_fix; - arm_fix_data * arm_data; - - switch (exp->X_op) - { - case O_constant: - case O_symbol: - case O_add: - case O_subtract: - new_fix = fix_new_exp (frag, where, size, exp, pc_rel, reloc); - break; - - default: - new_fix = fix_new (frag, where, size, make_expr_symbol (exp), 0, - pc_rel, reloc); - break; - } - - /* Mark whether the fix is to a THUMB instruction, or an ARM instruction */ - arm_data = (arm_fix_data *) obstack_alloc (& notes, sizeof (arm_fix_data)); - new_fix->tc_fix_data = (PTR) arm_data; - arm_data->thumb_mode = thumb_mode; - - return; -} - - -/* This fix_new is called by cons via TC_CONS_FIX_NEW. */ -void -cons_fix_new_arm (frag, where, size, exp) - fragS * frag; - int where; - int size; - expressionS * exp; -{ - bfd_reloc_code_real_type type; - int pcrel = 0; - - /* Pick a reloc ... - * - * @@ Should look at CPU word size. - */ - switch (size) - { - case 2: - type = BFD_RELOC_16; - break; - case 4: - default: - type = BFD_RELOC_32; - break; - case 8: - type = BFD_RELOC_64; - break; - } - - fix_new_exp (frag, where, (int) size, exp, pcrel, type); -} - -/* A good place to do this, although this was probably not intended - for this kind of use. We need to dump the literal pool before - references are made to a null symbol pointer. */ -void -arm_cleanup () -{ - if (current_poolP == NULL) - return; - - subseg_set (text_section, 0); /* Put it at the end of text section. */ - s_ltorg (0); - listing_prev_line (); -} - -void -arm_start_line_hook () -{ - last_label_seen = NULL; -} - -void -arm_frob_label (sym) - symbolS * sym; -{ - last_label_seen = sym; - - ARM_SET_THUMB (sym, thumb_mode); - -#if defined OBJ_COFF || defined OBJ_ELF - ARM_SET_INTERWORK (sym, support_interwork); -#endif - - if (label_is_thumb_function_name) - { - /* When the address of a Thumb function is taken the bottom - bit of that address should be set. This will allow - interworking between Arm and Thumb functions to work - correctly. */ - - THUMB_SET_FUNC (sym, 1); - - label_is_thumb_function_name = false; - } -} - -/* Adjust the symbol table. This marks Thumb symbols as distinct from - ARM ones. */ - -void -arm_adjust_symtab () -{ -#ifdef OBJ_COFF - symbolS * sym; - - for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym)) - { - if (ARM_IS_THUMB (sym)) - { - if (THUMB_IS_FUNC (sym)) - { - /* Mark the symbol as a Thumb function. */ - if ( S_GET_STORAGE_CLASS (sym) == C_STAT - || S_GET_STORAGE_CLASS (sym) == C_LABEL) /* This can happen! */ - S_SET_STORAGE_CLASS (sym, C_THUMBSTATFUNC); - - else if (S_GET_STORAGE_CLASS (sym) == C_EXT) - S_SET_STORAGE_CLASS (sym, C_THUMBEXTFUNC); - else - as_bad (_("%s: unexpected function type: %d"), - S_GET_NAME (sym), S_GET_STORAGE_CLASS (sym)); - } - else switch (S_GET_STORAGE_CLASS (sym)) - { - case C_EXT: - S_SET_STORAGE_CLASS (sym, C_THUMBEXT); - break; - case C_STAT: - S_SET_STORAGE_CLASS (sym, C_THUMBSTAT); - break; - case C_LABEL: - S_SET_STORAGE_CLASS (sym, C_THUMBLABEL); - break; - default: /* do nothing */ - break; - } - } - - if (ARM_IS_INTERWORK (sym)) - coffsymbol (symbol_get_bfdsym (sym))->native->u.syment.n_flags = 0xFF; - } -#endif -#ifdef OBJ_ELF - symbolS * sym; - char bind; - - for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym)) - { - if (ARM_IS_THUMB (sym)) - { - elf_symbol_type * elf_sym; - - elf_sym = elf_symbol (symbol_get_bfdsym (sym)); - bind = ELF_ST_BIND (elf_sym); - - /* If it's a .thumb_func, declare it as so, - otherwise tag label as .code 16. */ - if (THUMB_IS_FUNC (sym)) - elf_sym->internal_elf_sym.st_info = - ELF_ST_INFO (bind, STT_ARM_TFUNC); - else - elf_sym->internal_elf_sym.st_info = - ELF_ST_INFO (bind, STT_ARM_16BIT); - } - } -#endif -} - -int -arm_data_in_code () -{ - if (thumb_mode && ! strncmp (input_line_pointer + 1, "data:", 5)) - { - *input_line_pointer = '/'; - input_line_pointer += 5; - *input_line_pointer = 0; - return 1; - } - - return 0; -} - -char * -arm_canonicalize_symbol_name (name) - char * name; -{ - int len; - - if (thumb_mode && (len = strlen (name)) > 5 - && streq (name + len - 5, "/data")) - *(name + len - 5) = 0; - - return name; -} - -boolean -arm_validate_fix (fixP) - fixS * fixP; -{ - /* If the destination of the branch is a defined symbol which does not have - the THUMB_FUNC attribute, then we must be calling a function which has - the (interfacearm) attribute. We look for the Thumb entry point to that - function and change the branch to refer to that function instead. */ - if ( fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BRANCH23 - && fixP->fx_addsy != NULL - && S_IS_DEFINED (fixP->fx_addsy) - && ! THUMB_IS_FUNC (fixP->fx_addsy)) - { - fixP->fx_addsy = find_real_start (fixP->fx_addsy); - return true; - } - - return false; -} - -#ifdef OBJ_ELF -/* Relocations against Thumb function names must be left unadjusted, - so that the linker can use this information to correctly set the - bottom bit of their addresses. The MIPS version of this function - also prevents relocations that are mips-16 specific, but I do not - know why it does this. - - FIXME: - There is one other problem that ought to be addressed here, but - which currently is not: Taking the address of a label (rather - than a function) and then later jumping to that address. Such - addresses also ought to have their bottom bit set (assuming that - they reside in Thumb code), but at the moment they will not. */ - -boolean -arm_fix_adjustable (fixP) - fixS * fixP; -{ - if (fixP->fx_addsy == NULL) - return 1; - - /* Prevent all adjustments to global symbols. */ - if (S_IS_EXTERN (fixP->fx_addsy)) - return 0; - - if (S_IS_WEAK (fixP->fx_addsy)) - return 0; - - if (THUMB_IS_FUNC (fixP->fx_addsy) - && fixP->fx_subsy == NULL) - return 0; - - /* We need the symbol name for the VTABLE entries */ - if ( fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT - || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY) - return 0; - - return 1; -} - -const char * -elf32_arm_target_format () -{ - if (target_big_endian) - if (target_oabi) - return "elf32-bigarm-oabi"; - else - return "elf32-bigarm"; - else - if (target_oabi) - return "elf32-littlearm-oabi"; - else - return "elf32-littlearm"; -} - -void -armelf_frob_symbol (symp, puntp) - symbolS * symp; - int * puntp; -{ - elf_frob_symbol (symp, puntp); -} - -int -arm_force_relocation (fixp) - struct fix * fixp; -{ - if ( fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT - || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY - || fixp->fx_r_type == BFD_RELOC_ARM_PCREL_BRANCH - || fixp->fx_r_type == BFD_RELOC_THUMB_PCREL_BRANCH23) - return 1; - - return 0; -} - -static bfd_reloc_code_real_type -arm_parse_reloc () -{ - char id[16]; - char * ip; - unsigned int i; - static struct - { - char * str; - int len; - bfd_reloc_code_real_type reloc; - } - reloc_map[] = - { -#define MAP(str,reloc) { str, sizeof (str)-1, reloc } - MAP ("(got)", BFD_RELOC_ARM_GOT32), - MAP ("(gotoff)", BFD_RELOC_ARM_GOTOFF), - /* ScottB: Jan 30, 1998 */ - /* Added support for parsing "var(PLT)" branch instructions */ - /* generated by GCC for PLT relocs */ - MAP ("(plt)", BFD_RELOC_ARM_PLT32), - { NULL, 0, BFD_RELOC_UNUSED } -#undef MAP - }; - - for (i = 0, ip = input_line_pointer; - i < sizeof (id) && (isalnum (*ip) || ispunct (*ip)); - i++, ip++) - id[i] = tolower (*ip); - - for (i = 0; reloc_map[i].str; i++) - if (strncmp (id, reloc_map[i].str, reloc_map[i].len) == 0) - break; - - input_line_pointer += reloc_map[i].len; - - return reloc_map[i].reloc; -} - -static void -s_arm_elf_cons (nbytes) - int nbytes; -{ - expressionS exp; - -#ifdef md_flush_pending_output - md_flush_pending_output (); -#endif - - if (is_it_end_of_statement ()) - { - demand_empty_rest_of_line (); - return; - } - -#ifdef md_cons_align - md_cons_align (nbytes); -#endif - - do - { - bfd_reloc_code_real_type reloc; - - expression (& exp); - - if (exp.X_op == O_symbol - && * input_line_pointer == '(' - && (reloc = arm_parse_reloc()) != BFD_RELOC_UNUSED) - { - reloc_howto_type * howto = bfd_reloc_type_lookup (stdoutput, reloc); - int size = bfd_get_reloc_size (howto); - - if (size > nbytes) - as_bad ("%s relocations do not fit in %d bytes", - howto->name, nbytes); - else - { - register char * p = frag_more ((int) nbytes); - int offset = nbytes - size; - - fix_new_exp (frag_now, p - frag_now->fr_literal + offset, size, - & exp, 0, reloc); - } - } - else - emit_expr (& exp, (unsigned int) nbytes); - } - while (*input_line_pointer++ == ','); - - input_line_pointer--; /* Put terminator back into stream. */ - demand_empty_rest_of_line (); -} - -#endif /* OBJ_ELF */ diff --git a/contrib/binutils/gas/config/tc-arm.h b/contrib/binutils/gas/config/tc-arm.h deleted file mode 100644 index c5ab887051256..0000000000000 --- a/contrib/binutils/gas/config/tc-arm.h +++ /dev/null @@ -1,211 +0,0 @@ -/* This file is tc-arm.h - Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999 - Free Software Foundation, Inc. - Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org) - Modified by David Taylor (dtaylor@armltd.co.uk) - - 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. */ - -#define TC_ARM 1 - -#ifndef TARGET_BYTES_BIG_ENDIAN -#define TARGET_BYTES_BIG_ENDIAN 0 -#endif - -#define WORKING_DOT_WORD - -#define COFF_MAGIC ARMMAGIC -#define TARGET_ARCH bfd_arch_arm - -#define AOUT_MACHTYPE 0 - -#define DIFF_EXPR_OK - -#ifdef LITTLE_ENDIAN -#undef LITTLE_ENDIAN -#endif - -#ifdef BIG_ENDIAN -#undef BIG_ENDIAN -#endif - -#define LITTLE_ENDIAN 1234 -#define BIG_ENDIAN 4321 - -#if defined OBJ_AOUT -#if defined TE_RISCIX -# define TARGET_FORMAT "a.out-riscix" -#elif defined TE_LINUX -# define ARM_BI_ENDIAN -# define TARGET_FORMAT "a.out-arm-linux" -#elif defined TE_NetBSD -# define TARGET_FORMAT "a.out-arm-netbsd" -#else -# define ARM_BI_ENDIAN -# define TARGET_FORMAT \ - (target_big_endian ? "a.out-arm-big" : "a.out-arm-little") -#endif -#endif /* OBJ_AOUT */ - -#ifdef OBJ_AIF -#define TARGET_FORMAT "aif" -#endif - -#if defined OBJ_COFF || defined OBJ_ELF -# define ARM_BI_ENDIAN - -# define TC_VALIDATE_FIX(fixP, segType, Label) \ - if (arm_validate_fix (fixP)) add_symbolP = fixP->fx_addsy - extern boolean arm_validate_fix PARAMS ((struct fix *)); -#endif - -#ifdef OBJ_COFF -# if defined TE_PE -# define TC_FORCE_RELOCATION(x) ((x)->fx_r_type == BFD_RELOC_RVA) -# ifdef TE_EPOC -# define TARGET_FORMAT (target_big_endian ? "epoc-pe-arm-big" : "epoc-pe-arm-little") -# else -# define TARGET_FORMAT (target_big_endian ? "pe-arm-big" : "pe-arm-little") -# endif -# else -# define TARGET_FORMAT (target_big_endian ? "coff-arm-big" : "coff-arm-little") -# endif -#endif - -#ifdef OBJ_ELF -# define TARGET_FORMAT elf32_arm_target_format() - extern const char * elf32_arm_target_format PARAMS ((void)); - -# define TC_FORCE_RELOCATION(fixp) arm_force_relocation (fixp) - extern int arm_force_relocation PARAMS ((struct fix *)); -#endif - -#define md_convert_frag(b, s, f) {as_fatal (_("arm convert_frag\n"));} - -#define md_cleanup() arm_cleanup () - extern void arm_cleanup PARAMS ((void)); - -#define md_start_line_hook() arm_start_line_hook () - extern void arm_start_line_hook PARAMS ((void)); - -#define tc_frob_label(S) arm_frob_label (S) - extern void arm_frob_label PARAMS ((symbolS *)); - -/* We also need to mark assembler created symbols: */ -#define tc_frob_fake_label(S) arm_frob_label (S) - -/* NOTE: The fake label creation in stabs.c:s_stab_generic() has - deliberately not been updated to mark assembler created stabs - symbols as Thumb. */ - -#define TC_FIX_TYPE PTR -#define TC_INIT_FIX_DATA(FIXP) ((FIXP)->tc_fix_data = NULL) - -#ifdef OBJ_ELF -#include "write.h" /* For definition of fixS */ -#define obj_fix_adjustable(fixP) arm_fix_adjustable (fixP) -boolean arm_fix_adjustable PARAMS ((fixS *)); -#else -#define obj_fix_adjustable(fixP) 0 -#endif - -/* We need to keep some local information on symbols. */ - -#define TC_SYMFIELD_TYPE unsigned int -#define ARM_GET_FLAG(s) (*symbol_get_tc (s)) -#define ARM_SET_FLAG(s,v) (*symbol_get_tc (s) |= (v)) -#define ARM_RESET_FLAG(s,v) (*symbol_get_tc (s) &= ~(v)) - -#define ARM_FLAG_THUMB (1 << 0) /* The symbol is a Thumb symbol rather than an Arm symbol. */ -#define ARM_FLAG_INTERWORK (1 << 1) /* The symbol is attached to code that suppports interworking. */ -#define THUMB_FLAG_FUNC (1 << 2) /* The symbol is attached to the start of a Thumb function. */ - -#define ARM_IS_THUMB(s) (ARM_GET_FLAG (s) & ARM_FLAG_THUMB) -#define ARM_IS_INTERWORK(s) (ARM_GET_FLAG (s) & ARM_FLAG_INTERWORK) -#define THUMB_IS_FUNC(s) (ARM_GET_FLAG (s) & THUMB_FLAG_FUNC) - -#define ARM_SET_THUMB(s,t) ((t) ? ARM_SET_FLAG (s, ARM_FLAG_THUMB) : ARM_RESET_FLAG (s, ARM_FLAG_THUMB)) -#define ARM_SET_INTERWORK(s,t) ((t) ? ARM_SET_FLAG (s, ARM_FLAG_INTERWORK) : ARM_RESET_FLAG (s, ARM_FLAG_INTERWORK)) -#define THUMB_SET_FUNC(s,t) ((t) ? ARM_SET_FLAG (s, THUMB_FLAG_FUNC) : ARM_RESET_FLAG (s, THUMB_FLAG_FUNC)) - - -#define TC_START_LABEL(C,STR) \ - (c == ':' || (c == '/' && arm_data_in_code ())) -int arm_data_in_code PARAMS ((void)); - -#define tc_canonicalize_symbol_name(str) \ - arm_canonicalize_symbol_name (str); -char * arm_canonicalize_symbol_name PARAMS ((char *)); - -#define obj_adjust_symtab() arm_adjust_symtab () - extern void arm_adjust_symtab PARAMS ((void)); - -#ifdef OBJ_ELF -#define obj_frob_symbol(sym, punt) armelf_frob_symbol ((sym), & (punt)) -void armelf_frob_symbol PARAMS ((symbolS *, int *)); -#endif - -#define tc_aout_pre_write_hook(x) {;} /* not used */ - -#define LISTING_HEADER "ARM GAS " - -#define OPTIONAL_REGISTER_PREFIX '%' - -#define md_operand(x) - -#define TC_HANDLES_FX_DONE - -#define MD_APPLY_FIX3 - -#define LOCAL_LABEL(name) (name[0] == '.' && (name[1] == 'L')) -#define LOCAL_LABELS_FB 1 -#ifdef OBJ_ELF -#define LOCAL_LABEL_PREFIX '.' -#endif - -/* 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. - This is only used for pcrel relocations, so GOTOFF does not need to be - checked here. I am not sure if some of the others are ever used with - pcrel, but it is easier to be safe than sorry. */ - -#define TC_RELOC_RTSYM_LOC_FIXUP(FIX) \ - ( (FIX)->fx_r_type != BFD_RELOC_ARM_GOT12 \ - && (FIX)->fx_r_type != BFD_RELOC_ARM_GOT32 \ - && (FIX)->fx_r_type != BFD_RELOC_32) - -#define TC_CONS_FIX_NEW cons_fix_new_arm - extern void cons_fix_new_arm PARAMS ((fragS *, int, int, expressionS *)); - -/* Don't allow symbols to be discarded on GOT related relocs, - nor on globals. */ -#define tc_fix_adjustable(x) (\ - ((x)->fx_r_type == BFD_RELOC_ARM_PLT32 \ - || (x)->fx_r_type == BFD_RELOC_ARM_GOT32 \ - || (x)->fx_r_type == BFD_RELOC_ARM_GOTOFF \ - || S_IS_EXTERN ((x)->fx_addsy) \ - || S_IS_WEAK ((x)->fx_addsy)) ? 0 : 1) - -#ifdef OBJ_ELF -#define GLOBAL_OFFSET_TABLE_NAME "_GLOBAL_OFFSET_TABLE_" -#else -#define GLOBAL_OFFSET_TABLE_NAME "__GLOBAL_OFFSET_TABLE_" -#endif - -/* end of tc-arm.h */ diff --git a/contrib/binutils/gas/config/tc-generic.c b/contrib/binutils/gas/config/tc-generic.c deleted file mode 100644 index e69de29bb2d1d..0000000000000 --- a/contrib/binutils/gas/config/tc-generic.c +++ /dev/null diff --git a/contrib/binutils/gas/config/tc-generic.h b/contrib/binutils/gas/config/tc-generic.h deleted file mode 100644 index 72df020316518..0000000000000 --- a/contrib/binutils/gas/config/tc-generic.h +++ /dev/null @@ -1,39 +0,0 @@ -/* This file is tc-generic.h - - Copyright (C) 1987, 91, 92, 95, 1997 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. */ - -/* - * This file is tc-generic.h and is intended to be a template for target cpu - * specific header files. It is my intent that this file compile. It is also - * my intent that this file grow into something that can be used as both a - * template for porting, and a stub for testing. xoxorich. - */ - -#define TC_GENERIC 1 - -#define TARGET_BYTES_BIG_ENDIAN 0 - -/* - * Local Variables: - * comment-column: 0 - * fill-column: 131 - * End: - */ - -/* end of tc-generic.h */ diff --git a/contrib/binutils/gas/config/tc-i386.c b/contrib/binutils/gas/config/tc-i386.c deleted file mode 100644 index 7efd6dd180e4f..0000000000000 --- a/contrib/binutils/gas/config/tc-i386.c +++ /dev/null @@ -1,4536 +0,0 @@ -/* i386.c -- Assemble code for the Intel 80386 - Copyright (C) 1989, 91, 92, 93, 94, 95, 96, 97, 98, 99, 2000 - Free Software Foundation. - - 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. */ - -/* - Intel 80386 machine specific gas. - Written by Eliot Dresselhaus (eliot@mgm.mit.edu). - Bugs & suggestions are completely welcome. This is free software. - Please help us make it better. - */ - -#include <ctype.h> - -#include "as.h" -#include "subsegs.h" -#include "opcode/i386.h" - -#ifndef REGISTER_WARNINGS -#define REGISTER_WARNINGS 1 -#endif - -#ifndef INFER_ADDR_PREFIX -#define INFER_ADDR_PREFIX 1 -#endif - -#ifndef SCALE1_WHEN_NO_INDEX -/* Specifying a scale factor besides 1 when there is no index is - futile. eg. `mov (%ebx,2),%al' does exactly the same as - `mov (%ebx),%al'. To slavishly follow what the programmer - specified, set SCALE1_WHEN_NO_INDEX to 0. */ -#define SCALE1_WHEN_NO_INDEX 1 -#endif - -#define true 1 -#define false 0 - -static unsigned int mode_from_disp_size PARAMS ((unsigned int)); -static int fits_in_signed_byte PARAMS ((long)); -static int fits_in_unsigned_byte PARAMS ((long)); -static int fits_in_unsigned_word PARAMS ((long)); -static int fits_in_signed_word PARAMS ((long)); -static int smallest_imm_type PARAMS ((long)); -static int add_prefix PARAMS ((unsigned int)); -static void set_16bit_code_flag PARAMS ((int)); -static void set_16bit_gcc_code_flag PARAMS((int)); -static void set_intel_syntax PARAMS ((int)); - -#ifdef BFD_ASSEMBLER -static bfd_reloc_code_real_type reloc - PARAMS ((int, int, bfd_reloc_code_real_type)); -#endif - -/* 'md_assemble ()' gathers together information and puts it into a - i386_insn. */ - -union i386_op - { - expressionS *disps; - expressionS *imms; - const reg_entry *regs; - }; - -struct _i386_insn - { - /* TM holds the template for the insn were currently assembling. */ - template tm; - - /* SUFFIX holds the instruction mnemonic suffix if given. - (e.g. 'l' for 'movl') */ - char suffix; - - /* OPERANDS gives the number of given operands. */ - unsigned int operands; - - /* REG_OPERANDS, DISP_OPERANDS, MEM_OPERANDS, IMM_OPERANDS give the number - of given register, displacement, memory operands and immediate - operands. */ - unsigned int reg_operands, disp_operands, mem_operands, imm_operands; - - /* TYPES [i] is the type (see above #defines) which tells us how to - use OP[i] for the corresponding operand. */ - unsigned int types[MAX_OPERANDS]; - - /* Displacement expression, immediate expression, or register for each - operand. */ - union i386_op op[MAX_OPERANDS]; - - /* Relocation type for operand */ -#ifdef BFD_ASSEMBLER - enum bfd_reloc_code_real disp_reloc[MAX_OPERANDS]; -#else - int disp_reloc[MAX_OPERANDS]; -#endif - - /* BASE_REG, INDEX_REG, and LOG2_SCALE_FACTOR are used to encode - the base index byte below. */ - const reg_entry *base_reg; - const reg_entry *index_reg; - unsigned int log2_scale_factor; - - /* SEG gives the seg_entries of this insn. They are zero unless - explicit segment overrides are given. */ - const seg_entry *seg[2]; /* segments for memory operands (if given) */ - - /* PREFIX holds all the given prefix opcodes (usually null). - PREFIXES is the number of prefix opcodes. */ - unsigned int prefixes; - unsigned char prefix[MAX_PREFIXES]; - - /* RM and SIB are the modrm byte and the sib byte where the - addressing modes of this insn are encoded. */ - - modrm_byte rm; - sib_byte sib; - }; - -typedef struct _i386_insn i386_insn; - -/* List of chars besides those in app.c:symbol_chars that can start an - operand. Used to prevent the scrubber eating vital white-space. */ -#ifdef LEX_AT -const char extra_symbol_chars[] = "*%-(@"; -#else -const char extra_symbol_chars[] = "*%-("; -#endif - -/* This array holds the chars that always start a comment. If the - pre-processor is disabled, these aren't very useful */ -#if defined (TE_I386AIX) || ((defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) && ! defined (TE_LINUX)) -/* Putting '/' here makes it impossible to use the divide operator. - However, we need it for compatibility with SVR4 systems. */ -const char comment_chars[] = "#/"; -#define PREFIX_SEPARATOR '\\' -#else -const char comment_chars[] = "#"; -#define PREFIX_SEPARATOR '/' -#endif - -/* This array holds the chars that only start a comment at the beginning of - a line. If the line seems to have the form '# 123 filename' - .line and .file directives will appear in the pre-processed output */ -/* Note that input_file.c hand checks for '#' at the beginning of the - first line of the input file. This is because the compiler outputs - #NO_APP at the beginning of its output. */ -/* Also note that comments started like this one will always work if - '/' isn't otherwise defined. */ -#if defined (TE_I386AIX) || ((defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) && ! defined (TE_LINUX)) -const char line_comment_chars[] = ""; -#else -const char line_comment_chars[] = "/"; -#endif - -const char line_separator_chars[] = ""; - -/* Chars that can be used to separate mant from exp in floating point nums */ -const char EXP_CHARS[] = "eE"; - -/* Chars that mean this number is a floating point constant */ -/* As in 0f12.456 */ -/* or 0d1.2345e12 */ -const char FLT_CHARS[] = "fFdDxX"; - -/* tables for lexical analysis */ -static char mnemonic_chars[256]; -static char register_chars[256]; -static char operand_chars[256]; -static char identifier_chars[256]; -static char digit_chars[256]; - -/* lexical macros */ -#define is_mnemonic_char(x) (mnemonic_chars[(unsigned char) x]) -#define is_operand_char(x) (operand_chars[(unsigned char) x]) -#define is_register_char(x) (register_chars[(unsigned char) x]) -#define is_space_char(x) ((x) == ' ') -#define is_identifier_char(x) (identifier_chars[(unsigned char) x]) -#define is_digit_char(x) (digit_chars[(unsigned char) x]) - -/* put here all non-digit non-letter charcters that may occur in an operand */ -static char operand_special_chars[] = "%$-+(,)*._~/<>|&^!:[@]"; - -/* md_assemble() always leaves the strings it's passed unaltered. To - effect this we maintain a stack of saved characters that we've smashed - with '\0's (indicating end of strings for various sub-fields of the - assembler instruction). */ -static char save_stack[32]; -static char *save_stack_p; /* stack pointer */ -#define END_STRING_AND_SAVE(s) \ - do { *save_stack_p++ = *(s); *(s) = '\0'; } while (0) -#define RESTORE_END_STRING(s) \ - do { *(s) = *--save_stack_p; } while (0) - -/* The instruction we're assembling. */ -static i386_insn i; - -/* Possible templates for current insn. */ -static const templates *current_templates; - -/* Per instruction expressionS buffers: 2 displacements & 2 immediate max. */ -static expressionS disp_expressions[2], im_expressions[2]; - -static int this_operand; /* current operand we are working on */ - -static int flag_do_long_jump; /* FIXME what does this do? */ - -static int flag_16bit_code; /* 1 if we're writing 16-bit code, 0 if 32-bit */ - -static int intel_syntax = 0; /* 1 for intel syntax, 0 if att syntax */ - -static int allow_naked_reg = 0; /* 1 if register prefix % not required */ - -static char stackop_size = '\0'; /* Used in 16 bit gcc mode to add an l - suffix to call, ret, enter, leave, push, - and pop instructions so that gcc has the - same stack frame as in 32 bit mode. */ - -/* Interface to relax_segment. - There are 2 relax states for 386 jump insns: one for conditional & - one for unconditional jumps. This is because these two types of - jumps add different sizes to frags when we're figuring out what - sort of jump to choose to reach a given label. */ - -/* types */ -#define COND_JUMP 1 /* conditional jump */ -#define UNCOND_JUMP 2 /* unconditional jump */ -/* sizes */ -#define CODE16 1 -#define SMALL 0 -#define SMALL16 (SMALL|CODE16) -#define BIG 2 -#define BIG16 (BIG|CODE16) - -#ifndef INLINE -#ifdef __GNUC__ -#define INLINE __inline__ -#else -#define INLINE -#endif -#endif - -#define ENCODE_RELAX_STATE(type,size) \ - ((relax_substateT)((type<<2) | (size))) -#define SIZE_FROM_RELAX_STATE(s) \ - ( (((s) & 0x3) == BIG ? 4 : (((s) & 0x3) == BIG16 ? 2 : 1)) ) - -/* This table is used by relax_frag to promote short jumps to long - ones where necessary. SMALL (short) jumps may be promoted to BIG - (32 bit long) ones, and SMALL16 jumps to BIG16 (16 bit long). We - don't allow a short jump in a 32 bit code segment to be promoted to - a 16 bit offset jump because it's slower (requires data size - prefix), and doesn't work, unless the destination is in the bottom - 64k of the code segment (The top 16 bits of eip are zeroed). */ - -const relax_typeS md_relax_table[] = -{ - /* The fields are: - 1) most positive reach of this state, - 2) most negative reach of this state, - 3) how many bytes this mode will add to the size of the current frag - 4) which index into the table to try if we can't fit into this one. - */ - {1, 1, 0, 0}, - {1, 1, 0, 0}, - {1, 1, 0, 0}, - {1, 1, 0, 0}, - - {127 + 1, -128 + 1, 0, ENCODE_RELAX_STATE (COND_JUMP, BIG)}, - {127 + 1, -128 + 1, 0, ENCODE_RELAX_STATE (COND_JUMP, BIG16)}, - /* dword conditionals adds 4 bytes to frag: - 1 extra opcode byte, 3 extra displacement bytes. */ - {0, 0, 4, 0}, - /* word conditionals add 2 bytes to frag: - 1 extra opcode byte, 1 extra displacement byte. */ - {0, 0, 2, 0}, - - {127 + 1, -128 + 1, 0, ENCODE_RELAX_STATE (UNCOND_JUMP, BIG)}, - {127 + 1, -128 + 1, 0, ENCODE_RELAX_STATE (UNCOND_JUMP, BIG16)}, - /* dword jmp adds 3 bytes to frag: - 0 extra opcode bytes, 3 extra displacement bytes. */ - {0, 0, 3, 0}, - /* word jmp adds 1 byte to frag: - 0 extra opcode bytes, 1 extra displacement byte. */ - {0, 0, 1, 0} - -}; - - -void -i386_align_code (fragP, count) - fragS *fragP; - int count; -{ - /* Various efficient no-op patterns for aligning code labels. */ - /* Note: Don't try to assemble the instructions in the comments. */ - /* 0L and 0w are not legal */ - static const char f32_1[] = - {0x90}; /* nop */ - static const char f32_2[] = - {0x89,0xf6}; /* movl %esi,%esi */ - static const char f32_3[] = - {0x8d,0x76,0x00}; /* leal 0(%esi),%esi */ - static const char f32_4[] = - {0x8d,0x74,0x26,0x00}; /* leal 0(%esi,1),%esi */ - static const char f32_5[] = - {0x90, /* nop */ - 0x8d,0x74,0x26,0x00}; /* leal 0(%esi,1),%esi */ - static const char f32_6[] = - {0x8d,0xb6,0x00,0x00,0x00,0x00}; /* leal 0L(%esi),%esi */ - static const char f32_7[] = - {0x8d,0xb4,0x26,0x00,0x00,0x00,0x00}; /* leal 0L(%esi,1),%esi */ - static const char f32_8[] = - {0x90, /* nop */ - 0x8d,0xb4,0x26,0x00,0x00,0x00,0x00}; /* leal 0L(%esi,1),%esi */ - static const char f32_9[] = - {0x89,0xf6, /* movl %esi,%esi */ - 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ - static const char f32_10[] = - {0x8d,0x76,0x00, /* leal 0(%esi),%esi */ - 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ - static const char f32_11[] = - {0x8d,0x74,0x26,0x00, /* leal 0(%esi,1),%esi */ - 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ - static const char f32_12[] = - {0x8d,0xb6,0x00,0x00,0x00,0x00, /* leal 0L(%esi),%esi */ - 0x8d,0xbf,0x00,0x00,0x00,0x00}; /* leal 0L(%edi),%edi */ - static const char f32_13[] = - {0x8d,0xb6,0x00,0x00,0x00,0x00, /* leal 0L(%esi),%esi */ - 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ - static const char f32_14[] = - {0x8d,0xb4,0x26,0x00,0x00,0x00,0x00, /* leal 0L(%esi,1),%esi */ - 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ - static const char f32_15[] = - {0xeb,0x0d,0x90,0x90,0x90,0x90,0x90, /* jmp .+15; lotsa nops */ - 0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90}; - static const char f16_3[] = - {0x8d,0x74,0x00}; /* lea 0(%esi),%esi */ - static const char f16_4[] = - {0x8d,0xb4,0x00,0x00}; /* lea 0w(%si),%si */ - static const char f16_5[] = - {0x90, /* nop */ - 0x8d,0xb4,0x00,0x00}; /* lea 0w(%si),%si */ - static const char f16_6[] = - {0x89,0xf6, /* mov %si,%si */ - 0x8d,0xbd,0x00,0x00}; /* lea 0w(%di),%di */ - static const char f16_7[] = - {0x8d,0x74,0x00, /* lea 0(%si),%si */ - 0x8d,0xbd,0x00,0x00}; /* lea 0w(%di),%di */ - static const char f16_8[] = - {0x8d,0xb4,0x00,0x00, /* lea 0w(%si),%si */ - 0x8d,0xbd,0x00,0x00}; /* lea 0w(%di),%di */ - static const char *const f32_patt[] = { - f32_1, f32_2, f32_3, f32_4, f32_5, f32_6, f32_7, f32_8, - f32_9, f32_10, f32_11, f32_12, f32_13, f32_14, f32_15 - }; - static const char *const f16_patt[] = { - f32_1, f32_2, f16_3, f16_4, f16_5, f16_6, f16_7, f16_8, - f32_15, f32_15, f32_15, f32_15, f32_15, f32_15, f32_15 - }; - - if (count > 0 && count <= 15) - { - if (flag_16bit_code) - { - memcpy(fragP->fr_literal + fragP->fr_fix, - f16_patt[count - 1], count); - if (count > 8) /* adjust jump offset */ - fragP->fr_literal[fragP->fr_fix + 1] = count - 2; - } - else - memcpy(fragP->fr_literal + fragP->fr_fix, - f32_patt[count - 1], count); - fragP->fr_var = count; - } -} - -static char *output_invalid PARAMS ((int c)); -static int i386_operand PARAMS ((char *operand_string)); -static int i386_intel_operand PARAMS ((char *operand_string, int got_a_float)); -static const reg_entry *parse_register PARAMS ((char *reg_string, - char **end_op)); - -#ifndef I386COFF -static void s_bss PARAMS ((int)); -#endif - -symbolS *GOT_symbol; /* Pre-defined "_GLOBAL_OFFSET_TABLE_" */ - -static INLINE unsigned int -mode_from_disp_size (t) - unsigned int t; -{ - return (t & Disp8) ? 1 : (t & (Disp16|Disp32)) ? 2 : 0; -} - -static INLINE int -fits_in_signed_byte (num) - long num; -{ - return (num >= -128) && (num <= 127); -} /* fits_in_signed_byte() */ - -static INLINE int -fits_in_unsigned_byte (num) - long num; -{ - return (num & 0xff) == num; -} /* fits_in_unsigned_byte() */ - -static INLINE int -fits_in_unsigned_word (num) - long num; -{ - return (num & 0xffff) == num; -} /* fits_in_unsigned_word() */ - -static INLINE int -fits_in_signed_word (num) - long num; -{ - return (-32768 <= num) && (num <= 32767); -} /* fits_in_signed_word() */ - -static int -smallest_imm_type (num) - long num; -{ -#if 0 - /* This code is disabled because all the Imm1 forms in the opcode table - are slower on the i486, and they're the versions with the implicitly - specified single-position displacement, which has another syntax if - you really want to use that form. If you really prefer to have the - one-byte-shorter Imm1 form despite these problems, re-enable this - code. */ - if (num == 1) - return Imm1 | Imm8 | Imm8S | Imm16 | Imm32; -#endif - return (fits_in_signed_byte (num) - ? (Imm8S | Imm8 | Imm16 | Imm32) - : fits_in_unsigned_byte (num) - ? (Imm8 | Imm16 | Imm32) - : (fits_in_signed_word (num) || fits_in_unsigned_word (num)) - ? (Imm16 | Imm32) - : (Imm32)); -} /* smallest_imm_type() */ - -/* Returns 0 if attempting to add a prefix where one from the same - class already exists, 1 if non rep/repne added, 2 if rep/repne - added. */ -static int -add_prefix (prefix) - unsigned int prefix; -{ - int ret = 1; - int q; - - switch (prefix) - { - default: - abort (); - - case CS_PREFIX_OPCODE: - case DS_PREFIX_OPCODE: - case ES_PREFIX_OPCODE: - case FS_PREFIX_OPCODE: - case GS_PREFIX_OPCODE: - case SS_PREFIX_OPCODE: - q = SEG_PREFIX; - break; - - case REPNE_PREFIX_OPCODE: - case REPE_PREFIX_OPCODE: - ret = 2; - /* fall thru */ - case LOCK_PREFIX_OPCODE: - q = LOCKREP_PREFIX; - break; - - case FWAIT_OPCODE: - q = WAIT_PREFIX; - break; - - case ADDR_PREFIX_OPCODE: - q = ADDR_PREFIX; - break; - - case DATA_PREFIX_OPCODE: - q = DATA_PREFIX; - break; - } - - if (i.prefix[q]) - { - as_bad (_("same type of prefix used twice")); - return 0; - } - - i.prefixes += 1; - i.prefix[q] = prefix; - return ret; -} - -static void -set_16bit_code_flag (new_16bit_code_flag) - int new_16bit_code_flag; -{ - flag_16bit_code = new_16bit_code_flag; - stackop_size = '\0'; -} - -static void -set_16bit_gcc_code_flag (new_16bit_code_flag) - int new_16bit_code_flag; -{ - flag_16bit_code = new_16bit_code_flag; - stackop_size = new_16bit_code_flag ? 'l' : '\0'; -} - -static void -set_intel_syntax (syntax_flag) - int syntax_flag; -{ - /* Find out if register prefixing is specified. */ - int ask_naked_reg = 0; - - SKIP_WHITESPACE (); - if (! is_end_of_line[(unsigned char) *input_line_pointer]) - { - char *string = input_line_pointer; - int e = get_symbol_end (); - - if (strcmp(string, "prefix") == 0) - ask_naked_reg = 1; - else if (strcmp(string, "noprefix") == 0) - ask_naked_reg = -1; - else - as_bad (_("bad argument to syntax directive.")); - *input_line_pointer = e; - } - demand_empty_rest_of_line (); - - intel_syntax = syntax_flag; - - if (ask_naked_reg == 0) - { -#ifdef BFD_ASSEMBLER - allow_naked_reg = (intel_syntax - && (bfd_get_symbol_leading_char (stdoutput) != '\0')); -#else - allow_naked_reg = 0; /* conservative default */ -#endif - } - else - allow_naked_reg = (ask_naked_reg < 0); -} - -const pseudo_typeS md_pseudo_table[] = -{ -#ifndef I386COFF - {"bss", s_bss, 0}, -#endif -#if !defined(OBJ_AOUT) && !defined(USE_ALIGN_PTWO) - {"align", s_align_bytes, 0}, -#else - {"align", s_align_ptwo, 0}, -#endif - {"ffloat", float_cons, 'f'}, - {"dfloat", float_cons, 'd'}, - {"tfloat", float_cons, 'x'}, - {"value", cons, 2}, - {"noopt", s_ignore, 0}, - {"optim", s_ignore, 0}, - {"code16gcc", set_16bit_gcc_code_flag, 1}, - {"code16", set_16bit_code_flag, 1}, - {"code32", set_16bit_code_flag, 0}, - {"intel_syntax", set_intel_syntax, 1}, - {"att_syntax", set_intel_syntax, 0}, - {0, 0, 0} -}; - -/* for interface with expression () */ -extern char *input_line_pointer; - -/* hash table for instruction mnemonic lookup */ -static struct hash_control *op_hash; -/* hash table for register lookup */ -static struct hash_control *reg_hash; - - -void -md_begin () -{ - const char *hash_err; - - /* initialize op_hash hash table */ - op_hash = hash_new (); - - { - register const template *optab; - register templates *core_optab; - - optab = i386_optab; /* setup for loop */ - core_optab = (templates *) xmalloc (sizeof (templates)); - core_optab->start = optab; - - while (1) - { - ++optab; - if (optab->name == NULL - || strcmp (optab->name, (optab - 1)->name) != 0) - { - /* different name --> ship out current template list; - add to hash table; & begin anew */ - core_optab->end = optab; - hash_err = hash_insert (op_hash, - (optab - 1)->name, - (PTR) core_optab); - if (hash_err) - { - hash_error: - as_fatal (_("Internal Error: Can't hash %s: %s"), - (optab - 1)->name, - hash_err); - } - if (optab->name == NULL) - break; - core_optab = (templates *) xmalloc (sizeof (templates)); - core_optab->start = optab; - } - } - } - - /* initialize reg_hash hash table */ - reg_hash = hash_new (); - { - register const reg_entry *regtab; - - for (regtab = i386_regtab; - regtab < i386_regtab + sizeof (i386_regtab) / sizeof (i386_regtab[0]); - regtab++) - { - hash_err = hash_insert (reg_hash, regtab->reg_name, (PTR) regtab); - if (hash_err) - goto hash_error; - } - } - - /* fill in lexical tables: mnemonic_chars, operand_chars. */ - { - register int c; - register char *p; - - for (c = 0; c < 256; c++) - { - if (isdigit (c)) - { - digit_chars[c] = c; - mnemonic_chars[c] = c; - register_chars[c] = c; - operand_chars[c] = c; - } - else if (islower (c)) - { - mnemonic_chars[c] = c; - register_chars[c] = c; - operand_chars[c] = c; - } - else if (isupper (c)) - { - mnemonic_chars[c] = tolower (c); - register_chars[c] = mnemonic_chars[c]; - operand_chars[c] = c; - } - - if (isalpha (c) || isdigit (c)) - identifier_chars[c] = c; - else if (c >= 128) - { - identifier_chars[c] = c; - operand_chars[c] = c; - } - } - -#ifdef LEX_AT - identifier_chars['@'] = '@'; -#endif - digit_chars['-'] = '-'; - identifier_chars['_'] = '_'; - identifier_chars['.'] = '.'; - - for (p = operand_special_chars; *p != '\0'; p++) - operand_chars[(unsigned char) *p] = *p; - } - -#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) - if (OUTPUT_FLAVOR == bfd_target_elf_flavour) - { - record_alignment (text_section, 2); - record_alignment (data_section, 2); - record_alignment (bss_section, 2); - } -#endif -} - -void -i386_print_statistics (file) - FILE *file; -{ - hash_print_statistics (file, "i386 opcode", op_hash); - hash_print_statistics (file, "i386 register", reg_hash); -} - - -#ifdef DEBUG386 - -/* debugging routines for md_assemble */ -static void pi PARAMS ((char *, i386_insn *)); -static void pte PARAMS ((template *)); -static void pt PARAMS ((unsigned int)); -static void pe PARAMS ((expressionS *)); -static void ps PARAMS ((symbolS *)); - -static void -pi (line, x) - char *line; - i386_insn *x; -{ - register template *p; - int i; - - fprintf (stdout, "%s: template ", line); - pte (&x->tm); - fprintf (stdout, " modrm: mode %x reg %x reg/mem %x", - x->rm.mode, x->rm.reg, x->rm.regmem); - fprintf (stdout, " base %x index %x scale %x\n", - x->bi.base, x->bi.index, x->bi.scale); - for (i = 0; i < x->operands; i++) - { - fprintf (stdout, " #%d: ", i + 1); - pt (x->types[i]); - fprintf (stdout, "\n"); - if (x->types[i] - & (Reg | SReg2 | SReg3 | Control | Debug | Test | RegMMX | RegXMM)) - fprintf (stdout, "%s\n", x->op[i].regs->reg_name); - if (x->types[i] & Imm) - pe (x->op[i].imms); - if (x->types[i] & Disp) - pe (x->op[i].disps); - } -} - -static void -pte (t) - template *t; -{ - int i; - fprintf (stdout, " %d operands ", t->operands); - fprintf (stdout, "opcode %x ", - t->base_opcode); - if (t->extension_opcode != None) - fprintf (stdout, "ext %x ", t->extension_opcode); - if (t->opcode_modifier & D) - fprintf (stdout, "D"); - if (t->opcode_modifier & W) - fprintf (stdout, "W"); - fprintf (stdout, "\n"); - for (i = 0; i < t->operands; i++) - { - fprintf (stdout, " #%d type ", i + 1); - pt (t->operand_types[i]); - fprintf (stdout, "\n"); - } -} - -static void -pe (e) - expressionS *e; -{ - fprintf (stdout, " operation %d\n", e->X_op); - fprintf (stdout, " add_number %ld (%lx)\n", - (long) e->X_add_number, (long) e->X_add_number); - if (e->X_add_symbol) - { - fprintf (stdout, " add_symbol "); - ps (e->X_add_symbol); - fprintf (stdout, "\n"); - } - if (e->X_op_symbol) - { - fprintf (stdout, " op_symbol "); - ps (e->X_op_symbol); - fprintf (stdout, "\n"); - } -} - -static void -ps (s) - symbolS *s; -{ - fprintf (stdout, "%s type %s%s", - S_GET_NAME (s), - S_IS_EXTERNAL (s) ? "EXTERNAL " : "", - segment_name (S_GET_SEGMENT (s))); -} - -struct type_name - { - unsigned int mask; - char *tname; - } - -type_names[] = -{ - { Reg8, "r8" }, - { Reg16, "r16" }, - { Reg32, "r32" }, - { Imm8, "i8" }, - { Imm8S, "i8s" }, - { Imm16, "i16" }, - { Imm32, "i32" }, - { Imm1, "i1" }, - { BaseIndex, "BaseIndex" }, - { Disp8, "d8" }, - { Disp16, "d16" }, - { Disp32, "d32" }, - { InOutPortReg, "InOutPortReg" }, - { ShiftCount, "ShiftCount" }, - { Control, "control reg" }, - { Test, "test reg" }, - { Debug, "debug reg" }, - { FloatReg, "FReg" }, - { FloatAcc, "FAcc" }, - { SReg2, "SReg2" }, - { SReg3, "SReg3" }, - { Acc, "Acc" }, - { JumpAbsolute, "Jump Absolute" }, - { RegMMX, "rMMX" }, - { RegXMM, "rXMM" }, - { EsSeg, "es" }, - { 0, "" } -}; - -static void -pt (t) - unsigned int t; -{ - register struct type_name *ty; - - if (t == Unknown) - { - fprintf (stdout, _("Unknown")); - } - else - { - for (ty = type_names; ty->mask; ty++) - if (t & ty->mask) - fprintf (stdout, "%s, ", ty->tname); - } - fflush (stdout); -} - -#endif /* DEBUG386 */ - -int -tc_i386_force_relocation (fixp) - struct fix *fixp; -{ -#ifdef BFD_ASSEMBLER - if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT - || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY) - return 1; - return 0; -#else - /* For COFF */ - return fixp->fx_r_type == 7; -#endif -} - -#ifdef BFD_ASSEMBLER -static bfd_reloc_code_real_type reloc - PARAMS ((int, int, bfd_reloc_code_real_type)); - -static bfd_reloc_code_real_type -reloc (size, pcrel, other) - int size; - int pcrel; - bfd_reloc_code_real_type other; -{ - if (other != NO_RELOC) return other; - - if (pcrel) - { - switch (size) - { - case 1: return BFD_RELOC_8_PCREL; - case 2: return BFD_RELOC_16_PCREL; - case 4: return BFD_RELOC_32_PCREL; - } - as_bad (_("can not do %d byte pc-relative relocation"), size); - } - else - { - switch (size) - { - case 1: return BFD_RELOC_8; - case 2: return BFD_RELOC_16; - case 4: return BFD_RELOC_32; - } - as_bad (_("can not do %d byte relocation"), size); - } - - return BFD_RELOC_NONE; -} - -/* - * Here we decide which fixups can be adjusted to make them relative to - * the beginning of the section instead of the symbol. Basically we need - * to make sure that the dynamic relocations are done correctly, so in - * some cases we force the original symbol to be used. - */ -int -tc_i386_fix_adjustable (fixP) - fixS *fixP; -{ -#if defined (OBJ_ELF) || defined (TE_PE) - /* Prevent all adjustments to global symbols, or else dynamic - linking will not work correctly. */ - if (S_IS_EXTERN (fixP->fx_addsy)) - return 0; - if (S_IS_WEAK (fixP->fx_addsy)) - return 0; -#endif - /* adjust_reloc_syms doesn't know about the GOT */ - if (fixP->fx_r_type == BFD_RELOC_386_GOTOFF - || fixP->fx_r_type == BFD_RELOC_386_PLT32 - || fixP->fx_r_type == BFD_RELOC_386_GOT32 - || fixP->fx_r_type == BFD_RELOC_RVA - || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT - || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY) - return 0; - return 1; -} -#else -#define reloc(SIZE,PCREL,OTHER) 0 -#define BFD_RELOC_16 0 -#define BFD_RELOC_32 0 -#define BFD_RELOC_16_PCREL 0 -#define BFD_RELOC_32_PCREL 0 -#define BFD_RELOC_386_PLT32 0 -#define BFD_RELOC_386_GOT32 0 -#define BFD_RELOC_386_GOTOFF 0 -#endif - -static int -intel_float_operand PARAMS ((char *mnemonic)); - -static int -intel_float_operand (mnemonic) - char *mnemonic; -{ - if (mnemonic[0] == 'f' && mnemonic[1] =='i') - return 2; - - if (mnemonic[0] == 'f') - return 1; - - return 0; -} - -/* This is the guts of the machine-dependent assembler. LINE points to a - machine dependent instruction. This function is supposed to emit - the frags/bytes it assembles to. */ - -void -md_assemble (line) - char *line; -{ - /* Points to template once we've found it. */ - const template *t; - - /* Count the size of the instruction generated. */ - int insn_size = 0; - - int j; - - char mnemonic[MAX_MNEM_SIZE]; - - /* Initialize globals. */ - memset (&i, '\0', sizeof (i)); - for (j = 0; j < MAX_OPERANDS; j++) - i.disp_reloc[j] = NO_RELOC; - memset (disp_expressions, '\0', sizeof (disp_expressions)); - memset (im_expressions, '\0', sizeof (im_expressions)); - save_stack_p = save_stack; /* reset stack pointer */ - - /* First parse an instruction mnemonic & call i386_operand for the operands. - We assume that the scrubber has arranged it so that line[0] is the valid - start of a (possibly prefixed) mnemonic. */ - { - char *l = line; - char *token_start = l; - char *mnem_p; - - /* Non-zero if we found a prefix only acceptable with string insns. */ - const char *expecting_string_instruction = NULL; - - while (1) - { - mnem_p = mnemonic; - while ((*mnem_p = mnemonic_chars[(unsigned char) *l]) != 0) - { - mnem_p++; - if (mnem_p >= mnemonic + sizeof (mnemonic)) - { - as_bad (_("no such 386 instruction: `%s'"), token_start); - return; - } - l++; - } - if (!is_space_char (*l) - && *l != END_OF_INSN - && *l != PREFIX_SEPARATOR) - { - as_bad (_("invalid character %s in mnemonic"), - output_invalid (*l)); - return; - } - if (token_start == l) - { - if (*l == PREFIX_SEPARATOR) - as_bad (_("expecting prefix; got nothing")); - else - as_bad (_("expecting mnemonic; got nothing")); - return; - } - - /* Look up instruction (or prefix) via hash table. */ - current_templates = hash_find (op_hash, mnemonic); - - if (*l != END_OF_INSN - && (! is_space_char (*l) || l[1] != END_OF_INSN) - && current_templates - && (current_templates->start->opcode_modifier & IsPrefix)) - { - /* If we are in 16-bit mode, do not allow addr16 or data16. - Similarly, in 32-bit mode, do not allow addr32 or data32. */ - if ((current_templates->start->opcode_modifier & (Size16 | Size32)) - && (((current_templates->start->opcode_modifier & Size32) != 0) - ^ flag_16bit_code)) - { - as_bad (_("redundant %s prefix"), - current_templates->start->name); - return; - } - /* Add prefix, checking for repeated prefixes. */ - switch (add_prefix (current_templates->start->base_opcode)) - { - case 0: - return; - case 2: - expecting_string_instruction = - current_templates->start->name; - break; - } - /* Skip past PREFIX_SEPARATOR and reset token_start. */ - token_start = ++l; - } - else - break; - } - - if (!current_templates) - { - /* See if we can get a match by trimming off a suffix. */ - switch (mnem_p[-1]) - { - case WORD_MNEM_SUFFIX: - case BYTE_MNEM_SUFFIX: - case SHORT_MNEM_SUFFIX: - case LONG_MNEM_SUFFIX: - i.suffix = mnem_p[-1]; - mnem_p[-1] = '\0'; - current_templates = hash_find (op_hash, mnemonic); - break; - - /* Intel Syntax */ - case DWORD_MNEM_SUFFIX: - if (intel_syntax) - { - i.suffix = mnem_p[-1]; - mnem_p[-1] = '\0'; - current_templates = hash_find (op_hash, mnemonic); - break; - } - } - if (!current_templates) - { - as_bad (_("no such 386 instruction: `%s'"), token_start); - return; - } - } - - /* check for rep/repne without a string instruction */ - if (expecting_string_instruction - && !(current_templates->start->opcode_modifier & IsString)) - { - as_bad (_("expecting string instruction after `%s'"), - expecting_string_instruction); - return; - } - - /* There may be operands to parse. */ - if (*l != END_OF_INSN) - { - /* parse operands */ - - /* 1 if operand is pending after ','. */ - unsigned int expecting_operand = 0; - - /* Non-zero if operand parens not balanced. */ - unsigned int paren_not_balanced; - - do - { - /* skip optional white space before operand */ - if (is_space_char (*l)) - ++l; - if (!is_operand_char (*l) && *l != END_OF_INSN) - { - as_bad (_("invalid character %s before operand %d"), - output_invalid (*l), - i.operands + 1); - return; - } - token_start = l; /* after white space */ - paren_not_balanced = 0; - while (paren_not_balanced || *l != ',') - { - if (*l == END_OF_INSN) - { - if (paren_not_balanced) - { - if (!intel_syntax) - as_bad (_("unbalanced parenthesis in operand %d."), - i.operands + 1); - else - as_bad (_("unbalanced brackets in operand %d."), - i.operands + 1); - return; - } - else - break; /* we are done */ - } - else if (!is_operand_char (*l) && !is_space_char (*l)) - { - as_bad (_("invalid character %s in operand %d"), - output_invalid (*l), - i.operands + 1); - return; - } - if (!intel_syntax) - { - if (*l == '(') - ++paren_not_balanced; - if (*l == ')') - --paren_not_balanced; - } - else - { - if (*l == '[') - ++paren_not_balanced; - if (*l == ']') - --paren_not_balanced; - } - l++; - } - if (l != token_start) - { /* yes, we've read in another operand */ - unsigned int operand_ok; - this_operand = i.operands++; - if (i.operands > MAX_OPERANDS) - { - as_bad (_("spurious operands; (%d operands/instruction max)"), - MAX_OPERANDS); - return; - } - /* now parse operand adding info to 'i' as we go along */ - END_STRING_AND_SAVE (l); - - if (intel_syntax) - operand_ok = i386_intel_operand (token_start, intel_float_operand (mnemonic)); - else - operand_ok = i386_operand (token_start); - - RESTORE_END_STRING (l); /* restore old contents */ - if (!operand_ok) - return; - } - else - { - if (expecting_operand) - { - expecting_operand_after_comma: - as_bad (_("expecting operand after ','; got nothing")); - return; - } - if (*l == ',') - { - as_bad (_("expecting operand before ','; got nothing")); - return; - } - } - - /* now *l must be either ',' or END_OF_INSN */ - if (*l == ',') - { - if (*++l == END_OF_INSN) - { /* just skip it, if it's \n complain */ - goto expecting_operand_after_comma; - } - expecting_operand = 1; - } - } - while (*l != END_OF_INSN); /* until we get end of insn */ - } - } - - /* Now we've parsed the mnemonic into a set of templates, and have the - operands at hand. - - Next, we find a template that matches the given insn, - making sure the overlap of the given operands types is consistent - with the template operand types. */ - -#define MATCH(overlap, given, template) \ - ((overlap & ~JumpAbsolute) \ - && ((given) & (BaseIndex|JumpAbsolute)) == ((overlap) & (BaseIndex|JumpAbsolute))) - - /* If given types r0 and r1 are registers they must be of the same type - unless the expected operand type register overlap is null. - Note that Acc in a template matches every size of reg. */ -#define CONSISTENT_REGISTER_MATCH(m0, g0, t0, m1, g1, t1) \ - ( ((g0) & Reg) == 0 || ((g1) & Reg) == 0 || \ - ((g0) & Reg) == ((g1) & Reg) || \ - ((((m0) & Acc) ? Reg : (t0)) & (((m1) & Acc) ? Reg : (t1)) & Reg) == 0 ) - - { - register unsigned int overlap0, overlap1; - unsigned int overlap2; - unsigned int found_reverse_match; - int suffix_check; - - /* All intel opcodes have reversed operands except for "bound" and - "enter". We also don't reverse intersegment "jmp" and "call" - instructions with 2 immediate operands so that the immediate segment - precedes the offset, as it does when in AT&T mode. "enter" and the - intersegment "jmp" and "call" instructions are the only ones that - have two immediate operands. */ - if (intel_syntax && i.operands > 1 - && (strcmp (mnemonic, "bound") != 0) - && !((i.types[0] & Imm) && (i.types[1] & Imm))) - { - union i386_op temp_op; - unsigned int temp_type; - int xchg1 = 0; - int xchg2 = 0; - - if (i.operands == 2) - { - xchg1 = 0; - xchg2 = 1; - } - else if (i.operands == 3) - { - xchg1 = 0; - xchg2 = 2; - } - temp_type = i.types[xchg2]; - i.types[xchg2] = i.types[xchg1]; - i.types[xchg1] = temp_type; - temp_op = i.op[xchg2]; - i.op[xchg2] = i.op[xchg1]; - i.op[xchg1] = temp_op; - - if (i.mem_operands == 2) - { - const seg_entry *temp_seg; - temp_seg = i.seg[0]; - i.seg[0] = i.seg[1]; - i.seg[1] = temp_seg; - } - } - - if (i.imm_operands) - { - /* Try to ensure constant immediates are represented in the smallest - opcode possible. */ - char guess_suffix = 0; - int op; - - if (i.suffix) - guess_suffix = i.suffix; - else if (i.reg_operands) - { - /* Figure out a suffix from the last register operand specified. - We can't do this properly yet, ie. excluding InOutPortReg, - but the following works for instructions with immediates. - In any case, we can't set i.suffix yet. */ - for (op = i.operands; --op >= 0; ) - if (i.types[op] & Reg) - { - if (i.types[op] & Reg8) - guess_suffix = BYTE_MNEM_SUFFIX; - else if (i.types[op] & Reg16) - guess_suffix = WORD_MNEM_SUFFIX; - break; - } - } - else if (flag_16bit_code ^ (i.prefix[DATA_PREFIX] != 0)) - guess_suffix = WORD_MNEM_SUFFIX; - - for (op = i.operands; --op >= 0; ) - if ((i.types[op] & Imm) - && i.op[op].imms->X_op == O_constant) - { - /* If a suffix is given, this operand may be shortened. */ - switch (guess_suffix) - { - case WORD_MNEM_SUFFIX: - i.types[op] |= Imm16; - break; - case BYTE_MNEM_SUFFIX: - i.types[op] |= Imm16 | Imm8 | Imm8S; - break; - } - - /* If this operand is at most 16 bits, convert it to a - signed 16 bit number before trying to see whether it will - fit in an even smaller size. This allows a 16-bit operand - such as $0xffe0 to be recognised as within Imm8S range. */ - if ((i.types[op] & Imm16) - && (i.op[op].imms->X_add_number & ~(offsetT)0xffff) == 0) - { - i.op[op].imms->X_add_number = - (((i.op[op].imms->X_add_number & 0xffff) ^ 0x8000) - 0x8000); - } - i.types[op] |= smallest_imm_type ((long) i.op[op].imms->X_add_number); - } - } - - overlap0 = 0; - overlap1 = 0; - overlap2 = 0; - found_reverse_match = 0; - suffix_check = (i.suffix == BYTE_MNEM_SUFFIX - ? No_bSuf - : (i.suffix == WORD_MNEM_SUFFIX - ? No_wSuf - : (i.suffix == SHORT_MNEM_SUFFIX - ? No_sSuf - : (i.suffix == LONG_MNEM_SUFFIX - ? No_lSuf - : (i.suffix == DWORD_MNEM_SUFFIX - ? No_dSuf - : (i.suffix == LONG_DOUBLE_MNEM_SUFFIX ? No_xSuf : 0)))))); - - for (t = current_templates->start; - t < current_templates->end; - t++) - { - /* Must have right number of operands. */ - if (i.operands != t->operands) - continue; - - /* Check the suffix, except for some instructions in intel mode. */ - if ((t->opcode_modifier & suffix_check) - && !(intel_syntax - && t->base_opcode == 0xd9 - && (t->extension_opcode == 5 /* 0xd9,5 "fldcw" */ - || t->extension_opcode == 7))) /* 0xd9,7 "f{n}stcw" */ - continue; - - else if (!t->operands) - break; /* 0 operands always matches */ - - overlap0 = i.types[0] & t->operand_types[0]; - switch (t->operands) - { - case 1: - if (!MATCH (overlap0, i.types[0], t->operand_types[0])) - continue; - break; - case 2: - case 3: - overlap1 = i.types[1] & t->operand_types[1]; - if (!MATCH (overlap0, i.types[0], t->operand_types[0]) - || !MATCH (overlap1, i.types[1], t->operand_types[1]) - || !CONSISTENT_REGISTER_MATCH (overlap0, i.types[0], - t->operand_types[0], - overlap1, i.types[1], - t->operand_types[1])) - { - - /* check if other direction is valid ... */ - if ((t->opcode_modifier & (D|FloatD)) == 0) - continue; - - /* try reversing direction of operands */ - overlap0 = i.types[0] & t->operand_types[1]; - overlap1 = i.types[1] & t->operand_types[0]; - if (!MATCH (overlap0, i.types[0], t->operand_types[1]) - || !MATCH (overlap1, i.types[1], t->operand_types[0]) - || !CONSISTENT_REGISTER_MATCH (overlap0, i.types[0], - t->operand_types[1], - overlap1, i.types[1], - t->operand_types[0])) - { - /* does not match either direction */ - continue; - } - /* found_reverse_match holds which of D or FloatDR - we've found. */ - found_reverse_match = t->opcode_modifier & (D|FloatDR); - break; - } - /* found a forward 2 operand match here */ - if (t->operands == 3) - { - /* Here we make use of the fact that there are no - reverse match 3 operand instructions, and all 3 - operand instructions only need to be checked for - register consistency between operands 2 and 3. */ - overlap2 = i.types[2] & t->operand_types[2]; - if (!MATCH (overlap2, i.types[2], t->operand_types[2]) - || !CONSISTENT_REGISTER_MATCH (overlap1, i.types[1], - t->operand_types[1], - overlap2, i.types[2], - t->operand_types[2])) - - continue; - } - /* found either forward/reverse 2 or 3 operand match here: - slip through to break */ - } - break; /* we've found a match; break out of loop */ - } /* for (t = ... */ - if (t == current_templates->end) - { /* we found no match */ - as_bad (_("suffix or operands invalid for `%s'"), - current_templates->start->name); - return; - } - - if (!intel_syntax - && (i.types[0] & JumpAbsolute) != (t->operand_types[0] & JumpAbsolute)) - { - as_warn (_("indirect %s without `*'"), t->name); - } - - if ((t->opcode_modifier & (IsPrefix|IgnoreSize)) == (IsPrefix|IgnoreSize)) - { - /* Warn them that a data or address size prefix doesn't affect - assembly of the next line of code. */ - as_warn (_("stand-alone `%s' prefix"), t->name); - } - - /* Copy the template we found. */ - i.tm = *t; - if (found_reverse_match) - { - /* If we found a reverse match we must alter the opcode - direction bit. found_reverse_match holds bits to change - (different for int & float insns). */ - - i.tm.base_opcode ^= found_reverse_match; - - i.tm.operand_types[0] = t->operand_types[1]; - i.tm.operand_types[1] = t->operand_types[0]; - } - - /* Undo SYSV386_COMPAT brokenness when in Intel mode. See i386.h */ - if (SYSV386_COMPAT - && intel_syntax - && (i.tm.base_opcode & 0xfffffde0) == 0xdce0) - i.tm.base_opcode ^= FloatR; - - if (i.tm.opcode_modifier & FWait) - if (! add_prefix (FWAIT_OPCODE)) - return; - - /* Check string instruction segment overrides */ - if ((i.tm.opcode_modifier & IsString) != 0 && i.mem_operands != 0) - { - int mem_op = (i.types[0] & AnyMem) ? 0 : 1; - if ((i.tm.operand_types[mem_op] & EsSeg) != 0) - { - if (i.seg[0] != NULL && i.seg[0] != &es) - { - as_bad (_("`%s' operand %d must use `%%es' segment"), - i.tm.name, - mem_op + 1); - return; - } - /* There's only ever one segment override allowed per instruction. - This instruction possibly has a legal segment override on the - second operand, so copy the segment to where non-string - instructions store it, allowing common code. */ - i.seg[0] = i.seg[1]; - } - else if ((i.tm.operand_types[mem_op + 1] & EsSeg) != 0) - { - if (i.seg[1] != NULL && i.seg[1] != &es) - { - as_bad (_("`%s' operand %d must use `%%es' segment"), - i.tm.name, - mem_op + 2); - return; - } - } - } - - /* If matched instruction specifies an explicit instruction mnemonic - suffix, use it. */ - if (i.tm.opcode_modifier & (Size16 | Size32)) - { - if (i.tm.opcode_modifier & Size16) - i.suffix = WORD_MNEM_SUFFIX; - else - i.suffix = LONG_MNEM_SUFFIX; - } - else if (i.reg_operands) - { - /* If there's no instruction mnemonic suffix we try to invent one - based on register operands. */ - if (!i.suffix) - { - /* We take i.suffix from the last register operand specified, - Destination register type is more significant than source - register type. */ - int op; - for (op = i.operands; --op >= 0; ) - if ((i.types[op] & Reg) - && !(i.tm.operand_types[op] & InOutPortReg)) - { - i.suffix = ((i.types[op] & Reg8) ? BYTE_MNEM_SUFFIX : - (i.types[op] & Reg16) ? WORD_MNEM_SUFFIX : - LONG_MNEM_SUFFIX); - break; - } - } - else if (i.suffix == BYTE_MNEM_SUFFIX) - { - int op; - for (op = i.operands; --op >= 0; ) - { - /* If this is an eight bit register, it's OK. If it's - the 16 or 32 bit version of an eight bit register, - we will just use the low portion, and that's OK too. */ - if (i.types[op] & Reg8) - continue; - - /* movzx and movsx should not generate this warning. */ - if (intel_syntax - && (i.tm.base_opcode == 0xfb7 - || i.tm.base_opcode == 0xfb6 - || i.tm.base_opcode == 0xfbe - || i.tm.base_opcode == 0xfbf)) - continue; - - if ((i.types[op] & WordReg) && i.op[op].regs->reg_num < 4 -#if 0 - /* Check that the template allows eight bit regs - This kills insns such as `orb $1,%edx', which - maybe should be allowed. */ - && (i.tm.operand_types[op] & (Reg8|InOutPortReg)) -#endif - ) - { -#if REGISTER_WARNINGS - if ((i.tm.operand_types[op] & InOutPortReg) == 0) - as_warn (_("using `%%%s' instead of `%%%s' due to `%c' suffix"), - (i.op[op].regs - (i.types[op] & Reg16 ? 8 : 16))->reg_name, - i.op[op].regs->reg_name, - i.suffix); -#endif - continue; - } - /* Any other register is bad */ - if (i.types[op] & (Reg | RegMMX | RegXMM - | SReg2 | SReg3 - | Control | Debug | Test - | FloatReg | FloatAcc)) - { - as_bad (_("`%%%s' not allowed with `%s%c'"), - i.op[op].regs->reg_name, - i.tm.name, - i.suffix); - return; - } - } - } - else if (i.suffix == LONG_MNEM_SUFFIX) - { - int op; - for (op = i.operands; --op >= 0; ) - /* Reject eight bit registers, except where the template - requires them. (eg. movzb) */ - if ((i.types[op] & Reg8) != 0 - && (i.tm.operand_types[op] & (Reg16|Reg32|Acc)) != 0) - { - as_bad (_("`%%%s' not allowed with `%s%c'"), - i.op[op].regs->reg_name, - i.tm.name, - i.suffix); - return; - } -#if REGISTER_WARNINGS - /* Warn if the e prefix on a general reg is missing. */ - else if ((i.types[op] & Reg16) != 0 - && (i.tm.operand_types[op] & (Reg32|Acc)) != 0) - { - as_warn (_("using `%%%s' instead of `%%%s' due to `%c' suffix"), - (i.op[op].regs + 8)->reg_name, - i.op[op].regs->reg_name, - i.suffix); - } -#endif - } - else if (i.suffix == WORD_MNEM_SUFFIX) - { - int op; - for (op = i.operands; --op >= 0; ) - /* Reject eight bit registers, except where the template - requires them. (eg. movzb) */ - if ((i.types[op] & Reg8) != 0 - && (i.tm.operand_types[op] & (Reg16|Reg32|Acc)) != 0) - { - as_bad (_("`%%%s' not allowed with `%s%c'"), - i.op[op].regs->reg_name, - i.tm.name, - i.suffix); - return; - } -#if REGISTER_WARNINGS - /* Warn if the e prefix on a general reg is present. */ - else if ((i.types[op] & Reg32) != 0 - && (i.tm.operand_types[op] & (Reg16|Acc)) != 0) - { - as_warn (_("using `%%%s' instead of `%%%s' due to `%c' suffix"), - (i.op[op].regs - 8)->reg_name, - i.op[op].regs->reg_name, - i.suffix); - } -#endif - } - else - abort(); - } - else if ((i.tm.opcode_modifier & DefaultSize) && !i.suffix) - { - i.suffix = stackop_size; - } - - /* Make still unresolved immediate matches conform to size of immediate - given in i.suffix. Note: overlap2 cannot be an immediate! */ - if ((overlap0 & (Imm8 | Imm8S | Imm16 | Imm32)) - && overlap0 != Imm8 && overlap0 != Imm8S - && overlap0 != Imm16 && overlap0 != Imm32) - { - if (i.suffix) - { - overlap0 &= (i.suffix == BYTE_MNEM_SUFFIX ? (Imm8 | Imm8S) : - (i.suffix == WORD_MNEM_SUFFIX ? Imm16 : Imm32)); - } - else if (overlap0 == (Imm16 | Imm32)) - { - overlap0 = - (flag_16bit_code ^ (i.prefix[DATA_PREFIX] != 0)) ? Imm16 : Imm32; - } - else - { - as_bad (_("no instruction mnemonic suffix given; can't determine immediate size")); - return; - } - } - if ((overlap1 & (Imm8 | Imm8S | Imm16 | Imm32)) - && overlap1 != Imm8 && overlap1 != Imm8S - && overlap1 != Imm16 && overlap1 != Imm32) - { - if (i.suffix) - { - overlap1 &= (i.suffix == BYTE_MNEM_SUFFIX ? (Imm8 | Imm8S) : - (i.suffix == WORD_MNEM_SUFFIX ? Imm16 : Imm32)); - } - else if (overlap1 == (Imm16 | Imm32)) - { - overlap1 = - (flag_16bit_code ^ (i.prefix[DATA_PREFIX] != 0)) ? Imm16 : Imm32; - } - else - { - as_bad (_("no instruction mnemonic suffix given; can't determine immediate size")); - return; - } - } - assert ((overlap2 & Imm) == 0); - - i.types[0] = overlap0; - if (overlap0 & ImplicitRegister) - i.reg_operands--; - if (overlap0 & Imm1) - i.imm_operands = 0; /* kludge for shift insns */ - - i.types[1] = overlap1; - if (overlap1 & ImplicitRegister) - i.reg_operands--; - - i.types[2] = overlap2; - if (overlap2 & ImplicitRegister) - i.reg_operands--; - - /* Finalize opcode. First, we change the opcode based on the operand - size given by i.suffix: We need not change things for byte insns. */ - - if (!i.suffix && (i.tm.opcode_modifier & W)) - { - as_bad (_("no instruction mnemonic suffix given and no register operands; can't size instruction")); - return; - } - - /* For movzx and movsx, need to check the register type */ - if (intel_syntax - && (i.tm.base_opcode == 0xfb6 || i.tm.base_opcode == 0xfbe)) - if (i.suffix && i.suffix == BYTE_MNEM_SUFFIX) - { - unsigned int prefix = DATA_PREFIX_OPCODE; - - if ((i.op[1].regs->reg_type & Reg16) != 0) - if (!add_prefix (prefix)) - return; - } - - if (i.suffix && i.suffix != BYTE_MNEM_SUFFIX) - { - /* It's not a byte, select word/dword operation. */ - if (i.tm.opcode_modifier & W) - { - if (i.tm.opcode_modifier & ShortForm) - i.tm.base_opcode |= 8; - else - i.tm.base_opcode |= 1; - } - /* Now select between word & dword operations via the operand - size prefix, except for instructions that will ignore this - prefix anyway. */ - if (((intel_syntax && (i.suffix == DWORD_MNEM_SUFFIX)) - || i.suffix == LONG_MNEM_SUFFIX) == flag_16bit_code - && !(i.tm.opcode_modifier & IgnoreSize)) - { - unsigned int prefix = DATA_PREFIX_OPCODE; - if (i.tm.opcode_modifier & JumpByte) /* jcxz, loop */ - prefix = ADDR_PREFIX_OPCODE; - - if (! add_prefix (prefix)) - return; - } - /* Size floating point instruction. */ - if (i.suffix == LONG_MNEM_SUFFIX - || (intel_syntax && i.suffix == DWORD_MNEM_SUFFIX)) - { - if (i.tm.opcode_modifier & FloatMF) - i.tm.base_opcode ^= 4; - } - } - - if (i.tm.opcode_modifier & ImmExt) - { - /* These AMD 3DNow! and Intel Katmai New Instructions have an - opcode suffix which is coded in the same place as an 8-bit - immediate field would be. Here we fake an 8-bit immediate - operand from the opcode suffix stored in tm.extension_opcode. */ - - expressionS *exp; - - assert(i.imm_operands == 0 && i.operands <= 2 && 2 < MAX_OPERANDS); - - exp = &im_expressions[i.imm_operands++]; - i.op[i.operands].imms = exp; - i.types[i.operands++] = Imm8; - exp->X_op = O_constant; - exp->X_add_number = i.tm.extension_opcode; - i.tm.extension_opcode = None; - } - - /* For insns with operands there are more diddles to do to the opcode. */ - if (i.operands) - { - /* Default segment register this instruction will use - for memory accesses. 0 means unknown. - This is only for optimizing out unnecessary segment overrides. */ - const seg_entry *default_seg = 0; - - /* The imul $imm, %reg instruction is converted into - imul $imm, %reg, %reg, and the clr %reg instruction - is converted into xor %reg, %reg. */ - if (i.tm.opcode_modifier & regKludge) - { - unsigned int first_reg_op = (i.types[0] & Reg) ? 0 : 1; - /* Pretend we saw the extra register operand. */ - assert (i.op[first_reg_op+1].regs == 0); - i.op[first_reg_op+1].regs = i.op[first_reg_op].regs; - i.types[first_reg_op+1] = i.types[first_reg_op]; - i.reg_operands = 2; - } - - if (i.tm.opcode_modifier & ShortForm) - { - /* The register or float register operand is in operand 0 or 1. */ - unsigned int op = (i.types[0] & (Reg | FloatReg)) ? 0 : 1; - /* Register goes in low 3 bits of opcode. */ - i.tm.base_opcode |= i.op[op].regs->reg_num; - if ((i.tm.opcode_modifier & Ugh) != 0) - { - /* Warn about some common errors, but press on regardless. - The first case can be generated by gcc (<= 2.8.1). */ - if (i.operands == 2) - { - /* reversed arguments on faddp, fsubp, etc. */ - as_warn (_("translating to `%s %%%s,%%%s'"), i.tm.name, - i.op[1].regs->reg_name, - i.op[0].regs->reg_name); - } - else - { - /* extraneous `l' suffix on fp insn */ - as_warn (_("translating to `%s %%%s'"), i.tm.name, - i.op[0].regs->reg_name); - } - } - } - else if (i.tm.opcode_modifier & Modrm) - { - /* The opcode is completed (modulo i.tm.extension_opcode which - must be put into the modrm byte). - Now, we make the modrm & index base bytes based on all the - info we've collected. */ - - /* i.reg_operands MUST be the number of real register operands; - implicit registers do not count. */ - if (i.reg_operands == 2) - { - unsigned int source, dest; - source = ((i.types[0] - & (Reg | RegMMX | RegXMM - | SReg2 | SReg3 - | Control | Debug | Test)) - ? 0 : 1); - dest = source + 1; - - i.rm.mode = 3; - /* One of the register operands will be encoded in the - i.tm.reg field, the other in the combined i.tm.mode - and i.tm.regmem fields. If no form of this - instruction supports a memory destination operand, - then we assume the source operand may sometimes be - a memory operand and so we need to store the - destination in the i.rm.reg field. */ - if ((i.tm.operand_types[dest] & AnyMem) == 0) - { - i.rm.reg = i.op[dest].regs->reg_num; - i.rm.regmem = i.op[source].regs->reg_num; - } - else - { - i.rm.reg = i.op[source].regs->reg_num; - i.rm.regmem = i.op[dest].regs->reg_num; - } - } - else - { /* if it's not 2 reg operands... */ - if (i.mem_operands) - { - unsigned int fake_zero_displacement = 0; - unsigned int op = ((i.types[0] & AnyMem) - ? 0 - : (i.types[1] & AnyMem) ? 1 : 2); - - default_seg = &ds; - - if (! i.base_reg) - { - i.rm.mode = 0; - if (! i.disp_operands) - fake_zero_displacement = 1; - if (! i.index_reg) - { - /* Operand is just <disp> */ - if (flag_16bit_code ^ (i.prefix[ADDR_PREFIX] != 0)) - { - i.rm.regmem = NO_BASE_REGISTER_16; - i.types[op] &= ~Disp; - i.types[op] |= Disp16; - } - else - { - i.rm.regmem = NO_BASE_REGISTER; - i.types[op] &= ~Disp; - i.types[op] |= Disp32; - } - } - else /* ! i.base_reg && i.index_reg */ - { - i.sib.index = i.index_reg->reg_num; - i.sib.base = NO_BASE_REGISTER; - i.sib.scale = i.log2_scale_factor; - i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING; - i.types[op] &= ~Disp; - i.types[op] |= Disp32; /* Must be 32 bit */ - } - } - else if (i.base_reg->reg_type & Reg16) - { - switch (i.base_reg->reg_num) - { - case 3: /* (%bx) */ - if (! i.index_reg) - i.rm.regmem = 7; - else /* (%bx,%si) -> 0, or (%bx,%di) -> 1 */ - i.rm.regmem = i.index_reg->reg_num - 6; - break; - case 5: /* (%bp) */ - default_seg = &ss; - if (! i.index_reg) - { - i.rm.regmem = 6; - if ((i.types[op] & Disp) == 0) - { - /* fake (%bp) into 0(%bp) */ - i.types[op] |= Disp8; - fake_zero_displacement = 1; - } - } - else /* (%bp,%si) -> 2, or (%bp,%di) -> 3 */ - i.rm.regmem = i.index_reg->reg_num - 6 + 2; - break; - default: /* (%si) -> 4 or (%di) -> 5 */ - i.rm.regmem = i.base_reg->reg_num - 6 + 4; - } - i.rm.mode = mode_from_disp_size (i.types[op]); - } - else /* i.base_reg and 32 bit mode */ - { - i.rm.regmem = i.base_reg->reg_num; - i.sib.base = i.base_reg->reg_num; - if (i.base_reg->reg_num == EBP_REG_NUM) - { - default_seg = &ss; - if (i.disp_operands == 0) - { - fake_zero_displacement = 1; - i.types[op] |= Disp8; - } - } - else if (i.base_reg->reg_num == ESP_REG_NUM) - { - default_seg = &ss; - } - i.sib.scale = i.log2_scale_factor; - if (! i.index_reg) - { - /* <disp>(%esp) becomes two byte modrm - with no index register. We've already - stored the code for esp in i.rm.regmem - ie. ESCAPE_TO_TWO_BYTE_ADDRESSING. Any - base register besides %esp will not use - the extra modrm byte. */ - i.sib.index = NO_INDEX_REGISTER; -#if ! SCALE1_WHEN_NO_INDEX - /* Another case where we force the second - modrm byte. */ - if (i.log2_scale_factor) - i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING; -#endif - } - else - { - i.sib.index = i.index_reg->reg_num; - i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING; - } - i.rm.mode = mode_from_disp_size (i.types[op]); - } - - if (fake_zero_displacement) - { - /* Fakes a zero displacement assuming that i.types[op] - holds the correct displacement size. */ - expressionS *exp; - - assert (i.op[op].disps == 0); - exp = &disp_expressions[i.disp_operands++]; - i.op[op].disps = exp; - exp->X_op = O_constant; - exp->X_add_number = 0; - exp->X_add_symbol = (symbolS *) 0; - exp->X_op_symbol = (symbolS *) 0; - } - } - - /* Fill in i.rm.reg or i.rm.regmem field with register - operand (if any) based on i.tm.extension_opcode. - Again, we must be careful to make sure that - segment/control/debug/test/MMX registers are coded - into the i.rm.reg field. */ - if (i.reg_operands) - { - unsigned int op = - ((i.types[0] - & (Reg | RegMMX | RegXMM - | SReg2 | SReg3 - | Control | Debug | Test)) - ? 0 - : ((i.types[1] - & (Reg | RegMMX | RegXMM - | SReg2 | SReg3 - | Control | Debug | Test)) - ? 1 - : 2)); - /* If there is an extension opcode to put here, the - register number must be put into the regmem field. */ - if (i.tm.extension_opcode != None) - i.rm.regmem = i.op[op].regs->reg_num; - else - i.rm.reg = i.op[op].regs->reg_num; - - /* Now, if no memory operand has set i.rm.mode = 0, 1, 2 - we must set it to 3 to indicate this is a register - operand in the regmem field. */ - if (!i.mem_operands) - i.rm.mode = 3; - } - - /* Fill in i.rm.reg field with extension opcode (if any). */ - if (i.tm.extension_opcode != None) - i.rm.reg = i.tm.extension_opcode; - } - } - else if (i.tm.opcode_modifier & (Seg2ShortForm | Seg3ShortForm)) - { - if (i.tm.base_opcode == POP_SEG_SHORT && i.op[0].regs->reg_num == 1) - { - as_bad (_("you can't `pop %%cs'")); - return; - } - i.tm.base_opcode |= (i.op[0].regs->reg_num << 3); - } - else if ((i.tm.base_opcode & ~(D|W)) == MOV_AX_DISP32) - { - default_seg = &ds; - } - else if ((i.tm.opcode_modifier & IsString) != 0) - { - /* For the string instructions that allow a segment override - on one of their operands, the default segment is ds. */ - default_seg = &ds; - } - - /* If a segment was explicitly specified, - and the specified segment is not the default, - use an opcode prefix to select it. - If we never figured out what the default segment is, - then default_seg will be zero at this point, - and the specified segment prefix will always be used. */ - if ((i.seg[0]) && (i.seg[0] != default_seg)) - { - if (! add_prefix (i.seg[0]->seg_prefix)) - return; - } - } - else if ((i.tm.opcode_modifier & Ugh) != 0) - { - /* UnixWare fsub no args is alias for fsubp, fadd -> faddp, etc. */ - as_warn (_("translating to `%sp'"), i.tm.name); - } - } - - /* Handle conversion of 'int $3' --> special int3 insn. */ - if (i.tm.base_opcode == INT_OPCODE && i.op[0].imms->X_add_number == 3) - { - i.tm.base_opcode = INT3_OPCODE; - i.imm_operands = 0; - } - - if ((i.tm.opcode_modifier & (Jump | JumpByte | JumpDword)) - && i.op[0].disps->X_op == O_constant) - { - /* Convert "jmp constant" (and "call constant") to a jump (call) to - the absolute address given by the constant. Since ix86 jumps and - calls are pc relative, we need to generate a reloc. */ - i.op[0].disps->X_add_symbol = &abs_symbol; - i.op[0].disps->X_op = O_symbol; - } - - /* We are ready to output the insn. */ - { - register char *p; - - /* Output jumps. */ - if (i.tm.opcode_modifier & Jump) - { - int size; - int code16; - int prefix; - - code16 = 0; - if (flag_16bit_code) - code16 = CODE16; - - prefix = 0; - if (i.prefix[DATA_PREFIX]) - { - prefix = 1; - i.prefixes -= 1; - code16 ^= CODE16; - } - - size = 4; - if (code16) - size = 2; - - if (i.prefixes != 0 && !intel_syntax) - as_warn (_("skipping prefixes on this instruction")); - - /* It's always a symbol; End frag & setup for relax. - Make sure there is enough room in this frag for the largest - instruction we may generate in md_convert_frag. This is 2 - bytes for the opcode and room for the prefix and largest - displacement. */ - frag_grow (prefix + 2 + size); - insn_size += prefix + 1; - /* Prefix and 1 opcode byte go in fr_fix. */ - p = frag_more (prefix + 1); - if (prefix) - *p++ = DATA_PREFIX_OPCODE; - *p = i.tm.base_opcode; - /* 1 possible extra opcode + displacement go in fr_var. */ - frag_var (rs_machine_dependent, - 1 + size, - 1, - ((unsigned char) *p == JUMP_PC_RELATIVE - ? ENCODE_RELAX_STATE (UNCOND_JUMP, SMALL) | code16 - : ENCODE_RELAX_STATE (COND_JUMP, SMALL) | code16), - i.op[0].disps->X_add_symbol, - i.op[0].disps->X_add_number, - p); - } - else if (i.tm.opcode_modifier & (JumpByte | JumpDword)) - { - int size; - - if (i.tm.opcode_modifier & JumpByte) - { - /* This is a loop or jecxz type instruction. */ - size = 1; - if (i.prefix[ADDR_PREFIX]) - { - insn_size += 1; - FRAG_APPEND_1_CHAR (ADDR_PREFIX_OPCODE); - i.prefixes -= 1; - } - } - else - { - int code16; - - code16 = 0; - if (flag_16bit_code) - code16 = CODE16; - - if (i.prefix[DATA_PREFIX]) - { - insn_size += 1; - FRAG_APPEND_1_CHAR (DATA_PREFIX_OPCODE); - i.prefixes -= 1; - code16 ^= CODE16; - } - - size = 4; - if (code16) - size = 2; - } - - if (i.prefixes != 0 && !intel_syntax) - as_warn (_("skipping prefixes on this instruction")); - - if (fits_in_unsigned_byte (i.tm.base_opcode)) - { - insn_size += 1 + size; - p = frag_more (1 + size); - } - else - { - /* opcode can be at most two bytes */ - insn_size += 2 + size; - p = frag_more (2 + size); - *p++ = (i.tm.base_opcode >> 8) & 0xff; - } - *p++ = i.tm.base_opcode & 0xff; - - fix_new_exp (frag_now, p - frag_now->fr_literal, size, - i.op[0].disps, 1, reloc (size, 1, i.disp_reloc[0])); - } - else if (i.tm.opcode_modifier & JumpInterSegment) - { - int size; - int prefix; - int code16; - - code16 = 0; - if (flag_16bit_code) - code16 = CODE16; - - prefix = 0; - if (i.prefix[DATA_PREFIX]) - { - prefix = 1; - i.prefixes -= 1; - code16 ^= CODE16; - } - - size = 4; - if (code16) - size = 2; - - if (i.prefixes != 0 && !intel_syntax) - as_warn (_("skipping prefixes on this instruction")); - - insn_size += prefix + 1 + 2 + size; /* 1 opcode; 2 segment; offset */ - p = frag_more (prefix + 1 + 2 + size); - if (prefix) - *p++ = DATA_PREFIX_OPCODE; - *p++ = i.tm.base_opcode; - if (i.op[1].imms->X_op == O_constant) - { - long n = (long) i.op[1].imms->X_add_number; - - if (size == 2 - && !fits_in_unsigned_word (n) - && !fits_in_signed_word (n)) - { - as_bad (_("16-bit jump out of range")); - return; - } - md_number_to_chars (p, (valueT) n, size); - } - else - fix_new_exp (frag_now, p - frag_now->fr_literal, size, - i.op[1].imms, 0, reloc (size, 0, i.disp_reloc[0])); - if (i.op[0].imms->X_op != O_constant) - as_bad (_("can't handle non absolute segment in `%s'"), - i.tm.name); - md_number_to_chars (p + size, (valueT) i.op[0].imms->X_add_number, 2); - } - else - { - /* Output normal instructions here. */ - unsigned char *q; - - /* The prefix bytes. */ - for (q = i.prefix; - q < i.prefix + sizeof (i.prefix) / sizeof (i.prefix[0]); - q++) - { - if (*q) - { - insn_size += 1; - p = frag_more (1); - md_number_to_chars (p, (valueT) *q, 1); - } - } - - /* Now the opcode; be careful about word order here! */ - if (fits_in_unsigned_byte (i.tm.base_opcode)) - { - insn_size += 1; - FRAG_APPEND_1_CHAR (i.tm.base_opcode); - } - else if (fits_in_unsigned_word (i.tm.base_opcode)) - { - insn_size += 2; - p = frag_more (2); - /* put out high byte first: can't use md_number_to_chars! */ - *p++ = (i.tm.base_opcode >> 8) & 0xff; - *p = i.tm.base_opcode & 0xff; - } - else - { /* opcode is either 3 or 4 bytes */ - if (i.tm.base_opcode & 0xff000000) - { - insn_size += 4; - p = frag_more (4); - *p++ = (i.tm.base_opcode >> 24) & 0xff; - } - else - { - insn_size += 3; - p = frag_more (3); - } - *p++ = (i.tm.base_opcode >> 16) & 0xff; - *p++ = (i.tm.base_opcode >> 8) & 0xff; - *p = (i.tm.base_opcode) & 0xff; - } - - /* Now the modrm byte and sib byte (if present). */ - if (i.tm.opcode_modifier & Modrm) - { - insn_size += 1; - p = frag_more (1); - md_number_to_chars (p, - (valueT) (i.rm.regmem << 0 - | i.rm.reg << 3 - | i.rm.mode << 6), - 1); - /* If i.rm.regmem == ESP (4) - && i.rm.mode != (Register mode) - && not 16 bit - ==> need second modrm byte. */ - if (i.rm.regmem == ESCAPE_TO_TWO_BYTE_ADDRESSING - && i.rm.mode != 3 - && !(i.base_reg && (i.base_reg->reg_type & Reg16) != 0)) - { - insn_size += 1; - p = frag_more (1); - md_number_to_chars (p, - (valueT) (i.sib.base << 0 - | i.sib.index << 3 - | i.sib.scale << 6), - 1); - } - } - - if (i.disp_operands) - { - register unsigned int n; - - for (n = 0; n < i.operands; n++) - { - if (i.types[n] & Disp) - { - if (i.op[n].disps->X_op == O_constant) - { - int size = 4; - long val = (long) i.op[n].disps->X_add_number; - - if (i.types[n] & (Disp8 | Disp16)) - { - long mask; - - size = 2; - mask = ~ (long) 0xffff; - if (i.types[n] & Disp8) - { - size = 1; - mask = ~ (long) 0xff; - } - - if ((val & mask) != 0 && (val & mask) != mask) - as_warn (_("%ld shortened to %ld"), - val, val & ~mask); - } - insn_size += size; - p = frag_more (size); - md_number_to_chars (p, (valueT) val, size); - } - else - { - int size = 4; - - if (i.types[n] & Disp16) - size = 2; - - insn_size += size; - p = frag_more (size); - fix_new_exp (frag_now, p - frag_now->fr_literal, size, - i.op[n].disps, 0, - reloc (size, 0, i.disp_reloc[n])); - } - } - } - } /* end displacement output */ - - /* output immediate */ - if (i.imm_operands) - { - register unsigned int n; - - for (n = 0; n < i.operands; n++) - { - if (i.types[n] & Imm) - { - if (i.op[n].imms->X_op == O_constant) - { - int size = 4; - long val = (long) i.op[n].imms->X_add_number; - - if (i.types[n] & (Imm8 | Imm8S | Imm16)) - { - long mask; - - size = 2; - mask = ~ (long) 0xffff; - if (i.types[n] & (Imm8 | Imm8S)) - { - size = 1; - mask = ~ (long) 0xff; - } - if ((val & mask) != 0 && (val & mask) != mask) - as_warn (_("%ld shortened to %ld"), - val, val & ~mask); - } - insn_size += size; - p = frag_more (size); - md_number_to_chars (p, (valueT) val, size); - } - else - { /* not absolute_section */ - /* Need a 32-bit fixup (don't support 8bit - non-absolute imms). Try to support other - sizes ... */ -#ifdef BFD_ASSEMBLER - enum bfd_reloc_code_real reloc_type; -#else - int reloc_type; -#endif - int size = 4; - - if (i.types[n] & Imm16) - size = 2; - else if (i.types[n] & (Imm8 | Imm8S)) - size = 1; - - insn_size += size; - p = frag_more (size); - reloc_type = reloc (size, 0, i.disp_reloc[0]); -#ifdef BFD_ASSEMBLER - if (reloc_type == BFD_RELOC_32 - && GOT_symbol - && GOT_symbol == i.op[n].imms->X_add_symbol - && (i.op[n].imms->X_op == O_symbol - || (i.op[n].imms->X_op == O_add - && ((symbol_get_value_expression - (i.op[n].imms->X_op_symbol)->X_op) - == O_subtract)))) - { - reloc_type = BFD_RELOC_386_GOTPC; - i.op[n].imms->X_add_number += 3; - } -#endif - fix_new_exp (frag_now, p - frag_now->fr_literal, size, - i.op[n].imms, 0, reloc_type); - } - } - } - } /* end immediate output */ - } - -#ifdef DEBUG386 - if (flag_debug) - { - pi (line, &i); - } -#endif /* DEBUG386 */ - } -} - -static int i386_immediate PARAMS ((char *)); - -static int -i386_immediate (imm_start) - char *imm_start; -{ - char *save_input_line_pointer; - segT exp_seg = 0; - expressionS * exp; - - if (i.imm_operands == MAX_IMMEDIATE_OPERANDS) - { - as_bad (_("only 1 or 2 immediate operands are allowed")); - return 0; - } - - exp = &im_expressions[i.imm_operands++]; - i.op[this_operand].imms = exp; - - if (is_space_char (*imm_start)) - ++imm_start; - - save_input_line_pointer = input_line_pointer; - input_line_pointer = imm_start; - -#ifndef LEX_AT - { - /* - * We can have operands of the form - * <symbol>@GOTOFF+<nnn> - * Take the easy way out here and copy everything - * into a temporary buffer... - */ - register char *cp; - - cp = strchr (input_line_pointer, '@'); - if (cp != NULL) - { - char *tmpbuf; - int len = 0; - int first; - - /* GOT relocations are not supported in 16 bit mode */ - if (flag_16bit_code) - as_bad (_("GOT relocations not supported in 16 bit mode")); - - if (GOT_symbol == NULL) - GOT_symbol = symbol_find_or_make (GLOBAL_OFFSET_TABLE_NAME); - - if (strncmp (cp + 1, "PLT", 3) == 0) - { - i.disp_reloc[this_operand] = BFD_RELOC_386_PLT32; - len = 3; - } - else if (strncmp (cp + 1, "GOTOFF", 6) == 0) - { - i.disp_reloc[this_operand] = BFD_RELOC_386_GOTOFF; - len = 6; - } - else if (strncmp (cp + 1, "GOT", 3) == 0) - { - i.disp_reloc[this_operand] = BFD_RELOC_386_GOT32; - len = 3; - } - else - as_bad (_("bad reloc specifier in expression")); - - /* Replace the relocation token with ' ', so that errors like - foo@GOTOFF1 will be detected. */ - first = cp - input_line_pointer; - tmpbuf = (char *) alloca (strlen(input_line_pointer)); - memcpy (tmpbuf, input_line_pointer, first); - tmpbuf[first] = ' '; - strcpy (tmpbuf + first + 1, cp + 1 + len); - input_line_pointer = tmpbuf; - } - } -#endif - - exp_seg = expression (exp); - - SKIP_WHITESPACE (); - if (*input_line_pointer) - as_bad (_("ignoring junk `%s' after expression"), input_line_pointer); - - input_line_pointer = save_input_line_pointer; - - if (exp->X_op == O_absent || exp->X_op == O_big) - { - /* missing or bad expr becomes absolute 0 */ - as_bad (_("missing or invalid immediate expression `%s' taken as 0"), - imm_start); - exp->X_op = O_constant; - exp->X_add_number = 0; - exp->X_add_symbol = (symbolS *) 0; - exp->X_op_symbol = (symbolS *) 0; - } - - if (exp->X_op == O_constant) - { - i.types[this_operand] |= Imm32; /* Size it properly later. */ - } -#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT)) - else if ( -#ifdef BFD_ASSEMBLER - OUTPUT_FLAVOR == bfd_target_aout_flavour && -#endif - exp_seg != text_section - && exp_seg != data_section - && exp_seg != bss_section - && exp_seg != undefined_section -#ifdef BFD_ASSEMBLER - && !bfd_is_com_section (exp_seg) -#endif - ) - { -#ifdef BFD_ASSEMBLER - as_bad (_("unimplemented segment %s in operand"), exp_seg->name); -#else - as_bad (_("unimplemented segment type %d in operand"), exp_seg); -#endif - return 0; - } -#endif - else - { - /* This is an address. The size of the address will be - determined later, depending on destination register, - suffix, or the default for the section. We exclude - Imm8S here so that `push $foo' and other instructions - with an Imm8S form will use Imm16 or Imm32. */ - i.types[this_operand] |= (Imm8 | Imm16 | Imm32); - } - - return 1; -} - -static int i386_scale PARAMS ((char *)); - -static int -i386_scale (scale) - char *scale; -{ - if (!isdigit (*scale)) - goto bad_scale; - - switch (*scale) - { - case '0': - case '1': - i.log2_scale_factor = 0; - break; - case '2': - i.log2_scale_factor = 1; - break; - case '4': - i.log2_scale_factor = 2; - break; - case '8': - i.log2_scale_factor = 3; - break; - default: - bad_scale: - as_bad (_("expecting scale factor of 1, 2, 4, or 8: got `%s'"), - scale); - return 0; - } - if (i.log2_scale_factor != 0 && ! i.index_reg) - { - as_warn (_("scale factor of %d without an index register"), - 1 << i.log2_scale_factor); -#if SCALE1_WHEN_NO_INDEX - i.log2_scale_factor = 0; -#endif - } - return 1; -} - -static int i386_displacement PARAMS ((char *, char *)); - -static int -i386_displacement (disp_start, disp_end) - char *disp_start; - char *disp_end; -{ - register expressionS *exp; - segT exp_seg = 0; - char *save_input_line_pointer; - int bigdisp = Disp32; - - if (flag_16bit_code ^ (i.prefix[ADDR_PREFIX] != 0)) - bigdisp = Disp16; - i.types[this_operand] |= bigdisp; - - exp = &disp_expressions[i.disp_operands]; - i.op[this_operand].disps = exp; - i.disp_operands++; - save_input_line_pointer = input_line_pointer; - input_line_pointer = disp_start; - END_STRING_AND_SAVE (disp_end); - -#ifndef GCC_ASM_O_HACK -#define GCC_ASM_O_HACK 0 -#endif -#if GCC_ASM_O_HACK - END_STRING_AND_SAVE (disp_end + 1); - if ((i.types[this_operand] & BaseIndex) != 0 - && displacement_string_end[-1] == '+') - { - /* This hack is to avoid a warning when using the "o" - constraint within gcc asm statements. - For instance: - - #define _set_tssldt_desc(n,addr,limit,type) \ - __asm__ __volatile__ ( \ - "movw %w2,%0\n\t" \ - "movw %w1,2+%0\n\t" \ - "rorl $16,%1\n\t" \ - "movb %b1,4+%0\n\t" \ - "movb %4,5+%0\n\t" \ - "movb $0,6+%0\n\t" \ - "movb %h1,7+%0\n\t" \ - "rorl $16,%1" \ - : "=o"(*(n)) : "q" (addr), "ri"(limit), "i"(type)) - - This works great except that the output assembler ends - up looking a bit weird if it turns out that there is - no offset. You end up producing code that looks like: - - #APP - movw $235,(%eax) - movw %dx,2+(%eax) - rorl $16,%edx - movb %dl,4+(%eax) - movb $137,5+(%eax) - movb $0,6+(%eax) - movb %dh,7+(%eax) - rorl $16,%edx - #NO_APP - - So here we provide the missing zero. - */ - - *displacement_string_end = '0'; - } -#endif -#ifndef LEX_AT - { - /* - * We can have operands of the form - * <symbol>@GOTOFF+<nnn> - * Take the easy way out here and copy everything - * into a temporary buffer... - */ - register char *cp; - - cp = strchr (input_line_pointer, '@'); - if (cp != NULL) - { - char *tmpbuf; - int len = 0; - int first; - - /* GOT relocations are not supported in 16 bit mode */ - if (flag_16bit_code) - as_bad (_("GOT relocations not supported in 16 bit mode")); - - if (GOT_symbol == NULL) - GOT_symbol = symbol_find_or_make (GLOBAL_OFFSET_TABLE_NAME); - - if (strncmp (cp + 1, "PLT", 3) == 0) - { - i.disp_reloc[this_operand] = BFD_RELOC_386_PLT32; - len = 3; - } - else if (strncmp (cp + 1, "GOTOFF", 6) == 0) - { - i.disp_reloc[this_operand] = BFD_RELOC_386_GOTOFF; - len = 6; - } - else if (strncmp (cp + 1, "GOT", 3) == 0) - { - i.disp_reloc[this_operand] = BFD_RELOC_386_GOT32; - len = 3; - } - else - as_bad (_("bad reloc specifier in expression")); - - /* Replace the relocation token with ' ', so that errors like - foo@GOTOFF1 will be detected. */ - first = cp - input_line_pointer; - tmpbuf = (char *) alloca (strlen(input_line_pointer)); - memcpy (tmpbuf, input_line_pointer, first); - tmpbuf[first] = ' '; - strcpy (tmpbuf + first + 1, cp + 1 + len); - input_line_pointer = tmpbuf; - } - } -#endif - - exp_seg = expression (exp); - -#ifdef BFD_ASSEMBLER - /* We do this to make sure that the section symbol is in - the symbol table. We will ultimately change the relocation - to be relative to the beginning of the section */ - if (i.disp_reloc[this_operand] == BFD_RELOC_386_GOTOFF) - { - if (S_IS_LOCAL(exp->X_add_symbol) - && S_GET_SEGMENT (exp->X_add_symbol) != undefined_section) - section_symbol (S_GET_SEGMENT (exp->X_add_symbol)); - assert (exp->X_op == O_symbol); - exp->X_op = O_subtract; - exp->X_op_symbol = GOT_symbol; - i.disp_reloc[this_operand] = BFD_RELOC_32; - } -#endif - - SKIP_WHITESPACE (); - if (*input_line_pointer) - as_bad (_("ignoring junk `%s' after expression"), - input_line_pointer); -#if GCC_ASM_O_HACK - RESTORE_END_STRING (disp_end + 1); -#endif - RESTORE_END_STRING (disp_end); - input_line_pointer = save_input_line_pointer; - - if (exp->X_op == O_absent || exp->X_op == O_big) - { - /* missing or bad expr becomes absolute 0 */ - as_bad (_("missing or invalid displacement expression `%s' taken as 0"), - disp_start); - exp->X_op = O_constant; - exp->X_add_number = 0; - exp->X_add_symbol = (symbolS *) 0; - exp->X_op_symbol = (symbolS *) 0; - } - - if (exp->X_op == O_constant) - { - if (i.types[this_operand] & Disp16) - { - /* We know this operand is at most 16 bits, so convert to a - signed 16 bit number before trying to see whether it will - fit in an even smaller size. */ - exp->X_add_number = - (((exp->X_add_number & 0xffff) ^ 0x8000) - 0x8000); - } - if (fits_in_signed_byte (exp->X_add_number)) - i.types[this_operand] |= Disp8; - } -#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT)) - else if ( -#ifdef BFD_ASSEMBLER - OUTPUT_FLAVOR == bfd_target_aout_flavour && -#endif - exp_seg != text_section - && exp_seg != data_section - && exp_seg != bss_section - && exp_seg != undefined_section) - { -#ifdef BFD_ASSEMBLER - as_bad (_("unimplemented segment %s in operand"), exp_seg->name); -#else - as_bad (_("unimplemented segment type %d in operand"), exp_seg); -#endif - return 0; - } -#endif - return 1; -} - -static int i386_operand_modifier PARAMS ((char **, int)); - -static int -i386_operand_modifier (op_string, got_a_float) - char **op_string; - int got_a_float; -{ - if (!strncasecmp (*op_string, "BYTE PTR", 8)) - { - i.suffix = BYTE_MNEM_SUFFIX; - *op_string += 8; - return BYTE_PTR; - - } - else if (!strncasecmp (*op_string, "WORD PTR", 8)) - { - if (got_a_float == 2) /* "fi..." */ - i.suffix = SHORT_MNEM_SUFFIX; - else - i.suffix = WORD_MNEM_SUFFIX; - *op_string += 8; - return WORD_PTR; - } - - else if (!strncasecmp (*op_string, "DWORD PTR", 9)) - { - if (got_a_float == 1) /* "f..." */ - i.suffix = SHORT_MNEM_SUFFIX; - else - i.suffix = LONG_MNEM_SUFFIX; - *op_string += 9; - return DWORD_PTR; - } - - else if (!strncasecmp (*op_string, "QWORD PTR", 9)) - { - i.suffix = DWORD_MNEM_SUFFIX; - *op_string += 9; - return QWORD_PTR; - } - - else if (!strncasecmp (*op_string, "XWORD PTR", 9)) - { - i.suffix = LONG_DOUBLE_MNEM_SUFFIX; - *op_string += 9; - return XWORD_PTR; - } - - else if (!strncasecmp (*op_string, "SHORT", 5)) - { - *op_string += 5; - return SHORT; - } - - else if (!strncasecmp (*op_string, "OFFSET FLAT:", 12)) - { - *op_string += 12; - return OFFSET_FLAT; - } - - else if (!strncasecmp (*op_string, "FLAT", 4)) - { - *op_string += 4; - return FLAT; - } - - else return NONE_FOUND; -} - -static char * build_displacement_string PARAMS ((int, char *)); - -static char * -build_displacement_string (initial_disp, op_string) - int initial_disp; - char *op_string; -{ - char *temp_string = (char *) malloc (strlen (op_string) + 1); - char *end_of_operand_string; - char *tc; - char *temp_disp; - - temp_string[0] = '\0'; - tc = end_of_operand_string = strchr (op_string, '['); - if (initial_disp && !end_of_operand_string) - { - strcpy (temp_string, op_string); - return temp_string; - } - - /* Build the whole displacement string */ - if (initial_disp) - { - strncpy (temp_string, op_string, end_of_operand_string - op_string); - temp_string[end_of_operand_string - op_string] = '\0'; - temp_disp = tc; - } - else - temp_disp = op_string; - - while (*temp_disp != '\0') - { - char *end_op; - int add_minus = (*temp_disp == '-'); - - if (*temp_disp == '+' || *temp_disp == '-' || *temp_disp == '[') - temp_disp++; - - if (is_space_char (*temp_disp)) - temp_disp++; - - /* Don't consider registers */ - if ( !((*temp_disp == REGISTER_PREFIX || allow_naked_reg) - && parse_register (temp_disp, &end_op)) ) - { - char *string_start = temp_disp; - - while (*temp_disp != ']' - && *temp_disp != '+' - && *temp_disp != '-' - && *temp_disp != '*') - ++temp_disp; - - if (add_minus) - strcat (temp_string, "-"); - else - strcat (temp_string, "+"); - - strncat (temp_string, string_start, temp_disp - string_start); - if (*temp_disp == '+' || *temp_disp == '-') - --temp_disp; - } - - while (*temp_disp != '\0' - && *temp_disp != '+' - && *temp_disp != '-') - ++temp_disp; - } - - return temp_string; -} - -static int i386_parse_seg PARAMS ((char *)); - -static int -i386_parse_seg (op_string) - char *op_string; -{ - if (is_space_char (*op_string)) - ++op_string; - - /* Should be one of es, cs, ss, ds fs or gs */ - switch (*op_string++) - { - case 'e': - i.seg[i.mem_operands] = &es; - break; - case 'c': - i.seg[i.mem_operands] = &cs; - break; - case 's': - i.seg[i.mem_operands] = &ss; - break; - case 'd': - i.seg[i.mem_operands] = &ds; - break; - case 'f': - i.seg[i.mem_operands] = &fs; - break; - case 'g': - i.seg[i.mem_operands] = &gs; - break; - default: - as_bad (_("bad segment name `%s'"), op_string); - return 0; - } - - if (*op_string++ != 's') - { - as_bad (_("bad segment name `%s'"), op_string); - return 0; - } - - if (is_space_char (*op_string)) - ++op_string; - - if (*op_string != ':') - { - as_bad (_("bad segment name `%s'"), op_string); - return 0; - } - - return 1; - -} - -static int i386_index_check PARAMS((const char *)); - -/* Make sure the memory operand we've been dealt is valid. - Returns 1 on success, 0 on a failure. -*/ -static int -i386_index_check (operand_string) - const char *operand_string; -{ -#if INFER_ADDR_PREFIX - int fudged = 0; - - tryprefix: -#endif - if (flag_16bit_code ^ (i.prefix[ADDR_PREFIX] != 0) - /* 16 bit mode checks */ - ? ((i.base_reg - && ((i.base_reg->reg_type & (Reg16|BaseIndex)) - != (Reg16|BaseIndex))) - || (i.index_reg - && (((i.index_reg->reg_type & (Reg16|BaseIndex)) - != (Reg16|BaseIndex)) - || ! (i.base_reg - && i.base_reg->reg_num < 6 - && i.index_reg->reg_num >= 6 - && i.log2_scale_factor == 0)))) - /* 32 bit mode checks */ - : ((i.base_reg - && (i.base_reg->reg_type & Reg32) == 0) - || (i.index_reg - && ((i.index_reg->reg_type & (Reg32|BaseIndex)) - != (Reg32|BaseIndex))))) - { -#if INFER_ADDR_PREFIX - if (i.prefix[ADDR_PREFIX] == 0 && stackop_size != '\0') - { - i.prefix[ADDR_PREFIX] = ADDR_PREFIX_OPCODE; - i.prefixes += 1; - /* Change the size of any displacement too. At most one of - Disp16 or Disp32 is set. - FIXME. There doesn't seem to be any real need for separate - Disp16 and Disp32 flags. The same goes for Imm16 and Imm32. - Removing them would probably clean up the code quite a lot. - */ - if (i.types[this_operand] & (Disp16|Disp32)) - i.types[this_operand] ^= (Disp16|Disp32); - fudged = 1; - goto tryprefix; - } - if (fudged) - as_bad (_("`%s' is not a valid base/index expression"), - operand_string); - else -#endif - as_bad (_("`%s' is not a valid %s bit base/index expression"), - operand_string, - flag_16bit_code ^ (i.prefix[ADDR_PREFIX] != 0) ? "16" : "32"); - return 0; - } - return 1; -} - -static int i386_intel_memory_operand PARAMS ((char *)); - -static int -i386_intel_memory_operand (operand_string) - char *operand_string; -{ - char *op_string = operand_string; - char *end_of_operand_string; - - if ((i.mem_operands == 1 - && (current_templates->start->opcode_modifier & IsString) == 0) - || i.mem_operands == 2) - { - as_bad (_("too many memory references for `%s'"), - current_templates->start->name); - return 0; - } - - /* First check for a segment override. */ - if (*op_string != '[') - { - char *end_seg; - - end_seg = strchr (op_string, ':'); - if (end_seg) - { - if (!i386_parse_seg (op_string)) - return 0; - op_string = end_seg + 1; - } - } - - /* Look for displacement preceding open bracket */ - if (*op_string != '[') - { - char *temp_string; - - if (i.disp_operands) - return 0; - - temp_string = build_displacement_string (true, op_string); - - if (!i386_displacement (temp_string, temp_string + strlen (temp_string))) - { - free (temp_string); - return 0; - } - free (temp_string); - - end_of_operand_string = strchr (op_string, '['); - if (!end_of_operand_string) - end_of_operand_string = op_string + strlen (op_string); - - if (is_space_char (*end_of_operand_string)) - --end_of_operand_string; - - op_string = end_of_operand_string; - } - - if (*op_string == '[') - { - ++op_string; - - /* Pick off each component and figure out where it belongs */ - - end_of_operand_string = op_string; - - while (*op_string != ']') - { - const reg_entry *temp_reg; - char *end_op; - char *temp_string; - - while (*end_of_operand_string != '+' - && *end_of_operand_string != '-' - && *end_of_operand_string != '*' - && *end_of_operand_string != ']') - end_of_operand_string++; - - temp_string = op_string; - if (*temp_string == '+') - { - ++temp_string; - if (is_space_char (*temp_string)) - ++temp_string; - } - - if ((*temp_string == REGISTER_PREFIX || allow_naked_reg) - && (temp_reg = parse_register (temp_string, &end_op)) != NULL) - { - if (i.base_reg == NULL) - i.base_reg = temp_reg; - else - i.index_reg = temp_reg; - - i.types[this_operand] |= BaseIndex; - } - else if (*temp_string == REGISTER_PREFIX) - { - as_bad (_("bad register name `%s'"), temp_string); - return 0; - } - else if (is_digit_char (*op_string) - || *op_string == '+' || *op_string == '-') - { - char *temp_str; - - if (i.disp_operands != 0) - return 0; - - temp_string = build_displacement_string (false, op_string); - - temp_str = temp_string; - if (*temp_str == '+') - ++temp_str; - - if (!i386_displacement (temp_str, temp_str + strlen (temp_str))) - { - free (temp_string); - return 0; - } - free (temp_string); - - ++op_string; - end_of_operand_string = op_string; - while (*end_of_operand_string != ']' - && *end_of_operand_string != '+' - && *end_of_operand_string != '-' - && *end_of_operand_string != '*') - ++end_of_operand_string; - } - else if (*op_string == '*') - { - ++op_string; - - if (i.base_reg && !i.index_reg) - { - i.index_reg = i.base_reg; - i.base_reg = 0; - } - - if (!i386_scale (op_string)) - return 0; - } - op_string = end_of_operand_string; - ++end_of_operand_string; - } - } - - if (i386_index_check (operand_string) == 0) - return 0; - - i.mem_operands++; - return 1; -} - -static int -i386_intel_operand (operand_string, got_a_float) - char *operand_string; - int got_a_float; -{ - const reg_entry * r; - char *end_op; - char *op_string = operand_string; - - int operand_modifier = i386_operand_modifier (&op_string, got_a_float); - if (is_space_char (*op_string)) - ++op_string; - - switch (operand_modifier) - { - case BYTE_PTR: - case WORD_PTR: - case DWORD_PTR: - case QWORD_PTR: - case XWORD_PTR: - if (!i386_intel_memory_operand (op_string)) - return 0; - break; - - case FLAT: - case OFFSET_FLAT: - if (!i386_immediate (op_string)) - return 0; - break; - - case SHORT: - case NONE_FOUND: - /* Should be register or immediate */ - if (is_digit_char (*op_string) - && strchr (op_string, '[') == 0) - { - if (!i386_immediate (op_string)) - return 0; - } - else if ((*op_string == REGISTER_PREFIX || allow_naked_reg) - && (r = parse_register (op_string, &end_op)) != NULL) - { - /* Check for a segment override by searching for ':' after a - segment register. */ - op_string = end_op; - if (is_space_char (*op_string)) - ++op_string; - if (*op_string == ':' && (r->reg_type & (SReg2 | SReg3))) - { - switch (r->reg_num) - { - case 0: - i.seg[i.mem_operands] = &es; - break; - case 1: - i.seg[i.mem_operands] = &cs; - break; - case 2: - i.seg[i.mem_operands] = &ss; - break; - case 3: - i.seg[i.mem_operands] = &ds; - break; - case 4: - i.seg[i.mem_operands] = &fs; - break; - case 5: - i.seg[i.mem_operands] = &gs; - break; - } - - } - i.types[this_operand] |= r->reg_type & ~BaseIndex; - i.op[this_operand].regs = r; - i.reg_operands++; - } - else if (*op_string == REGISTER_PREFIX) - { - as_bad (_("bad register name `%s'"), op_string); - return 0; - } - else if (!i386_intel_memory_operand (op_string)) - return 0; - - break; - } /* end switch */ - - return 1; -} - -/* Parse OPERAND_STRING into the i386_insn structure I. Returns non-zero - on error. */ - -static int -i386_operand (operand_string) - char *operand_string; -{ - const reg_entry *r; - char *end_op; - char *op_string = operand_string; - - if (is_space_char (*op_string)) - ++op_string; - - /* We check for an absolute prefix (differentiating, - for example, 'jmp pc_relative_label' from 'jmp *absolute_label'. */ - if (*op_string == ABSOLUTE_PREFIX) - { - ++op_string; - if (is_space_char (*op_string)) - ++op_string; - i.types[this_operand] |= JumpAbsolute; - } - - /* Check if operand is a register. */ - if ((*op_string == REGISTER_PREFIX || allow_naked_reg) - && (r = parse_register (op_string, &end_op)) != NULL) - { - /* Check for a segment override by searching for ':' after a - segment register. */ - op_string = end_op; - if (is_space_char (*op_string)) - ++op_string; - if (*op_string == ':' && (r->reg_type & (SReg2 | SReg3))) - { - switch (r->reg_num) - { - case 0: - i.seg[i.mem_operands] = &es; - break; - case 1: - i.seg[i.mem_operands] = &cs; - break; - case 2: - i.seg[i.mem_operands] = &ss; - break; - case 3: - i.seg[i.mem_operands] = &ds; - break; - case 4: - i.seg[i.mem_operands] = &fs; - break; - case 5: - i.seg[i.mem_operands] = &gs; - break; - } - - /* Skip the ':' and whitespace. */ - ++op_string; - if (is_space_char (*op_string)) - ++op_string; - - if (!is_digit_char (*op_string) - && !is_identifier_char (*op_string) - && *op_string != '(' - && *op_string != ABSOLUTE_PREFIX) - { - as_bad (_("bad memory operand `%s'"), op_string); - return 0; - } - /* Handle case of %es:*foo. */ - if (*op_string == ABSOLUTE_PREFIX) - { - ++op_string; - if (is_space_char (*op_string)) - ++op_string; - i.types[this_operand] |= JumpAbsolute; - } - goto do_memory_reference; - } - if (*op_string) - { - as_bad (_("junk `%s' after register"), op_string); - return 0; - } - i.types[this_operand] |= r->reg_type & ~BaseIndex; - i.op[this_operand].regs = r; - i.reg_operands++; - } - else if (*op_string == REGISTER_PREFIX) - { - as_bad (_("bad register name `%s'"), op_string); - return 0; - } - else if (*op_string == IMMEDIATE_PREFIX) - { /* ... or an immediate */ - ++op_string; - if (i.types[this_operand] & JumpAbsolute) - { - as_bad (_("immediate operand illegal with absolute jump")); - return 0; - } - if (!i386_immediate (op_string)) - return 0; - } - else if (is_digit_char (*op_string) - || is_identifier_char (*op_string) - || *op_string == '(' ) - { - /* This is a memory reference of some sort. */ - char *base_string; - - /* Start and end of displacement string expression (if found). */ - char *displacement_string_start; - char *displacement_string_end; - - do_memory_reference: - if ((i.mem_operands == 1 - && (current_templates->start->opcode_modifier & IsString) == 0) - || i.mem_operands == 2) - { - as_bad (_("too many memory references for `%s'"), - current_templates->start->name); - return 0; - } - - /* Check for base index form. We detect the base index form by - looking for an ')' at the end of the operand, searching - for the '(' matching it, and finding a REGISTER_PREFIX or ',' - after the '('. */ - base_string = op_string + strlen (op_string); - - --base_string; - if (is_space_char (*base_string)) - --base_string; - - /* If we only have a displacement, set-up for it to be parsed later. */ - displacement_string_start = op_string; - displacement_string_end = base_string + 1; - - if (*base_string == ')') - { - char *temp_string; - unsigned int parens_balanced = 1; - /* We've already checked that the number of left & right ()'s are - equal, so this loop will not be infinite. */ - do - { - base_string--; - if (*base_string == ')') - parens_balanced++; - if (*base_string == '(') - parens_balanced--; - } - while (parens_balanced); - - temp_string = base_string; - - /* Skip past '(' and whitespace. */ - ++base_string; - if (is_space_char (*base_string)) - ++base_string; - - if (*base_string == ',' - || ((*base_string == REGISTER_PREFIX || allow_naked_reg) - && (i.base_reg = parse_register (base_string, &end_op)) != NULL)) - { - displacement_string_end = temp_string; - - i.types[this_operand] |= BaseIndex; - - if (i.base_reg) - { - base_string = end_op; - if (is_space_char (*base_string)) - ++base_string; - } - - /* There may be an index reg or scale factor here. */ - if (*base_string == ',') - { - ++base_string; - if (is_space_char (*base_string)) - ++base_string; - - if ((*base_string == REGISTER_PREFIX || allow_naked_reg) - && (i.index_reg = parse_register (base_string, &end_op)) != NULL) - { - base_string = end_op; - if (is_space_char (*base_string)) - ++base_string; - if (*base_string == ',') - { - ++base_string; - if (is_space_char (*base_string)) - ++base_string; - } - else if (*base_string != ')' ) - { - as_bad (_("expecting `,' or `)' after index register in `%s'"), - operand_string); - return 0; - } - } - else if (*base_string == REGISTER_PREFIX) - { - as_bad (_("bad register name `%s'"), base_string); - return 0; - } - - /* Check for scale factor. */ - if (isdigit ((unsigned char) *base_string)) - { - if (!i386_scale (base_string)) - return 0; - - ++base_string; - if (is_space_char (*base_string)) - ++base_string; - if (*base_string != ')') - { - as_bad (_("expecting `)' after scale factor in `%s'"), - operand_string); - return 0; - } - } - else if (!i.index_reg) - { - as_bad (_("expecting index register or scale factor after `,'; got '%c'"), - *base_string); - return 0; - } - } - else if (*base_string != ')') - { - as_bad (_("expecting `,' or `)' after base register in `%s'"), - operand_string); - return 0; - } - } - else if (*base_string == REGISTER_PREFIX) - { - as_bad (_("bad register name `%s'"), base_string); - return 0; - } - } - - /* If there's an expression beginning the operand, parse it, - assuming displacement_string_start and - displacement_string_end are meaningful. */ - if (displacement_string_start != displacement_string_end) - { - if (!i386_displacement (displacement_string_start, - displacement_string_end)) - return 0; - } - - /* Special case for (%dx) while doing input/output op. */ - if (i.base_reg - && i.base_reg->reg_type == (Reg16 | InOutPortReg) - && i.index_reg == 0 - && i.log2_scale_factor == 0 - && i.seg[i.mem_operands] == 0 - && (i.types[this_operand] & Disp) == 0) - { - i.types[this_operand] = InOutPortReg; - return 1; - } - - if (i386_index_check (operand_string) == 0) - return 0; - i.mem_operands++; - } - else - { /* it's not a memory operand; argh! */ - as_bad (_("invalid char %s beginning operand %d `%s'"), - output_invalid (*op_string), - this_operand + 1, - op_string); - return 0; - } - return 1; /* normal return */ -} - -/* - * md_estimate_size_before_relax() - * - * Called just before relax(). - * Any symbol that is now undefined will not become defined. - * Return the correct fr_subtype in the frag. - * Return the initial "guess for fr_var" to caller. - * The guess for fr_var is ACTUALLY the growth beyond fr_fix. - * Whatever we do to grow fr_fix or fr_var contributes to our returned value. - * Although it may not be explicit in the frag, pretend fr_var starts with a - * 0 value. - */ -int -md_estimate_size_before_relax (fragP, segment) - register fragS *fragP; - register segT segment; -{ - register unsigned char *opcode; - register int old_fr_fix; - - old_fr_fix = fragP->fr_fix; - opcode = (unsigned char *) fragP->fr_opcode; - /* We've already got fragP->fr_subtype right; all we have to do is - check for un-relaxable symbols. */ - if (S_GET_SEGMENT (fragP->fr_symbol) != segment) - { - /* symbol is undefined in this segment */ - int code16 = fragP->fr_subtype & CODE16; - int size = code16 ? 2 : 4; -#ifdef BFD_ASSEMBLER - enum bfd_reloc_code_real reloc_type; -#else - int reloc_type; -#endif - - if (GOT_symbol /* Not quite right - we should switch on presence of - @PLT, but I cannot see how to get to that from - here. We should have done this in md_assemble to - really get it right all of the time, but I think it - does not matter that much, as this will be right - most of the time. ERY */ - && S_GET_SEGMENT(fragP->fr_symbol) == undefined_section) - reloc_type = BFD_RELOC_386_PLT32; - else if (code16) - reloc_type = BFD_RELOC_16_PCREL; - else - reloc_type = BFD_RELOC_32_PCREL; - - switch (opcode[0]) - { - case JUMP_PC_RELATIVE: /* make jmp (0xeb) a dword displacement jump */ - opcode[0] = 0xe9; /* dword disp jmp */ - fragP->fr_fix += size; - fix_new (fragP, old_fr_fix, size, - fragP->fr_symbol, - fragP->fr_offset, 1, - reloc_type); - break; - - default: - /* This changes the byte-displacement jump 0x7N - to the dword-displacement jump 0x0f,0x8N. */ - opcode[1] = opcode[0] + 0x10; - opcode[0] = TWO_BYTE_OPCODE_ESCAPE; - fragP->fr_fix += 1 + size; /* we've added an opcode byte */ - fix_new (fragP, old_fr_fix + 1, size, - fragP->fr_symbol, - fragP->fr_offset, 1, - reloc_type); - break; - } - frag_wane (fragP); - } - return (fragP->fr_var + fragP->fr_fix - old_fr_fix); -} /* md_estimate_size_before_relax() */ - -/* - * md_convert_frag(); - * - * Called after relax() is finished. - * In: Address of frag. - * fr_type == rs_machine_dependent. - * fr_subtype is what the address relaxed to. - * - * Out: Any fixSs and constants are set up. - * Caller will turn frag into a ".space 0". - */ -#ifndef BFD_ASSEMBLER -void -md_convert_frag (headers, sec, fragP) - object_headers *headers ATTRIBUTE_UNUSED; - segT sec ATTRIBUTE_UNUSED; - register fragS *fragP; -#else -void -md_convert_frag (abfd, sec, fragP) - bfd *abfd ATTRIBUTE_UNUSED; - segT sec ATTRIBUTE_UNUSED; - register fragS *fragP; -#endif -{ - register unsigned char *opcode; - unsigned char *where_to_put_displacement = NULL; - unsigned int target_address; - unsigned int opcode_address; - unsigned int extension = 0; - int displacement_from_opcode_start; - - opcode = (unsigned char *) fragP->fr_opcode; - - /* Address we want to reach in file space. */ - target_address = S_GET_VALUE (fragP->fr_symbol) + fragP->fr_offset; -#ifdef BFD_ASSEMBLER /* not needed otherwise? */ - target_address += symbol_get_frag (fragP->fr_symbol)->fr_address; -#endif - - /* Address opcode resides at in file space. */ - opcode_address = fragP->fr_address + fragP->fr_fix; - - /* Displacement from opcode start to fill into instruction. */ - displacement_from_opcode_start = target_address - opcode_address; - - switch (fragP->fr_subtype) - { - case ENCODE_RELAX_STATE (COND_JUMP, SMALL): - case ENCODE_RELAX_STATE (COND_JUMP, SMALL16): - case ENCODE_RELAX_STATE (UNCOND_JUMP, SMALL): - case ENCODE_RELAX_STATE (UNCOND_JUMP, SMALL16): - /* don't have to change opcode */ - extension = 1; /* 1 opcode + 1 displacement */ - where_to_put_displacement = &opcode[1]; - break; - - case ENCODE_RELAX_STATE (COND_JUMP, BIG): - extension = 5; /* 2 opcode + 4 displacement */ - opcode[1] = opcode[0] + 0x10; - opcode[0] = TWO_BYTE_OPCODE_ESCAPE; - where_to_put_displacement = &opcode[2]; - break; - - case ENCODE_RELAX_STATE (UNCOND_JUMP, BIG): - extension = 4; /* 1 opcode + 4 displacement */ - opcode[0] = 0xe9; - where_to_put_displacement = &opcode[1]; - break; - - case ENCODE_RELAX_STATE (COND_JUMP, BIG16): - extension = 3; /* 2 opcode + 2 displacement */ - opcode[1] = opcode[0] + 0x10; - opcode[0] = TWO_BYTE_OPCODE_ESCAPE; - where_to_put_displacement = &opcode[2]; - break; - - case ENCODE_RELAX_STATE (UNCOND_JUMP, BIG16): - extension = 2; /* 1 opcode + 2 displacement */ - opcode[0] = 0xe9; - where_to_put_displacement = &opcode[1]; - break; - - default: - BAD_CASE (fragP->fr_subtype); - break; - } - /* now put displacement after opcode */ - md_number_to_chars ((char *) where_to_put_displacement, - (valueT) (displacement_from_opcode_start - extension), - SIZE_FROM_RELAX_STATE (fragP->fr_subtype)); - fragP->fr_fix += extension; -} - - -int md_short_jump_size = 2; /* size of byte displacement jmp */ -int md_long_jump_size = 5; /* size of dword displacement jmp */ -const int md_reloc_size = 8; /* Size of relocation record */ - -void -md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol) - char *ptr; - addressT from_addr, to_addr; - fragS *frag ATTRIBUTE_UNUSED; - symbolS *to_symbol ATTRIBUTE_UNUSED; -{ - long offset; - - offset = to_addr - (from_addr + 2); - md_number_to_chars (ptr, (valueT) 0xeb, 1); /* opcode for byte-disp jump */ - md_number_to_chars (ptr + 1, (valueT) offset, 1); -} - -void -md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol) - char *ptr; - addressT from_addr, to_addr; - fragS *frag; - symbolS *to_symbol; -{ - long offset; - - if (flag_do_long_jump) - { - offset = to_addr - S_GET_VALUE (to_symbol); - md_number_to_chars (ptr, (valueT) 0xe9, 1);/* opcode for long jmp */ - md_number_to_chars (ptr + 1, (valueT) offset, 4); - fix_new (frag, (ptr + 1) - frag->fr_literal, 4, - to_symbol, (offsetT) 0, 0, BFD_RELOC_32); - } - else - { - offset = to_addr - (from_addr + 5); - md_number_to_chars (ptr, (valueT) 0xe9, 1); - md_number_to_chars (ptr + 1, (valueT) offset, 4); - } -} - -/* Apply a fixup (fixS) to segment data, once it has been determined - by our caller that we have all the info we need to fix it up. - - On the 386, immediates, displacements, and data pointers are all in - the same (little-endian) format, so we don't need to care about which - we are handling. */ - -int -md_apply_fix3 (fixP, valp, seg) - fixS *fixP; /* The fix we're to put in. */ - valueT *valp; /* Pointer to the value of the bits. */ - segT seg ATTRIBUTE_UNUSED; /* Segment fix is from. */ -{ - register char *p = fixP->fx_where + fixP->fx_frag->fr_literal; - valueT value = *valp; - -#if defined (BFD_ASSEMBLER) && !defined (TE_Mach) - if (fixP->fx_pcrel) - { - switch (fixP->fx_r_type) - { - default: - break; - - case BFD_RELOC_32: - fixP->fx_r_type = BFD_RELOC_32_PCREL; - break; - case BFD_RELOC_16: - fixP->fx_r_type = BFD_RELOC_16_PCREL; - break; - case BFD_RELOC_8: - fixP->fx_r_type = BFD_RELOC_8_PCREL; - break; - } - } - - /* This is a hack. There should be a better way to handle this. - This covers for the fact that bfd_install_relocation will - subtract the current location (for partial_inplace, PC relative - relocations); see more below. */ - if ((fixP->fx_r_type == BFD_RELOC_32_PCREL - || fixP->fx_r_type == BFD_RELOC_16_PCREL - || fixP->fx_r_type == BFD_RELOC_8_PCREL) - && fixP->fx_addsy) - { -#ifndef OBJ_AOUT - if (OUTPUT_FLAVOR == bfd_target_elf_flavour -#ifdef TE_PE - || OUTPUT_FLAVOR == bfd_target_coff_flavour -#endif - ) - value += fixP->fx_where + fixP->fx_frag->fr_address; -#endif -#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) - if (OUTPUT_FLAVOR == bfd_target_elf_flavour) - { - segT fseg = S_GET_SEGMENT (fixP->fx_addsy); - - if ((fseg == seg - || (symbol_section_p (fixP->fx_addsy) - && fseg != absolute_section)) - && ! S_IS_EXTERNAL (fixP->fx_addsy) - && ! S_IS_WEAK (fixP->fx_addsy) - && S_IS_DEFINED (fixP->fx_addsy) - && ! S_IS_COMMON (fixP->fx_addsy)) - { - /* Yes, we add the values in twice. This is because - bfd_perform_relocation subtracts them out again. I think - bfd_perform_relocation is broken, but I don't dare change - it. FIXME. */ - value += fixP->fx_where + fixP->fx_frag->fr_address; - } - } -#endif -#if defined (OBJ_COFF) && defined (TE_PE) - /* For some reason, the PE format does not store a section - address offset for a PC relative symbol. */ - if (S_GET_SEGMENT (fixP->fx_addsy) != seg) - value += md_pcrel_from (fixP); - else if (S_IS_EXTERNAL (fixP->fx_addsy) - || S_IS_WEAK (fixP->fx_addsy)) - { - /* We are generating an external relocation for this defined - symbol. We add the address, because - bfd_install_relocation will subtract it. VALUE already - holds the symbol value, because fixup_segment added it - in. We subtract it out, and then we subtract it out - again because bfd_install_relocation will add it in - again. */ - value += md_pcrel_from (fixP); - value -= 2 * S_GET_VALUE (fixP->fx_addsy); - } -#endif - } -#ifdef TE_PE - else if (fixP->fx_addsy != NULL - && S_IS_DEFINED (fixP->fx_addsy) - && (S_IS_EXTERNAL (fixP->fx_addsy) - || S_IS_WEAK (fixP->fx_addsy))) - { - /* We are generating an external relocation for this defined - symbol. VALUE already holds the symbol value, and - bfd_install_relocation will add it in again. We don't want - either addition. */ - value -= 2 * S_GET_VALUE (fixP->fx_addsy); - } -#endif - - /* Fix a few things - the dynamic linker expects certain values here, - and we must not dissappoint it. */ -#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) - if (OUTPUT_FLAVOR == bfd_target_elf_flavour - && fixP->fx_addsy) - switch (fixP->fx_r_type) { - case BFD_RELOC_386_PLT32: - /* Make the jump instruction point to the address of the operand. At - runtime we merely add the offset to the actual PLT entry. */ - value = 0xfffffffc; - break; - case BFD_RELOC_386_GOTPC: -/* - * This is tough to explain. We end up with this one if we have - * operands that look like "_GLOBAL_OFFSET_TABLE_+[.-.L284]". The goal - * here is to obtain the absolute address of the GOT, and it is strongly - * preferable from a performance point of view to avoid using a runtime - * relocation for this. The actual sequence of instructions often look - * something like: - * - * call .L66 - * .L66: - * popl %ebx - * addl $_GLOBAL_OFFSET_TABLE_+[.-.L66],%ebx - * - * The call and pop essentially return the absolute address of - * the label .L66 and store it in %ebx. The linker itself will - * ultimately change the first operand of the addl so that %ebx points to - * the GOT, but to keep things simple, the .o file must have this operand - * set so that it generates not the absolute address of .L66, but the - * absolute address of itself. This allows the linker itself simply - * treat a GOTPC relocation as asking for a pcrel offset to the GOT to be - * added in, and the addend of the relocation is stored in the operand - * field for the instruction itself. - * - * Our job here is to fix the operand so that it would add the correct - * offset so that %ebx would point to itself. The thing that is tricky is - * that .-.L66 will point to the beginning of the instruction, so we need - * to further modify the operand so that it will point to itself. - * There are other cases where you have something like: - * - * .long $_GLOBAL_OFFSET_TABLE_+[.-.L66] - * - * and here no correction would be required. Internally in the assembler - * we treat operands of this form as not being pcrel since the '.' is - * explicitly mentioned, and I wonder whether it would simplify matters - * to do it this way. Who knows. In earlier versions of the PIC patches, - * the pcrel_adjust field was used to store the correction, but since the - * expression is not pcrel, I felt it would be confusing to do it this way. - */ - value -= 1; - break; - case BFD_RELOC_386_GOT32: - value = 0; /* Fully resolved at runtime. No addend. */ - break; - case BFD_RELOC_386_GOTOFF: - break; - - case BFD_RELOC_VTABLE_INHERIT: - case BFD_RELOC_VTABLE_ENTRY: - fixP->fx_done = 0; - return 1; - - default: - break; - } -#endif /* defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) */ - *valp = value; -#endif /* defined (BFD_ASSEMBLER) && !defined (TE_Mach) */ - md_number_to_chars (p, value, fixP->fx_size); - - return 1; -} - -#if 0 -/* This is never used. */ -long /* Knows about the byte order in a word. */ -md_chars_to_number (con, nbytes) - unsigned char con[]; /* Low order byte 1st. */ - int nbytes; /* Number of bytes in the input. */ -{ - long retval; - for (retval = 0, con += nbytes - 1; nbytes--; con--) - { - retval <<= BITS_PER_CHAR; - retval |= *con; - } - return retval; -} -#endif /* 0 */ - - -#define MAX_LITTLENUMS 6 - -/* Turn the string pointed to by litP into a floating point constant of type - type, and emit the appropriate bytes. The number of LITTLENUMS emitted - is stored in *sizeP . An error message is returned, or NULL on OK. */ -char * -md_atof (type, litP, sizeP) - int type; - char *litP; - int *sizeP; -{ - int prec; - LITTLENUM_TYPE words[MAX_LITTLENUMS]; - LITTLENUM_TYPE *wordP; - char *t; - - switch (type) - { - case 'f': - case 'F': - prec = 2; - break; - - case 'd': - case 'D': - prec = 4; - break; - - case 'x': - case 'X': - prec = 5; - break; - - default: - *sizeP = 0; - return _("Bad call to md_atof ()"); - } - t = atof_ieee (input_line_pointer, type, words); - if (t) - input_line_pointer = t; - - *sizeP = prec * sizeof (LITTLENUM_TYPE); - /* This loops outputs the LITTLENUMs in REVERSE order; in accord with - the bigendian 386. */ - for (wordP = words + prec - 1; prec--;) - { - md_number_to_chars (litP, (valueT) (*wordP--), sizeof (LITTLENUM_TYPE)); - litP += sizeof (LITTLENUM_TYPE); - } - return 0; -} - -char output_invalid_buf[8]; - -static char * output_invalid PARAMS ((int)); - -static char * -output_invalid (c) - int c; -{ - if (isprint (c)) - sprintf (output_invalid_buf, "'%c'", c); - else - sprintf (output_invalid_buf, "(0x%x)", (unsigned) c); - return output_invalid_buf; -} - - -/* REG_STRING starts *before* REGISTER_PREFIX. */ - -static const reg_entry * -parse_register (reg_string, end_op) - char *reg_string; - char **end_op; -{ - char *s = reg_string; - char *p; - char reg_name_given[MAX_REG_NAME_SIZE + 1]; - const reg_entry *r; - - /* Skip possible REGISTER_PREFIX and possible whitespace. */ - if (*s == REGISTER_PREFIX) - ++s; - - if (is_space_char (*s)) - ++s; - - p = reg_name_given; - while ((*p++ = register_chars[(unsigned char) *s]) != '\0') - { - if (p >= reg_name_given + MAX_REG_NAME_SIZE) - return (const reg_entry *) NULL; - s++; - } - - *end_op = s; - - r = (const reg_entry *) hash_find (reg_hash, reg_name_given); - - /* Handle floating point regs, allowing spaces in the (i) part. */ - if (r == i386_regtab /* %st is first entry of table */) - { - if (is_space_char (*s)) - ++s; - if (*s == '(') - { - ++s; - if (is_space_char (*s)) - ++s; - if (*s >= '0' && *s <= '7') - { - r = &i386_float_regtab[*s - '0']; - ++s; - if (is_space_char (*s)) - ++s; - if (*s == ')') - { - *end_op = s + 1; - return r; - } - } - /* We have "%st(" then garbage */ - return (const reg_entry *) NULL; - } - } - - return r; -} - -#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) -CONST char *md_shortopts = "kmVQ:sq"; -#else -CONST char *md_shortopts = "m"; -#endif -struct option md_longopts[] = { - {NULL, no_argument, NULL, 0} -}; -size_t md_longopts_size = sizeof (md_longopts); - -int -md_parse_option (c, arg) - int c; - char *arg ATTRIBUTE_UNUSED; -{ - switch (c) - { - case 'm': - flag_do_long_jump = 1; - break; - -#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) - /* -k: Ignore for FreeBSD compatibility. */ - case 'k': - break; - - /* -V: SVR4 argument to print version ID. */ - case 'V': - print_version_id (); - break; - - /* -Qy, -Qn: SVR4 arguments controlling whether a .comment section - should be emitted or not. FIXME: Not implemented. */ - case 'Q': - break; - - case 's': - /* -s: On i386 Solaris, this tells the native assembler to use - .stab instead of .stab.excl. We always use .stab anyhow. */ - break; - - case 'q': - /* -q: On i386 Solaris, this tells the native assembler does - fewer checks. */ - break; -#endif - - default: - return 0; - } - return 1; -} - -void -md_show_usage (stream) - FILE *stream; -{ - fprintf (stream, _("\ - -m do long jump\n")); -#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) - fprintf (stream, _("\ - -V print assembler version number\n\ - -k ignored\n\ - -Qy, -Qn ignored\n\ - -q ignored\n\ - -s ignored\n")); -#endif -} - -#ifdef BFD_ASSEMBLER -#if ((defined (OBJ_MAYBE_ELF) && defined (OBJ_MAYBE_COFF)) \ - || (defined (OBJ_MAYBE_ELF) && defined (OBJ_MAYBE_AOUT)) \ - || (defined (OBJ_MAYBE_COFF) && defined (OBJ_MAYBE_AOUT))) - -/* Pick the target format to use. */ - -const char * -i386_target_format () -{ - switch (OUTPUT_FLAVOR) - { -#ifdef OBJ_MAYBE_AOUT - case bfd_target_aout_flavour: - return AOUT_TARGET_FORMAT; -#endif -#ifdef OBJ_MAYBE_COFF - case bfd_target_coff_flavour: - return "coff-i386"; -#endif -#ifdef OBJ_MAYBE_ELF - case bfd_target_elf_flavour: - return "elf32-i386"; -#endif - default: - abort (); - return NULL; - } -} - -#endif /* OBJ_MAYBE_ more than one */ -#endif /* BFD_ASSEMBLER */ - -symbolS * -md_undefined_symbol (name) - char *name; -{ - if (name[0] == GLOBAL_OFFSET_TABLE_NAME[0] - && name[1] == GLOBAL_OFFSET_TABLE_NAME[1] - && name[2] == GLOBAL_OFFSET_TABLE_NAME[2] - && strcmp (name, GLOBAL_OFFSET_TABLE_NAME) == 0) - { - if (!GOT_symbol) - { - if (symbol_find (name)) - as_bad (_("GOT already in symbol table")); - GOT_symbol = symbol_new (name, undefined_section, - (valueT) 0, &zero_address_frag); - }; - return GOT_symbol; - } - return 0; -} - -/* Round up a section size to the appropriate boundary. */ -valueT -md_section_align (segment, size) - segT segment ATTRIBUTE_UNUSED; - valueT size; -{ -#ifdef BFD_ASSEMBLER -#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT)) - if (OUTPUT_FLAVOR == bfd_target_aout_flavour) - { - /* For a.out, force the section size to be aligned. If we don't do - this, BFD will align it for us, but it will not write out the - final bytes of the section. This may be a bug in BFD, but it is - easier to fix it here since that is how the other a.out targets - work. */ - int align; - - align = bfd_get_section_alignment (stdoutput, segment); - size = ((size + (1 << align) - 1) & ((valueT) -1 << align)); - } -#endif -#endif - - return size; -} - -/* On the i386, PC-relative offsets are relative to the start of the - next instruction. That is, the address of the offset, plus its - size, since the offset is always the last part of the insn. */ - -long -md_pcrel_from (fixP) - fixS *fixP; -{ - return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address; -} - -#ifndef I386COFF - -static void -s_bss (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - register int temp; - - temp = get_absolute_expression (); - subseg_set (bss_section, (subsegT) temp); - demand_empty_rest_of_line (); -} - -#endif - - -#ifdef BFD_ASSEMBLER - -void -i386_validate_fix (fixp) - fixS *fixp; -{ - if (fixp->fx_subsy && fixp->fx_subsy == GOT_symbol) - { - fixp->fx_r_type = BFD_RELOC_386_GOTOFF; - fixp->fx_subsy = 0; - } -} - -arelent * -tc_gen_reloc (section, fixp) - asection *section ATTRIBUTE_UNUSED; - fixS *fixp; -{ - arelent *rel; - bfd_reloc_code_real_type code; - - switch (fixp->fx_r_type) - { - case BFD_RELOC_386_PLT32: - case BFD_RELOC_386_GOT32: - case BFD_RELOC_386_GOTOFF: - case BFD_RELOC_386_GOTPC: - case BFD_RELOC_RVA: - case BFD_RELOC_VTABLE_ENTRY: - case BFD_RELOC_VTABLE_INHERIT: - code = fixp->fx_r_type; - break; - default: - if (fixp->fx_pcrel) - { - switch (fixp->fx_size) - { - default: - as_bad (_("can not do %d byte pc-relative relocation"), - fixp->fx_size); - code = BFD_RELOC_32_PCREL; - break; - case 1: code = BFD_RELOC_8_PCREL; break; - case 2: code = BFD_RELOC_16_PCREL; break; - case 4: code = BFD_RELOC_32_PCREL; break; - } - } - else - { - switch (fixp->fx_size) - { - default: - as_bad (_("can not do %d byte relocation"), fixp->fx_size); - code = BFD_RELOC_32; - break; - case 1: code = BFD_RELOC_8; break; - case 2: code = BFD_RELOC_16; break; - case 4: code = BFD_RELOC_32; break; - } - } - break; - } - - if (code == BFD_RELOC_32 - && GOT_symbol - && fixp->fx_addsy == GOT_symbol) - code = BFD_RELOC_386_GOTPC; - - rel = (arelent *) xmalloc (sizeof (arelent)); - rel->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); - *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); - - rel->address = fixp->fx_frag->fr_address + fixp->fx_where; - /* HACK: Since i386 ELF uses Rel instead of Rela, encode the - vtable entry to be used in the relocation's section offset. */ - if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY) - rel->address = fixp->fx_offset; - - if (fixp->fx_pcrel) - rel->addend = fixp->fx_addnumber; - else - rel->addend = 0; - - rel->howto = bfd_reloc_type_lookup (stdoutput, code); - if (rel->howto == NULL) - { - as_bad_where (fixp->fx_file, fixp->fx_line, - _("cannot represent relocation type %s"), - bfd_get_reloc_code_name (code)); - /* Set howto to a garbage value so that we can keep going. */ - rel->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32); - assert (rel->howto != NULL); - } - - return rel; -} - -#else /* ! BFD_ASSEMBLER */ - -#if (defined(OBJ_AOUT) | defined(OBJ_BOUT)) -void -tc_aout_fix_to_chars (where, fixP, segment_address_in_file) - char *where; - fixS *fixP; - relax_addressT segment_address_in_file; -{ - /* - * In: length of relocation (or of address) in chars: 1, 2 or 4. - * Out: GNU LD relocation length code: 0, 1, or 2. - */ - - static const unsigned char nbytes_r_length[] = {42, 0, 1, 42, 2}; - long r_symbolnum; - - know (fixP->fx_addsy != NULL); - - md_number_to_chars (where, - (valueT) (fixP->fx_frag->fr_address - + fixP->fx_where - segment_address_in_file), - 4); - - r_symbolnum = (S_IS_DEFINED (fixP->fx_addsy) - ? S_GET_TYPE (fixP->fx_addsy) - : fixP->fx_addsy->sy_number); - - where[6] = (r_symbolnum >> 16) & 0x0ff; - where[5] = (r_symbolnum >> 8) & 0x0ff; - where[4] = r_symbolnum & 0x0ff; - where[7] = ((((!S_IS_DEFINED (fixP->fx_addsy)) << 3) & 0x08) - | ((nbytes_r_length[fixP->fx_size] << 1) & 0x06) - | (((fixP->fx_pcrel << 0) & 0x01) & 0x0f)); -} - -#endif /* OBJ_AOUT or OBJ_BOUT */ - -#if defined (I386COFF) - -short -tc_coff_fix2rtype (fixP) - fixS *fixP; -{ - if (fixP->fx_r_type == R_IMAGEBASE) - return R_IMAGEBASE; - - return (fixP->fx_pcrel ? - (fixP->fx_size == 1 ? R_PCRBYTE : - fixP->fx_size == 2 ? R_PCRWORD : - R_PCRLONG) : - (fixP->fx_size == 1 ? R_RELBYTE : - fixP->fx_size == 2 ? R_RELWORD : - R_DIR32)); -} - -int -tc_coff_sizemachdep (frag) - fragS *frag; -{ - if (frag->fr_next) - return (frag->fr_next->fr_address - frag->fr_address); - else - return 0; -} - -#endif /* I386COFF */ - -#endif /* ! BFD_ASSEMBLER */ - -/* end of tc-i386.c */ diff --git a/contrib/binutils/gas/config/tc-i386.h b/contrib/binutils/gas/config/tc-i386.h deleted file mode 100644 index 2bf9a7f89cf08..0000000000000 --- a/contrib/binutils/gas/config/tc-i386.h +++ /dev/null @@ -1,479 +0,0 @@ -/* tc-i386.h -- Header file for tc-i386.c - Copyright (C) 1989, 92, 93, 94, 95, 96, 97, 98, 99, 2000 - Free Software Foundation. - - 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_I386 -#define TC_I386 1 - -#ifdef ANSI_PROTOTYPES -struct fix; -#endif - -#define TARGET_BYTES_BIG_ENDIAN 0 - -#ifdef TE_LYNX -#define TARGET_FORMAT "coff-i386-lynx" -#endif - -#ifdef BFD_ASSEMBLER -/* This is used to determine relocation types in tc-i386.c. The first - parameter is the current relocation type, the second one is the desired - type. The idea is that if the original type is already some kind of PIC - relocation, we leave it alone, otherwise we give it the desired type */ - -#define tc_fix_adjustable(X) tc_i386_fix_adjustable(X) -extern int tc_i386_fix_adjustable PARAMS ((struct fix *)); - -/* This is the relocation type for direct references to GLOBAL_OFFSET_TABLE. - * It comes up in complicated expressions such as - * _GLOBAL_OFFSET_TABLE_+[.-.L284], which cannot be expressed normally with - * the regular expressions. The fixup specified here when used at runtime - * implies that we should add the address of the GOT to the specified location, - * and as a result we have simplified the expression into something we can use. - */ -#define TC_RELOC_GLOBAL_OFFSET_TABLE BFD_RELOC_386_GOTPC - -/* 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. - This is only used for pcrel relocations, so GOTOFF does not need to be - checked here. I am not sure if some of the others are ever used with - pcrel, but it is easier to be safe than sorry. */ - -#define TC_RELOC_RTSYM_LOC_FIXUP(FIX) \ - ((FIX)->fx_r_type != BFD_RELOC_386_PLT32 \ - && (FIX)->fx_r_type != BFD_RELOC_386_GOT32 \ - && (FIX)->fx_r_type != BFD_RELOC_386_GOTPC \ - && ((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)))) - -#define TARGET_ARCH bfd_arch_i386 - -#ifdef TE_NetBSD -#define AOUT_TARGET_FORMAT "a.out-i386-netbsd" -#endif -#ifdef TE_386BSD -#define AOUT_TARGET_FORMAT "a.out-i386-bsd" -#endif -#ifdef TE_LINUX -#define AOUT_TARGET_FORMAT "a.out-i386-linux" -#endif -#ifdef TE_Mach -#define AOUT_TARGET_FORMAT "a.out-mach3" -#endif -#ifdef TE_DYNIX -#define AOUT_TARGET_FORMAT "a.out-i386-dynix" -#endif -#ifndef AOUT_TARGET_FORMAT -#define AOUT_TARGET_FORMAT "a.out-i386" -#endif - -#if ((defined (OBJ_MAYBE_ELF) && defined (OBJ_MAYBE_COFF)) \ - || (defined (OBJ_MAYBE_ELF) && defined (OBJ_MAYBE_AOUT)) \ - || (defined (OBJ_MAYBE_COFF) && defined (OBJ_MAYBE_AOUT))) -extern const char *i386_target_format PARAMS ((void)); -#define TARGET_FORMAT i386_target_format () -#else -#ifdef OBJ_ELF -#define TARGET_FORMAT "elf32-i386" -#endif -#ifdef OBJ_AOUT -#define TARGET_FORMAT AOUT_TARGET_FORMAT -#endif -#endif - -#else /* ! BFD_ASSEMBLER */ - -/* COFF STUFF */ - -#define COFF_MAGIC I386MAGIC -#define BFD_ARCH bfd_arch_i386 -#define COFF_FLAGS F_AR32WR -#define TC_COUNT_RELOC(x) ((x)->fx_addsy || (x)->fx_r_type==7) -#define TC_COFF_FIX2RTYPE(fixP) tc_coff_fix2rtype(fixP) -extern short tc_coff_fix2rtype PARAMS ((struct fix *)); -#define TC_COFF_SIZEMACHDEP(frag) tc_coff_sizemachdep(frag) -extern int tc_coff_sizemachdep PARAMS ((fragS *frag)); - -#ifdef TE_GO32 -/* DJGPP now expects some sections to be 2**4 aligned. */ -#define SUB_SEGMENT_ALIGN(SEG) \ - ((strcmp (obj_segment_name (SEG), ".text") == 0 \ - || strcmp (obj_segment_name (SEG), ".data") == 0 \ - || strcmp (obj_segment_name (SEG), ".bss") == 0 \ - || strncmp (obj_segment_name (SEG), ".gnu.linkonce.t", 15) == 0 \ - || strncmp (obj_segment_name (SEG), ".gnu.linkonce.d", 15) == 0 \ - || strncmp (obj_segment_name (SEG), ".gnu.linkonce.r", 15) == 0) \ - ? 4 \ - : 2) -#else -#define SUB_SEGMENT_ALIGN(SEG) 2 -#endif - -#define TC_RVA_RELOC 7 -/* Need this for PIC relocations */ -#define NEED_FX_R_TYPE - - -#ifdef TE_386BSD -/* The BSDI linker apparently rejects objects with a machine type of - M_386 (100). */ -#define AOUT_MACHTYPE 0 -#else -#define AOUT_MACHTYPE 100 -#endif - -#undef REVERSE_SORT_RELOCS - -#endif /* ! BFD_ASSEMBLER */ - -#define TC_FORCE_RELOCATION(fixp) tc_i386_force_relocation(fixp) -extern int tc_i386_force_relocation PARAMS ((struct fix *)); - -#ifdef BFD_ASSEMBLER -#define NO_RELOC BFD_RELOC_NONE -#else -#define NO_RELOC 0 -#endif -#define tc_coff_symbol_emit_hook(a) ; /* not used */ - -#ifndef BFD_ASSEMBLER -#ifndef OBJ_AOUT -#ifndef TE_PE -#ifndef TE_GO32 -/* Local labels starts with .L */ -#define LOCAL_LABEL(name) (name[0] == '.' \ - && (name[1] == 'L' || name[1] == 'X' || name[1] == '.')) -#endif -#endif -#endif -#endif - -#define LOCAL_LABELS_FB 1 - -#define tc_aout_pre_write_hook(x) {;} /* not used */ -#define tc_crawl_symbol_chain(a) {;} /* not used */ -#define tc_headers_hook(a) {;} /* not used */ - -extern const char extra_symbol_chars[]; -#define tc_symbol_chars extra_symbol_chars - -#define MAX_OPERANDS 3 /* max operands per insn */ -#define MAX_IMMEDIATE_OPERANDS 2/* max immediates per insn (lcall, ljmp) */ -#define MAX_MEMORY_OPERANDS 2 /* max memory refs per insn (string ops) */ - -/* Prefixes will be emitted in the order defined below. - WAIT_PREFIX must be the first prefix since FWAIT is really is an - instruction, and so must come before any prefixes. */ -#define WAIT_PREFIX 0 -#define LOCKREP_PREFIX 1 -#define ADDR_PREFIX 2 -#define DATA_PREFIX 3 -#define SEG_PREFIX 4 -#define MAX_PREFIXES 5 /* max prefixes per opcode */ - -/* we define the syntax here (modulo base,index,scale syntax) */ -#define REGISTER_PREFIX '%' -#define IMMEDIATE_PREFIX '$' -#define ABSOLUTE_PREFIX '*' - -#define TWO_BYTE_OPCODE_ESCAPE 0x0f -#define NOP_OPCODE (char) 0x90 - -/* register numbers */ -#define EBP_REG_NUM 5 -#define ESP_REG_NUM 4 - -/* modrm_byte.regmem for twobyte escape */ -#define ESCAPE_TO_TWO_BYTE_ADDRESSING ESP_REG_NUM -/* index_base_byte.index for no index register addressing */ -#define NO_INDEX_REGISTER ESP_REG_NUM -/* index_base_byte.base for no base register addressing */ -#define NO_BASE_REGISTER EBP_REG_NUM -#define NO_BASE_REGISTER_16 6 - -/* these are the instruction mnemonic suffixes. */ -#define WORD_MNEM_SUFFIX 'w' -#define BYTE_MNEM_SUFFIX 'b' -#define SHORT_MNEM_SUFFIX 's' -#define LONG_MNEM_SUFFIX 'l' -/* Intel Syntax */ -#define LONG_DOUBLE_MNEM_SUFFIX 'x' -/* Intel Syntax */ -#define DWORD_MNEM_SUFFIX 'd' - -/* modrm.mode = REGMEM_FIELD_HAS_REG when a register is in there */ -#define REGMEM_FIELD_HAS_REG 0x3/* always = 0x3 */ -#define REGMEM_FIELD_HAS_MEM (~REGMEM_FIELD_HAS_REG) - -#define END_OF_INSN '\0' - -/* Intel Syntax */ -/* Values 0-4 map onto scale factor */ -#define BYTE_PTR 0 -#define WORD_PTR 1 -#define DWORD_PTR 2 -#define QWORD_PTR 3 -#define XWORD_PTR 4 -#define SHORT 5 -#define OFFSET_FLAT 6 -#define FLAT 7 -#define NONE_FOUND 8 -/* - When an operand is read in it is classified by its type. This type includes - all the possible ways an operand can be used. Thus, '%eax' is both 'register - # 0' and 'The Accumulator'. In our language this is expressed by OR'ing - 'Reg32' (any 32 bit register) and 'Acc' (the accumulator). - Operands are classified so that we can match given operand types with - the opcode table in opcode/i386.h. - */ -/* register */ -#define Reg8 0x1 /* 8 bit reg */ -#define Reg16 0x2 /* 16 bit reg */ -#define Reg32 0x4 /* 32 bit reg */ -/* immediate */ -#define Imm8 0x8 /* 8 bit immediate */ -#define Imm8S 0x10 /* 8 bit immediate sign extended */ -#define Imm16 0x20 /* 16 bit immediate */ -#define Imm32 0x40 /* 32 bit immediate */ -#define Imm1 0x80 /* 1 bit immediate */ -/* memory */ -#define BaseIndex 0x100 -/* Disp8,16,32 are used in different ways, depending on the - instruction. For jumps, they specify the size of the PC relative - displacement, for baseindex type instructions, they specify the - size of the offset relative to the base register, and for memory - offset instructions such as `mov 1234,%al' they specify the size of - the offset relative to the segment base. */ -#define Disp8 0x200 /* 8 bit displacement */ -#define Disp16 0x400 /* 16 bit displacement */ -#define Disp32 0x800 /* 32 bit displacement */ -/* specials */ -#define InOutPortReg 0x1000 /* register to hold in/out port addr = dx */ -#define ShiftCount 0x2000 /* register to hold shift cound = cl */ -#define Control 0x4000 /* Control register */ -#define Debug 0x8000 /* Debug register */ -#define Test 0x10000 /* Test register */ -#define FloatReg 0x20000 /* Float register */ -#define FloatAcc 0x40000 /* Float stack top %st(0) */ -#define SReg2 0x80000 /* 2 bit segment register */ -#define SReg3 0x100000 /* 3 bit segment register */ -#define Acc 0x200000 /* Accumulator %al or %ax or %eax */ -#define JumpAbsolute 0x400000 -#define RegMMX 0x800000 /* MMX register */ -#define RegXMM 0x1000000 /* XMM registers in PIII */ -#define EsSeg 0x2000000 /* String insn operand with fixed es segment */ -/* InvMem is for instructions with a modrm byte that only allow a - general register encoding in the i.tm.mode and i.tm.regmem fields, - eg. control reg moves. They really ought to support a memory form, - but don't, so we add an InvMem flag to the register operand to - indicate that it should be encoded in the i.tm.regmem field. */ -#define InvMem 0x4000000 - -#define Reg (Reg8|Reg16|Reg32) /* gen'l register */ -#define WordReg (Reg16|Reg32) -#define ImplicitRegister (InOutPortReg|ShiftCount|Acc|FloatAcc) -#define Imm (Imm8|Imm8S|Imm16|Imm32) /* gen'l immediate */ -#define Disp (Disp8|Disp16|Disp32) /* General displacement */ -#define AnyMem (Disp|BaseIndex|InvMem) /* General memory */ -/* The following aliases are defined because the opcode table - carefully specifies the allowed memory types for each instruction. - At the moment we can only tell a memory reference size by the - instruction suffix, so there's not much point in defining Mem8, - Mem16, Mem32 and Mem64 opcode modifiers - We might as well just use - the suffix directly to check memory operands. */ -#define LLongMem AnyMem /* 64 bits (or more) */ -#define LongMem AnyMem /* 32 bit memory ref */ -#define ShortMem AnyMem /* 16 bit memory ref */ -#define WordMem AnyMem /* 16 or 32 bit memory ref */ -#define ByteMem AnyMem /* 8 bit memory ref */ - -#define SMALLEST_DISP_TYPE(num) \ - (fits_in_signed_byte(num) ? (Disp8|Disp32) : Disp32) - -typedef struct -{ - /* instruction name sans width suffix ("mov" for movl insns) */ - char *name; - - /* how many operands */ - unsigned int operands; - - /* base_opcode is the fundamental opcode byte without optional - prefix(es). */ - unsigned int base_opcode; - - /* extension_opcode is the 3 bit extension for group <n> insns. - This field is also used to store the 8-bit opcode suffix for the - AMD 3DNow! instructions. - If this template has no extension opcode (the usual case) use None */ - unsigned int extension_opcode; -#define None 0xffff /* If no extension_opcode is possible. */ - - /* the bits in opcode_modifier are used to generate the final opcode from - the base_opcode. These bits also are used to detect alternate forms of - the same instruction */ - unsigned int opcode_modifier; - - /* opcode_modifier bits: */ -#define W 0x1 /* set if operands can be words or dwords - encoded the canonical way */ -#define D 0x2 /* D = 0 if Reg --> Regmem; - D = 1 if Regmem --> Reg: MUST BE 0x2 */ -#define Modrm 0x4 -#define FloatR 0x8 /* src/dest swap for floats: MUST BE 0x8 */ -#define ShortForm 0x10 /* register is in low 3 bits of opcode */ -#define FloatMF 0x20 /* FP insn memory format bit, sized by 0x4 */ -#define Jump 0x40 /* special case for jump insns. */ -#define JumpDword 0x80 /* call and jump */ -#define JumpByte 0x100 /* loop and jecxz */ -#define JumpInterSegment 0x200 /* special case for intersegment leaps/calls */ -#define FloatD 0x400 /* direction for float insns: MUST BE 0x400 */ -#define Seg2ShortForm 0x800 /* encoding of load segment reg insns */ -#define Seg3ShortForm 0x1000 /* fs/gs segment register insns. */ -#define Size16 0x2000 /* needs size prefix if in 32-bit mode */ -#define Size32 0x4000 /* needs size prefix if in 16-bit mode */ -#define IgnoreSize 0x8000 /* instruction ignores operand size prefix */ -#define DefaultSize 0x10000 /* default insn size depends on mode */ -#define No_bSuf 0x20000 /* b suffix on instruction illegal */ -#define No_wSuf 0x40000 /* w suffix on instruction illegal */ -#define No_lSuf 0x80000 /* l suffix on instruction illegal */ -#define No_sSuf 0x100000 /* s suffix on instruction illegal */ -#define No_dSuf 0x200000 /* d suffix on instruction illegal */ -#define No_xSuf 0x400000 /* x suffix on instruction illegal */ -#define FWait 0x800000 /* instruction needs FWAIT */ -#define IsString 0x1000000 /* quick test for string instructions */ -#define regKludge 0x2000000 /* fake an extra reg operand for clr, imul */ -#define IsPrefix 0x4000000 /* opcode is a prefix */ -#define ImmExt 0x8000000 /* instruction has extension in 8 bit imm */ -#define Ugh 0x80000000 /* deprecated fp insn, gets a warning */ - - /* operand_types[i] describes the type of operand i. This is made - by OR'ing together all of the possible type masks. (e.g. - 'operand_types[i] = Reg|Imm' specifies that operand i can be - either a register or an immediate operand */ - unsigned int operand_types[3]; -} -template; - -/* - 'templates' is for grouping together 'template' structures for opcodes - of the same name. This is only used for storing the insns in the grand - ole hash table of insns. - The templates themselves start at START and range up to (but not including) - END. - */ -typedef struct - { - const template *start; - const template *end; - } templates; - -/* these are for register name --> number & type hash lookup */ -typedef struct - { - char *reg_name; - unsigned int reg_type; - unsigned int reg_num; - } -reg_entry; - -typedef struct - { - char *seg_name; - unsigned int seg_prefix; - } -seg_entry; - -/* 386 operand encoding bytes: see 386 book for details of this. */ -typedef struct - { - unsigned int regmem; /* codes register or memory operand */ - unsigned int reg; /* codes register operand (or extended opcode) */ - unsigned int mode; /* how to interpret regmem & reg */ - } -modrm_byte; - -/* 386 opcode byte to code indirect addressing. */ -typedef struct - { - unsigned base; - unsigned index; - unsigned scale; - } -sib_byte; - -/* The name of the global offset table generated by the compiler. Allow - this to be overridden if need be. */ -#ifndef GLOBAL_OFFSET_TABLE_NAME -#define GLOBAL_OFFSET_TABLE_NAME "_GLOBAL_OFFSET_TABLE_" -#endif - -#ifdef BFD_ASSEMBLER -void i386_validate_fix PARAMS ((struct fix *)); -#define TC_VALIDATE_FIX(FIXP,SEGTYPE,SKIP) i386_validate_fix(FIXP) -#endif - -#endif /* TC_I386 */ - -#define md_operand(x) - -extern const struct relax_type md_relax_table[]; -#define TC_GENERIC_RELAX_TABLE md_relax_table - -#define md_do_align(n, fill, len, max, around) \ -if ((n) && !need_pass_2 \ - && (!(fill) || ((char)*(fill) == (char)0x90 && (len) == 1)) \ - && subseg_text_p (now_seg)) \ - { \ - char *p; \ - p = frag_var (rs_align_code, 15, 1, (relax_substateT) max, \ - (symbolS *) 0, (offsetT) (n), (char *) 0); \ - *p = 0x90; \ - goto around; \ - } - -extern void i386_align_code PARAMS ((fragS *, int)); - -#define HANDLE_ALIGN(fragP) \ -if (fragP->fr_type == rs_align_code) \ - i386_align_code (fragP, (fragP->fr_next->fr_address \ - - fragP->fr_address \ - - fragP->fr_fix)); - -/* call md_apply_fix3 with segment instead of md_apply_fix */ -#define MD_APPLY_FIX3 - -void i386_print_statistics PARAMS ((FILE *)); -#define tc_print_statistics i386_print_statistics - -#define md_number_to_chars number_to_chars_littleendian - -#ifdef SCO_ELF -#define tc_init_after_args() sco_id () -extern void sco_id PARAMS ((void)); -#endif - -#define DIFF_EXPR_OK /* foo-. gets turned into PC relative relocs */ - -/* end of tc-i386.h */ diff --git a/contrib/binutils/gas/config/tc-m68851.h b/contrib/binutils/gas/config/tc-m68851.h deleted file mode 100644 index 0f6d741337524..0000000000000 --- a/contrib/binutils/gas/config/tc-m68851.h +++ /dev/null @@ -1,304 +0,0 @@ -/* This file is tc-m68851.h - - Copyright (C) 1987-1992 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. */ - -/* - * pmmu.h - */ - -/* I suppose we have to copyright this file. Someone on the net sent it - to us as part of the changes for the m68851 Memory Management Unit */ - -/* Copyright (C) 1987 Free Software Foundation, Inc. - - This file is part of Gas, the GNU Assembler. - - The GNU assembler is distributed in the hope that it will be - useful, but WITHOUT ANY WARRANTY. No author or distributor - accepts responsibility to anyone for the consequences of using it - or for whether it serves any particular purpose or works at all, - unless he says so in writing. Refer to the GNU Assembler General - Public License for full details. - - Everyone is granted permission to copy, modify and redistribute - the GNU Assembler, but only under the conditions described in the - GNU Assembler General Public License. A copy of this license is - supposed to have been given to you along with the GNU Assembler - so you can know your rights and responsibilities. It should be - in a file named COPYING. Among other things, the copyright - notice and this notice must be preserved on all copies. */ - -#ifdef m68851 - -/* - I didn't use much imagination in choosing the - following codes, so many of them aren't very - mnemonic. -rab - - P pmmu register - Possible values: - 000 TC Translation Control reg - 100 CAL Current Access Level - 101 VAL Validate Access Level - 110 SCC Stack Change Control - 111 AC Access Control - - W wide pmmu registers - Possible values: - 001 DRP Dma Root Pointer - 010 SRP Supervisor Root Pointer - 011 CRP Cpu Root Pointer - - f function code register - 0 SFC - 1 DFC - - V VAL register only - - X BADx, BACx - 100 BAD Breakpoint Acknowledge Data - 101 BAC Breakpoint Acknowledge Control - - Y PSR - Z PCSR - - | memory (modes 2-6, 7.*) - - */ - -/* - * these defines should be in m68k.c but - * i put them here to keep all the m68851 stuff - * together -rab - * JF--Make sure these #s don't clash with the ones in m68k.c - * That would be BAD. - */ -#define TC (FPS+1) /* 48 */ -#define DRP (TC+1) /* 49 */ -#define SRP (DRP+1) /* 50 */ -#define CRP (SRP+1) /* 51 */ -#define CAL (CRP+1) /* 52 */ -#define VAL (CAL+1) /* 53 */ -#define SCC (VAL+1) /* 54 */ -#define AC (SCC+1) /* 55 */ -#define BAD (AC+1) /* 56,57,58,59, 60,61,62,63 */ -#define BAC (BAD+8) /* 64,65,66,67, 68,69,70,71 */ -#define PSR (BAC+8) /* 72 */ -#define PCSR (PSR+1) /* 73 */ - -/* name */ /* opcode */ /* match */ /* args */ - -{"pbac", one(0xf0c7), one(0xffbf), "Bc"}, -{"pbacw", one(0xf087), one(0xffbf), "Bc"}, -{"pbas", one(0xf0c6), one(0xffbf), "Bc"}, -{"pbasw", one(0xf086), one(0xffbf), "Bc"}, -{"pbbc", one(0xf0c1), one(0xffbf), "Bc"}, -{"pbbcw", one(0xf081), one(0xffbf), "Bc"}, -{"pbbs", one(0xf0c0), one(0xffbf), "Bc"}, -{"pbbsw", one(0xf080), one(0xffbf), "Bc"}, -{"pbcc", one(0xf0cf), one(0xffbf), "Bc"}, -{"pbccw", one(0xf08f), one(0xffbf), "Bc"}, -{"pbcs", one(0xf0ce), one(0xffbf), "Bc"}, -{"pbcsw", one(0xf08e), one(0xffbf), "Bc"}, -{"pbgc", one(0xf0cd), one(0xffbf), "Bc"}, -{"pbgcw", one(0xf08d), one(0xffbf), "Bc"}, -{"pbgs", one(0xf0cc), one(0xffbf), "Bc"}, -{"pbgsw", one(0xf08c), one(0xffbf), "Bc"}, -{"pbic", one(0xf0cb), one(0xffbf), "Bc"}, -{"pbicw", one(0xf08b), one(0xffbf), "Bc"}, -{"pbis", one(0xf0ca), one(0xffbf), "Bc"}, -{"pbisw", one(0xf08a), one(0xffbf), "Bc"}, -{"pblc", one(0xf0c3), one(0xffbf), "Bc"}, -{"pblcw", one(0xf083), one(0xffbf), "Bc"}, -{"pbls", one(0xf0c2), one(0xffbf), "Bc"}, -{"pblsw", one(0xf082), one(0xffbf), "Bc"}, -{"pbsc", one(0xf0c5), one(0xffbf), "Bc"}, -{"pbscw", one(0xf085), one(0xffbf), "Bc"}, -{"pbss", one(0xf0c4), one(0xffbf), "Bc"}, -{"pbssw", one(0xf084), one(0xffbf), "Bc"}, -{"pbwc", one(0xf0c9), one(0xffbf), "Bc"}, -{"pbwcw", one(0xf089), one(0xffbf), "Bc"}, -{"pbws", one(0xf0c8), one(0xffbf), "Bc"}, -{"pbwsw", one(0xf088), one(0xffbf), "Bc"}, - - -{"pdbac", two(0xf048, 0x0007), two(0xfff8, 0xffff), "DsBw"}, -{"pdbas", two(0xf048, 0x0006), two(0xfff8, 0xffff), "DsBw"}, -{"pdbbc", two(0xf048, 0x0001), two(0xfff8, 0xffff), "DsBw"}, -{"pdbbs", two(0xf048, 0x0000), two(0xfff8, 0xffff), "DsBw"}, -{"pdbcc", two(0xf048, 0x000f), two(0xfff8, 0xffff), "DsBw"}, -{"pdbcs", two(0xf048, 0x000e), two(0xfff8, 0xffff), "DsBw"}, -{"pdbgc", two(0xf048, 0x000d), two(0xfff8, 0xffff), "DsBw"}, -{"pdbgs", two(0xf048, 0x000c), two(0xfff8, 0xffff), "DsBw"}, -{"pdbic", two(0xf048, 0x000b), two(0xfff8, 0xffff), "DsBw"}, -{"pdbis", two(0xf048, 0x000a), two(0xfff8, 0xffff), "DsBw"}, -{"pdblc", two(0xf048, 0x0003), two(0xfff8, 0xffff), "DsBw"}, -{"pdbls", two(0xf048, 0x0002), two(0xfff8, 0xffff), "DsBw"}, -{"pdbsc", two(0xf048, 0x0005), two(0xfff8, 0xffff), "DsBw"}, -{"pdbss", two(0xf048, 0x0004), two(0xfff8, 0xffff), "DsBw"}, -{"pdbwc", two(0xf048, 0x0009), two(0xfff8, 0xffff), "DsBw"}, -{"pdbws", two(0xf048, 0x0008), two(0xfff8, 0xffff), "DsBw"}, - -{"pflusha", two(0xf000, 0x2400), two(0xffff, 0xffff), "" }, - -{"pflush", two(0xf000, 0x3010), two(0xffc0, 0xfe10), "T3T9" }, -{"pflush", two(0xf000, 0x3810), two(0xffc0, 0xfe10), "T3T9&s" }, -{"pflush", two(0xf000, 0x3008), two(0xffc0, 0xfe18), "D3T9" }, -{"pflush", two(0xf000, 0x3808), two(0xffc0, 0xfe18), "D3T9&s" }, -{"pflush", two(0xf000, 0x3000), two(0xffc0, 0xfe1e), "f3T9" }, -{"pflush", two(0xf000, 0x3800), two(0xffc0, 0xfe1e), "f3T9&s" }, - -{"pflushs", two(0xf000, 0x3410), two(0xfff8, 0xfe10), "T3T9" }, -{"pflushs", two(0xf000, 0x3c00), two(0xfff8, 0xfe00), "T3T9&s" }, -{"pflushs", two(0xf000, 0x3408), two(0xfff8, 0xfe18), "D3T9" }, -{"pflushs", two(0xf000, 0x3c08), two(0xfff8, 0xfe18), "D3T9&s" }, -{"pflushs", two(0xf000, 0x3400), two(0xfff8, 0xfe1e), "f3T9" }, -{"pflushs", two(0xf000, 0x3c00), two(0xfff8, 0xfe1e), "f3T9&s"}, - -{"pflushr", two(0xf000, 0xa000), two(0xffc0, 0xffff), "|s" }, - -{"ploadr", two(0xf000, 0x2210), two(0xffc0, 0xfff0), "T3&s" }, -{"ploadr", two(0xf000, 0x2208), two(0xffc0, 0xfff8), "D3&s" }, -{"ploadr", two(0xf000, 0x2200), two(0xffc0, 0xfffe), "f3&s" }, -{"ploadw", two(0xf000, 0x2010), two(0xffc0, 0xfff0), "T3&s" }, -{"ploadw", two(0xf000, 0x2008), two(0xffc0, 0xfff8), "D3&s" }, -{"ploadw", two(0xf000, 0x2000), two(0xffc0, 0xfffe), "f3&s" }, - - /* TC, CRP, DRP, SRP, CAL, VAL, SCC, AC */ -{"pmove", two(0xf000, 0x4000), two(0xffc0, 0xe3ff), "*sP8" }, -{"pmove", two(0xf000, 0x4200), two(0xffc0, 0xe3ff), "P8%s" }, -{"pmove", two(0xf000, 0x4000), two(0xffc0, 0xe3ff), "|sW8" }, -{"pmove", two(0xf000, 0x4200), two(0xffc0, 0xe3ff), "W8~s" }, - - /* BADx, BACx */ -{"pmove", two(0xf000, 0x6200), two(0xffc0, 0xe3e3), "*sX3" }, -{"pmove", two(0xf000, 0x6000), two(0xffc0, 0xe3e3), "X3%s" }, - - /* PSR, PCSR */ - /* {"pmove", two(0xf000, 0x6100), two(oxffc0, oxffff), "*sZ8" }, */ -{"pmove", two(0xf000, 0x6000), two(0xffc0, 0xffff), "*sY8" }, -{"pmove", two(0xf000, 0x6200), two(0xffc0, 0xffff), "Y8%s" }, -{"pmove", two(0xf000, 0x6600), two(0xffc0, 0xffff), "Z8%s" }, - -{"prestore", one(0xf140), one(0xffc0), "&s"}, -{"prestore", one(0xf158), one(0xfff8), "+s"}, -{"psave", one(0xf100), one(0xffc0), "&s"}, -{"psave", one(0xf100), one(0xffc0), "+s"}, - -{"psac", two(0xf040, 0x0007), two(0xffc0, 0xffff), "@s"}, -{"psas", two(0xf040, 0x0006), two(0xffc0, 0xffff), "@s"}, -{"psbc", two(0xf040, 0x0001), two(0xffc0, 0xffff), "@s"}, -{"psbs", two(0xf040, 0x0000), two(0xffc0, 0xffff), "@s"}, -{"pscc", two(0xf040, 0x000f), two(0xffc0, 0xffff), "@s"}, -{"pscs", two(0xf040, 0x000e), two(0xffc0, 0xffff), "@s"}, -{"psgc", two(0xf040, 0x000d), two(0xffc0, 0xffff), "@s"}, -{"psgs", two(0xf040, 0x000c), two(0xffc0, 0xffff), "@s"}, -{"psic", two(0xf040, 0x000b), two(0xffc0, 0xffff), "@s"}, -{"psis", two(0xf040, 0x000a), two(0xffc0, 0xffff), "@s"}, -{"pslc", two(0xf040, 0x0003), two(0xffc0, 0xffff), "@s"}, -{"psls", two(0xf040, 0x0002), two(0xffc0, 0xffff), "@s"}, -{"pssc", two(0xf040, 0x0005), two(0xffc0, 0xffff), "@s"}, -{"psss", two(0xf040, 0x0004), two(0xffc0, 0xffff), "@s"}, -{"pswc", two(0xf040, 0x0009), two(0xffc0, 0xffff), "@s"}, -{"psws", two(0xf040, 0x0008), two(0xffc0, 0xffff), "@s"}, - -{"ptestr", two(0xf000, 0x8210), two(0xffc0, 0xe3f0), "T3&sQ8" }, -{"ptestr", two(0xf000, 0x8310), two(0xffc0, 0xe310), "T3&sQ8A9" }, -{"ptestr", two(0xf000, 0x8208), two(0xffc0, 0xe3f8), "D3&sQ8" }, -{"ptestr", two(0xf000, 0x8308), two(0xffc0, 0xe318), "D3&sQ8A9" }, -{"ptestr", two(0xf000, 0x8200), two(0xffc0, 0xe3fe), "f3&sQ8" }, -{"ptestr", two(0xf000, 0x8300), two(0xffc0, 0xe31e), "f3&sQ8A9" }, - -{"ptestw", two(0xf000, 0x8010), two(0xffc0, 0xe3f0), "T3&sQ8" }, -{"ptestw", two(0xf000, 0x8110), two(0xffc0, 0xe310), "T3&sQ8A9" }, -{"ptestw", two(0xf000, 0x8008), two(0xffc0, 0xe3f8), "D3&sQ8" }, -{"ptestw", two(0xf000, 0x8108), two(0xffc0, 0xe318), "D3&sQ8A9" }, -{"ptestw", two(0xf000, 0x8000), two(0xffc0, 0xe3fe), "f3&sQ8" }, -{"ptestw", two(0xf000, 0x8100), two(0xffc0, 0xe31e), "f3&sQ8A9" }, - -{"ptrapacw", two(0xf07a, 0x0007), two(0xffff, 0xffff), "#w"}, -{"ptrapacl", two(0xf07b, 0x0007), two(0xffff, 0xffff), "#l"}, -{"ptrapac", two(0xf07c, 0x0007), two(0xffff, 0xffff), ""}, - -{"ptrapasw", two(0xf07a, 0x0006), two(0xffff, 0xffff), "#w"}, -{"ptrapasl", two(0xf07b, 0x0006), two(0xffff, 0xffff), "#l"}, -{"ptrapas", two(0xf07c, 0x0006), two(0xffff, 0xffff), ""}, - -{"ptrapbcw", two(0xf07a, 0x0001), two(0xffff, 0xffff), "#w"}, -{"ptrapbcl", two(0xf07b, 0x0001), two(0xffff, 0xffff), "#l"}, -{"ptrapbc", two(0xf07c, 0x0001), two(0xffff, 0xffff), ""}, - -{"ptrapbsw", two(0xf07a, 0x0000), two(0xffff, 0xffff), "#w"}, -{"ptrapbsl", two(0xf07b, 0x0000), two(0xffff, 0xffff), "#l"}, -{"ptrapbs", two(0xf07c, 0x0000), two(0xffff, 0xffff), ""}, - -{"ptrapccw", two(0xf07a, 0x000f), two(0xffff, 0xffff), "#w"}, -{"ptrapccl", two(0xf07b, 0x000f), two(0xffff, 0xffff), "#l"}, -{"ptrapcc", two(0xf07c, 0x000f), two(0xffff, 0xffff), ""}, - -{"ptrapcsw", two(0xf07a, 0x000e), two(0xffff, 0xffff), "#w"}, -{"ptrapcsl", two(0xf07b, 0x000e), two(0xffff, 0xffff), "#l"}, -{"ptrapcs", two(0xf07c, 0x000e), two(0xffff, 0xffff), ""}, - -{"ptrapgcw", two(0xf07a, 0x000d), two(0xffff, 0xffff), "#w"}, -{"ptrapgcl", two(0xf07b, 0x000d), two(0xffff, 0xffff), "#l"}, -{"ptrapgc", two(0xf07c, 0x000d), two(0xffff, 0xffff), ""}, - -{"ptrapgsw", two(0xf07a, 0x000c), two(0xffff, 0xffff), "#w"}, -{"ptrapgsl", two(0xf07b, 0x000c), two(0xffff, 0xffff), "#l"}, -{"ptrapgs", two(0xf07c, 0x000c), two(0xffff, 0xffff), ""}, - -{"ptrapicw", two(0xf07a, 0x000b), two(0xffff, 0xffff), "#w"}, -{"ptrapicl", two(0xf07b, 0x000b), two(0xffff, 0xffff), "#l"}, -{"ptrapic", two(0xf07c, 0x000b), two(0xffff, 0xffff), ""}, - -{"ptrapisw", two(0xf07a, 0x000a), two(0xffff, 0xffff), "#w"}, -{"ptrapisl", two(0xf07b, 0x000a), two(0xffff, 0xffff), "#l"}, -{"ptrapis", two(0xf07c, 0x000a), two(0xffff, 0xffff), ""}, - -{"ptraplcw", two(0xf07a, 0x0003), two(0xffff, 0xffff), "#w"}, -{"ptraplcl", two(0xf07b, 0x0003), two(0xffff, 0xffff), "#l"}, -{"ptraplc", two(0xf07c, 0x0003), two(0xffff, 0xffff), ""}, - -{"ptraplsw", two(0xf07a, 0x0002), two(0xffff, 0xffff), "#w"}, -{"ptraplsl", two(0xf07b, 0x0002), two(0xffff, 0xffff), "#l"}, -{"ptrapls", two(0xf07c, 0x0002), two(0xffff, 0xffff), ""}, - -{"ptrapscw", two(0xf07a, 0x0005), two(0xffff, 0xffff), "#w"}, -{"ptrapscl", two(0xf07b, 0x0005), two(0xffff, 0xffff), "#l"}, -{"ptrapsc", two(0xf07c, 0x0005), two(0xffff, 0xffff), ""}, - -{"ptrapssw", two(0xf07a, 0x0004), two(0xffff, 0xffff), "#w"}, -{"ptrapssl", two(0xf07b, 0x0004), two(0xffff, 0xffff), "#l"}, -{"ptrapss", two(0xf07c, 0x0004), two(0xffff, 0xffff), ""}, - -{"ptrapwcw", two(0xf07a, 0x0009), two(0xffff, 0xffff), "#w"}, -{"ptrapwcl", two(0xf07b, 0x0009), two(0xffff, 0xffff), "#l"}, -{"ptrapwc", two(0xf07c, 0x0009), two(0xffff, 0xffff), ""}, - -{"ptrapwsw", two(0xf07a, 0x0008), two(0xffff, 0xffff), "#w"}, -{"ptrapwsl", two(0xf07b, 0x0008), two(0xffff, 0xffff), "#l"}, -{"ptrapws", two(0xf07c, 0x0008), two(0xffff, 0xffff), ""}, - -{"pvalid", two(0xf000, 0x2800), two(0xffc0, 0xffff), "Vs&s"}, -{"pvalid", two(0xf000, 0x2c00), two(0xffc0, 0xfff8), "A3&s" }, - -#endif /* m68851 */ - -/* end of tc-m68851.h */ diff --git a/contrib/binutils/gas/config/tc-ppc.c b/contrib/binutils/gas/config/tc-ppc.c deleted file mode 100644 index 365a535a28914..0000000000000 --- a/contrib/binutils/gas/config/tc-ppc.c +++ /dev/null @@ -1,5026 +0,0 @@ -/* tc-ppc.c -- Assemble for the PowerPC or POWER (RS/6000) - Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000 - Free Software Foundation, Inc. - Written by Ian Lance Taylor, Cygnus Support. - - 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. */ - -#include <stdio.h> -#include <ctype.h> -#include "as.h" -#include "subsegs.h" - -#include "opcode/ppc.h" - -#ifdef OBJ_ELF -#include "elf/ppc.h" -#endif - -#ifdef TE_PE -#include "coff/pe.h" -#endif - -/* This is the assembler for the PowerPC or POWER (RS/6000) chips. */ - -/* Tell the main code what the endianness is. */ -extern int target_big_endian; - -/* Whether or not, we've set target_big_endian. */ -static int set_target_endian = 0; - -/* Whether to use user friendly register names. */ -#ifndef TARGET_REG_NAMES_P -#ifdef TE_PE -#define TARGET_REG_NAMES_P true -#else -#define TARGET_REG_NAMES_P false -#endif -#endif - -static boolean reg_names_p = TARGET_REG_NAMES_P; - -static boolean register_name PARAMS ((expressionS *)); -static void ppc_set_cpu PARAMS ((void)); -static unsigned long ppc_insert_operand - PARAMS ((unsigned long insn, const struct powerpc_operand *operand, - offsetT val, char *file, unsigned int line)); -static void ppc_macro PARAMS ((char *str, const struct powerpc_macro *macro)); -static void ppc_byte PARAMS ((int)); -static int ppc_is_toc_sym PARAMS ((symbolS *sym)); -static void ppc_tc PARAMS ((int)); - -#ifdef OBJ_XCOFF -static void ppc_comm PARAMS ((int)); -static void ppc_bb PARAMS ((int)); -static void ppc_bc PARAMS ((int)); -static void ppc_bf PARAMS ((int)); -static void ppc_biei PARAMS ((int)); -static void ppc_bs PARAMS ((int)); -static void ppc_eb PARAMS ((int)); -static void ppc_ec PARAMS ((int)); -static void ppc_ef PARAMS ((int)); -static void ppc_es PARAMS ((int)); -static void ppc_csect PARAMS ((int)); -static void ppc_change_csect PARAMS ((symbolS *)); -static void ppc_function PARAMS ((int)); -static void ppc_extern PARAMS ((int)); -static void ppc_lglobl PARAMS ((int)); -static void ppc_section PARAMS ((int)); -static void ppc_named_section PARAMS ((int)); -static void ppc_stabx PARAMS ((int)); -static void ppc_rename PARAMS ((int)); -static void ppc_toc PARAMS ((int)); -static void ppc_xcoff_cons PARAMS ((int)); -static void ppc_vbyte PARAMS ((int)); -#endif - -#ifdef OBJ_ELF -static bfd_reloc_code_real_type ppc_elf_suffix PARAMS ((char **, expressionS *)); -static void ppc_elf_cons PARAMS ((int)); -static void ppc_elf_rdata PARAMS ((int)); -static void ppc_elf_lcomm PARAMS ((int)); -static void ppc_elf_validate_fix PARAMS ((fixS *, segT)); -#endif - -#ifdef TE_PE -static void ppc_set_current_section PARAMS ((segT)); -static void ppc_previous PARAMS ((int)); -static void ppc_pdata PARAMS ((int)); -static void ppc_ydata PARAMS ((int)); -static void ppc_reldata PARAMS ((int)); -static void ppc_rdata PARAMS ((int)); -static void ppc_ualong PARAMS ((int)); -static void ppc_znop PARAMS ((int)); -static void ppc_pe_comm PARAMS ((int)); -static void ppc_pe_section PARAMS ((int)); -static void ppc_pe_function PARAMS ((int)); -static void ppc_pe_tocd PARAMS ((int)); -#endif - -/* Generic assembler global variables which must be defined by all - targets. */ - -#ifdef OBJ_ELF -/* This string holds the chars that always start a comment. If the - pre-processor is disabled, these aren't very useful. The macro - tc_comment_chars points to this. We use this, rather than the - usual comment_chars, so that we can switch for Solaris conventions. */ -static const char ppc_solaris_comment_chars[] = "#!"; -static const char ppc_eabi_comment_chars[] = "#"; - -#ifdef TARGET_SOLARIS_COMMENT -const char *ppc_comment_chars = ppc_solaris_comment_chars; -#else -const char *ppc_comment_chars = ppc_eabi_comment_chars; -#endif -#else -const char comment_chars[] = "#"; -#endif - -/* Characters which start a comment at the beginning of a line. */ -const char line_comment_chars[] = "#"; - -/* Characters which may be used to separate multiple commands on a - single line. */ -const char line_separator_chars[] = ";"; - -/* Characters which are used to indicate an exponent in a floating - point number. */ -const char EXP_CHARS[] = "eE"; - -/* Characters which mean that a number is a floating point constant, - as in 0d1.0. */ -const char FLT_CHARS[] = "dD"; - -/* The target specific pseudo-ops which we support. */ - -const pseudo_typeS md_pseudo_table[] = -{ - /* Pseudo-ops which must be overridden. */ - { "byte", ppc_byte, 0 }, - -#ifdef OBJ_XCOFF - /* Pseudo-ops specific to the RS/6000 XCOFF format. Some of these - legitimately belong in the obj-*.c file. However, XCOFF is based - on COFF, and is only implemented for the RS/6000. We just use - obj-coff.c, and add what we need here. */ - { "comm", ppc_comm, 0 }, - { "lcomm", ppc_comm, 1 }, - { "bb", ppc_bb, 0 }, - { "bc", ppc_bc, 0 }, - { "bf", ppc_bf, 0 }, - { "bi", ppc_biei, 0 }, - { "bs", ppc_bs, 0 }, - { "csect", ppc_csect, 0 }, - { "data", ppc_section, 'd' }, - { "eb", ppc_eb, 0 }, - { "ec", ppc_ec, 0 }, - { "ef", ppc_ef, 0 }, - { "ei", ppc_biei, 1 }, - { "es", ppc_es, 0 }, - { "extern", ppc_extern, 0 }, - { "function", ppc_function, 0 }, - { "lglobl", ppc_lglobl, 0 }, - { "rename", ppc_rename, 0 }, - { "section", ppc_named_section, 0 }, - { "stabx", ppc_stabx, 0 }, - { "text", ppc_section, 't' }, - { "toc", ppc_toc, 0 }, - { "long", ppc_xcoff_cons, 2 }, - { "word", ppc_xcoff_cons, 1 }, - { "short", ppc_xcoff_cons, 1 }, - { "vbyte", ppc_vbyte, 0 }, -#endif - -#ifdef OBJ_ELF - { "long", ppc_elf_cons, 4 }, - { "word", ppc_elf_cons, 2 }, - { "short", ppc_elf_cons, 2 }, - { "rdata", ppc_elf_rdata, 0 }, - { "rodata", ppc_elf_rdata, 0 }, - { "lcomm", ppc_elf_lcomm, 0 }, -#endif - -#ifdef TE_PE - /* Pseudo-ops specific to the Windows NT PowerPC PE (coff) format */ - { "previous", ppc_previous, 0 }, - { "pdata", ppc_pdata, 0 }, - { "ydata", ppc_ydata, 0 }, - { "reldata", ppc_reldata, 0 }, - { "rdata", ppc_rdata, 0 }, - { "ualong", ppc_ualong, 0 }, - { "znop", ppc_znop, 0 }, - { "comm", ppc_pe_comm, 0 }, - { "lcomm", ppc_pe_comm, 1 }, - { "section", ppc_pe_section, 0 }, - { "function", ppc_pe_function,0 }, - { "tocd", ppc_pe_tocd, 0 }, -#endif - - /* This pseudo-op is used even when not generating XCOFF output. */ - { "tc", ppc_tc, 0 }, - - { NULL, NULL, 0 } -}; - - -/* Predefined register names if -mregnames (or default for Windows NT). */ -/* In general, there are lots of them, in an attempt to be compatible */ -/* with a number of other Windows NT assemblers. */ - -/* Structure to hold information about predefined registers. */ -struct pd_reg - { - char *name; - int value; - }; - -/* List of registers that are pre-defined: - - Each general register has predefined names of the form: - 1. r<reg_num> which has the value <reg_num>. - 2. r.<reg_num> which has the value <reg_num>. - - - Each floating point register has predefined names of the form: - 1. f<reg_num> which has the value <reg_num>. - 2. f.<reg_num> which has the value <reg_num>. - - Each condition register has predefined names of the form: - 1. cr<reg_num> which has the value <reg_num>. - 2. cr.<reg_num> which has the value <reg_num>. - - There are individual registers as well: - sp or r.sp has the value 1 - rtoc or r.toc has the value 2 - fpscr has the value 0 - xer has the value 1 - lr has the value 8 - ctr has the value 9 - pmr has the value 0 - dar has the value 19 - dsisr has the value 18 - dec has the value 22 - sdr1 has the value 25 - srr0 has the value 26 - srr1 has the value 27 - - The table is sorted. Suitable for searching by a binary search. */ - -static const struct pd_reg pre_defined_registers[] = -{ - { "cr.0", 0 }, /* Condition Registers */ - { "cr.1", 1 }, - { "cr.2", 2 }, - { "cr.3", 3 }, - { "cr.4", 4 }, - { "cr.5", 5 }, - { "cr.6", 6 }, - { "cr.7", 7 }, - - { "cr0", 0 }, - { "cr1", 1 }, - { "cr2", 2 }, - { "cr3", 3 }, - { "cr4", 4 }, - { "cr5", 5 }, - { "cr6", 6 }, - { "cr7", 7 }, - - { "ctr", 9 }, - - { "dar", 19 }, /* Data Access Register */ - { "dec", 22 }, /* Decrementer */ - { "dsisr", 18 }, /* Data Storage Interrupt Status Register */ - - { "f.0", 0 }, /* Floating point registers */ - { "f.1", 1 }, - { "f.10", 10 }, - { "f.11", 11 }, - { "f.12", 12 }, - { "f.13", 13 }, - { "f.14", 14 }, - { "f.15", 15 }, - { "f.16", 16 }, - { "f.17", 17 }, - { "f.18", 18 }, - { "f.19", 19 }, - { "f.2", 2 }, - { "f.20", 20 }, - { "f.21", 21 }, - { "f.22", 22 }, - { "f.23", 23 }, - { "f.24", 24 }, - { "f.25", 25 }, - { "f.26", 26 }, - { "f.27", 27 }, - { "f.28", 28 }, - { "f.29", 29 }, - { "f.3", 3 }, - { "f.30", 30 }, - { "f.31", 31 }, - { "f.4", 4 }, - { "f.5", 5 }, - { "f.6", 6 }, - { "f.7", 7 }, - { "f.8", 8 }, - { "f.9", 9 }, - - { "f0", 0 }, - { "f1", 1 }, - { "f10", 10 }, - { "f11", 11 }, - { "f12", 12 }, - { "f13", 13 }, - { "f14", 14 }, - { "f15", 15 }, - { "f16", 16 }, - { "f17", 17 }, - { "f18", 18 }, - { "f19", 19 }, - { "f2", 2 }, - { "f20", 20 }, - { "f21", 21 }, - { "f22", 22 }, - { "f23", 23 }, - { "f24", 24 }, - { "f25", 25 }, - { "f26", 26 }, - { "f27", 27 }, - { "f28", 28 }, - { "f29", 29 }, - { "f3", 3 }, - { "f30", 30 }, - { "f31", 31 }, - { "f4", 4 }, - { "f5", 5 }, - { "f6", 6 }, - { "f7", 7 }, - { "f8", 8 }, - { "f9", 9 }, - - { "fpscr", 0 }, - - { "lr", 8 }, /* Link Register */ - - { "pmr", 0 }, - - { "r.0", 0 }, /* General Purpose Registers */ - { "r.1", 1 }, - { "r.10", 10 }, - { "r.11", 11 }, - { "r.12", 12 }, - { "r.13", 13 }, - { "r.14", 14 }, - { "r.15", 15 }, - { "r.16", 16 }, - { "r.17", 17 }, - { "r.18", 18 }, - { "r.19", 19 }, - { "r.2", 2 }, - { "r.20", 20 }, - { "r.21", 21 }, - { "r.22", 22 }, - { "r.23", 23 }, - { "r.24", 24 }, - { "r.25", 25 }, - { "r.26", 26 }, - { "r.27", 27 }, - { "r.28", 28 }, - { "r.29", 29 }, - { "r.3", 3 }, - { "r.30", 30 }, - { "r.31", 31 }, - { "r.4", 4 }, - { "r.5", 5 }, - { "r.6", 6 }, - { "r.7", 7 }, - { "r.8", 8 }, - { "r.9", 9 }, - - { "r.sp", 1 }, /* Stack Pointer */ - - { "r.toc", 2 }, /* Pointer to the table of contents */ - - { "r0", 0 }, /* More general purpose registers */ - { "r1", 1 }, - { "r10", 10 }, - { "r11", 11 }, - { "r12", 12 }, - { "r13", 13 }, - { "r14", 14 }, - { "r15", 15 }, - { "r16", 16 }, - { "r17", 17 }, - { "r18", 18 }, - { "r19", 19 }, - { "r2", 2 }, - { "r20", 20 }, - { "r21", 21 }, - { "r22", 22 }, - { "r23", 23 }, - { "r24", 24 }, - { "r25", 25 }, - { "r26", 26 }, - { "r27", 27 }, - { "r28", 28 }, - { "r29", 29 }, - { "r3", 3 }, - { "r30", 30 }, - { "r31", 31 }, - { "r4", 4 }, - { "r5", 5 }, - { "r6", 6 }, - { "r7", 7 }, - { "r8", 8 }, - { "r9", 9 }, - - { "rtoc", 2 }, /* Table of contents */ - - { "sdr1", 25 }, /* Storage Description Register 1 */ - - { "sp", 1 }, - - { "srr0", 26 }, /* Machine Status Save/Restore Register 0 */ - { "srr1", 27 }, /* Machine Status Save/Restore Register 1 */ - - { "xer", 1 }, - -}; - -#define REG_NAME_CNT (sizeof(pre_defined_registers) / sizeof(struct pd_reg)) - -/* Given NAME, find the register number associated with that name, return - the integer value associated with the given name or -1 on failure. */ - -static int reg_name_search - PARAMS ((const struct pd_reg *, int, const char * name)); - -static int -reg_name_search (regs, regcount, name) - const struct pd_reg *regs; - int regcount; - const char *name; -{ - int middle, low, high; - int cmp; - - low = 0; - high = regcount - 1; - - do - { - middle = (low + high) / 2; - cmp = strcasecmp (name, regs[middle].name); - if (cmp < 0) - high = middle - 1; - else if (cmp > 0) - low = middle + 1; - else - return regs[middle].value; - } - while (low <= high); - - return -1; -} - -/* - * Summary of register_name(). - * - * in: Input_line_pointer points to 1st char of operand. - * - * out: A expressionS. - * The operand may have been a register: in this case, X_op == O_register, - * X_add_number is set to the register number, and truth is returned. - * Input_line_pointer->(next non-blank) char after operand, or is in its - * original state. - */ - -static boolean -register_name (expressionP) - expressionS *expressionP; -{ - int reg_number; - char *name; - char *start; - char c; - - /* Find the spelling of the operand */ - start = name = input_line_pointer; - if (name[0] == '%' && isalpha (name[1])) - name = ++input_line_pointer; - - else if (!reg_names_p || !isalpha (name[0])) - return false; - - c = get_symbol_end (); - reg_number = reg_name_search (pre_defined_registers, REG_NAME_CNT, name); - - /* look to see if it's in the register table */ - if (reg_number >= 0) - { - expressionP->X_op = O_register; - expressionP->X_add_number = reg_number; - - /* make the rest nice */ - expressionP->X_add_symbol = NULL; - expressionP->X_op_symbol = NULL; - *input_line_pointer = c; /* put back the delimiting char */ - return true; - } - else - { - /* reset the line as if we had not done anything */ - *input_line_pointer = c; /* put back the delimiting char */ - input_line_pointer = start; /* reset input_line pointer */ - return false; - } -} - -/* This function is called for each symbol seen in an expression. It - handles the special parsing which PowerPC assemblers are supposed - to use for condition codes. */ - -/* Whether to do the special parsing. */ -static boolean cr_operand; - -/* Names to recognize in a condition code. This table is sorted. */ -static const struct pd_reg cr_names[] = -{ - { "cr0", 0 }, - { "cr1", 1 }, - { "cr2", 2 }, - { "cr3", 3 }, - { "cr4", 4 }, - { "cr5", 5 }, - { "cr6", 6 }, - { "cr7", 7 }, - { "eq", 2 }, - { "gt", 1 }, - { "lt", 0 }, - { "so", 3 }, - { "un", 3 } -}; - -/* Parsing function. This returns non-zero if it recognized an - expression. */ - -int -ppc_parse_name (name, expr) - const char *name; - expressionS *expr; -{ - int val; - - if (! cr_operand) - return 0; - - val = reg_name_search (cr_names, sizeof cr_names / sizeof cr_names[0], - name); - if (val < 0) - return 0; - - expr->X_op = O_constant; - expr->X_add_number = val; - - return 1; -} - -/* Local variables. */ - -/* The type of processor we are assembling for. This is one or more - of the PPC_OPCODE flags defined in opcode/ppc.h. */ -static int ppc_cpu = 0; - -/* The size of the processor we are assembling for. This is either - PPC_OPCODE_32 or PPC_OPCODE_64. */ -static unsigned long ppc_size = PPC_OPCODE_32; - -/* Opcode hash table. */ -static struct hash_control *ppc_hash; - -/* Macro hash table. */ -static struct hash_control *ppc_macro_hash; - -#ifdef OBJ_ELF -/* What type of shared library support to use */ -static enum { SHLIB_NONE, SHLIB_PIC, SHILB_MRELOCATABLE } shlib = SHLIB_NONE; - -/* Flags to set in the elf header */ -static flagword ppc_flags = 0; - -/* Whether this is Solaris or not. */ -#ifdef TARGET_SOLARIS_COMMENT -#define SOLARIS_P true -#else -#define SOLARIS_P false -#endif - -static boolean msolaris = SOLARIS_P; -#endif - -#ifdef OBJ_XCOFF - -/* The RS/6000 assembler uses the .csect pseudo-op to generate code - using a bunch of different sections. These assembler sections, - however, are all encompassed within the .text or .data sections of - the final output file. We handle this by using different - subsegments within these main segments. */ - -/* Next subsegment to allocate within the .text segment. */ -static subsegT ppc_text_subsegment = 2; - -/* Linked list of csects in the text section. */ -static symbolS *ppc_text_csects; - -/* Next subsegment to allocate within the .data segment. */ -static subsegT ppc_data_subsegment = 2; - -/* Linked list of csects in the data section. */ -static symbolS *ppc_data_csects; - -/* The current csect. */ -static symbolS *ppc_current_csect; - -/* The RS/6000 assembler uses a TOC which holds addresses of functions - and variables. Symbols are put in the TOC with the .tc pseudo-op. - A special relocation is used when accessing TOC entries. We handle - the TOC as a subsegment within the .data segment. We set it up if - we see a .toc pseudo-op, and save the csect symbol here. */ -static symbolS *ppc_toc_csect; - -/* The first frag in the TOC subsegment. */ -static fragS *ppc_toc_frag; - -/* The first frag in the first subsegment after the TOC in the .data - segment. NULL if there are no subsegments after the TOC. */ -static fragS *ppc_after_toc_frag; - -/* The current static block. */ -static symbolS *ppc_current_block; - -/* The COFF debugging section; set by md_begin. This is not the - .debug section, but is instead the secret BFD section which will - cause BFD to set the section number of a symbol to N_DEBUG. */ -static asection *ppc_coff_debug_section; - -#endif /* OBJ_XCOFF */ - -#ifdef TE_PE - -/* Various sections that we need for PE coff support. */ -static segT ydata_section; -static segT pdata_section; -static segT reldata_section; -static segT rdata_section; -static segT tocdata_section; - -/* The current section and the previous section. See ppc_previous. */ -static segT ppc_previous_section; -static segT ppc_current_section; - -#endif /* TE_PE */ - -#ifdef OBJ_ELF -symbolS *GOT_symbol; /* Pre-defined "_GLOBAL_OFFSET_TABLE" */ -#endif /* OBJ_ELF */ - -#ifdef OBJ_ELF -CONST char *md_shortopts = "b:l:usm:K:VQ:"; -#else -CONST char *md_shortopts = "um:"; -#endif -struct option md_longopts[] = { - {NULL, no_argument, NULL, 0} -}; -size_t md_longopts_size = sizeof(md_longopts); - -int -md_parse_option (c, arg) - int c; - char *arg; -{ - switch (c) - { - case 'u': - /* -u means that any undefined symbols should be treated as - external, which is the default for gas anyhow. */ - break; - -#ifdef OBJ_ELF - case 'l': - /* Solaris as takes -le (presumably for little endian). For completeness - sake, recognize -be also. */ - if (strcmp (arg, "e") == 0) - { - target_big_endian = 0; - set_target_endian = 1; - } - else - return 0; - - break; - - case 'b': - if (strcmp (arg, "e") == 0) - { - target_big_endian = 1; - set_target_endian = 1; - } - else - return 0; - - break; - - case 'K': - /* Recognize -K PIC */ - if (strcmp (arg, "PIC") == 0 || strcmp (arg, "pic") == 0) - { - shlib = SHLIB_PIC; - ppc_flags |= EF_PPC_RELOCATABLE_LIB; - } - else - return 0; - - break; -#endif - - case 'm': - /* -mpwrx and -mpwr2 mean to assemble for the IBM POWER/2 - (RIOS2). */ - if (strcmp (arg, "pwrx") == 0 || strcmp (arg, "pwr2") == 0) - ppc_cpu = PPC_OPCODE_POWER | PPC_OPCODE_POWER2; - /* -mpwr means to assemble for the IBM POWER (RIOS1). */ - else if (strcmp (arg, "pwr") == 0) - ppc_cpu = PPC_OPCODE_POWER; - /* -m601 means to assemble for the Motorola PowerPC 601, which includes - instructions that are holdovers from the Power. */ - else if (strcmp (arg, "601") == 0) - ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_601; - /* -mppc, -mppc32, -m603, and -m604 mean to assemble for the - Motorola PowerPC 603/604. */ - else if (strcmp (arg, "ppc") == 0 - || strcmp (arg, "ppc32") == 0 - || strcmp (arg, "403") == 0 - || strcmp (arg, "603") == 0 - || strcmp (arg, "604") == 0) - ppc_cpu = PPC_OPCODE_PPC; - /* -mppc64 and -m620 mean to assemble for the 64-bit PowerPC - 620. */ - else if (strcmp (arg, "ppc64") == 0 || strcmp (arg, "620") == 0) - { - ppc_cpu = PPC_OPCODE_PPC; - ppc_size = PPC_OPCODE_64; - } - else if (strcmp (arg, "ppc64bridge") == 0) - { - ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_64_BRIDGE; - ppc_size = PPC_OPCODE_64; - } - /* -mcom means assemble for the common intersection between Power - and PowerPC. At present, we just allow the union, rather - than the intersection. */ - else if (strcmp (arg, "com") == 0) - ppc_cpu = PPC_OPCODE_COMMON; - /* -many means to assemble for any architecture (PWR/PWRX/PPC). */ - else if (strcmp (arg, "any") == 0) - ppc_cpu = PPC_OPCODE_ANY; - - else if (strcmp (arg, "regnames") == 0) - reg_names_p = true; - - else if (strcmp (arg, "no-regnames") == 0) - reg_names_p = false; - -#ifdef OBJ_ELF - /* -mrelocatable/-mrelocatable-lib -- warn about initializations that require relocation */ - else if (strcmp (arg, "relocatable") == 0) - { - shlib = SHILB_MRELOCATABLE; - ppc_flags |= EF_PPC_RELOCATABLE; - } - - else if (strcmp (arg, "relocatable-lib") == 0) - { - shlib = SHILB_MRELOCATABLE; - ppc_flags |= EF_PPC_RELOCATABLE_LIB; - } - - /* -memb, set embedded bit */ - else if (strcmp (arg, "emb") == 0) - ppc_flags |= EF_PPC_EMB; - - /* -mlittle/-mbig set the endianess */ - else if (strcmp (arg, "little") == 0 || strcmp (arg, "little-endian") == 0) - { - target_big_endian = 0; - set_target_endian = 1; - } - - else if (strcmp (arg, "big") == 0 || strcmp (arg, "big-endian") == 0) - { - target_big_endian = 1; - set_target_endian = 1; - } - - else if (strcmp (arg, "solaris") == 0) - { - msolaris = true; - ppc_comment_chars = ppc_solaris_comment_chars; - } - - else if (strcmp (arg, "no-solaris") == 0) - { - msolaris = false; - ppc_comment_chars = ppc_eabi_comment_chars; - } -#endif - else - { - as_bad (_("invalid switch -m%s"), arg); - return 0; - } - break; - -#ifdef OBJ_ELF - /* -V: SVR4 argument to print version ID. */ - case 'V': - print_version_id (); - break; - - /* -Qy, -Qn: SVR4 arguments controlling whether a .comment section - should be emitted or not. FIXME: Not implemented. */ - case 'Q': - break; - - /* Solaris takes -s to specify that .stabs go in a .stabs section, - rather than .stabs.excl, which is ignored by the linker. - FIXME: Not implemented. */ - case 's': - if (arg) - return 0; - - break; -#endif - - default: - return 0; - } - - return 1; -} - -void -md_show_usage (stream) - FILE *stream; -{ - fprintf(stream, _("\ -PowerPC options:\n\ --u ignored\n\ --mpwrx, -mpwr2 generate code for IBM POWER/2 (RIOS2)\n\ --mpwr generate code for IBM POWER (RIOS1)\n\ --m601 generate code for Motorola PowerPC 601\n\ --mppc, -mppc32, -m403, -m603, -m604\n\ - generate code for Motorola PowerPC 603/604\n\ --mppc64, -m620 generate code for Motorola PowerPC 620\n\ --mppc64bridge generate code for PowerPC 64, including bridge insns\n\ --mcom generate code Power/PowerPC common instructions\n\ --many generate code for any architecture (PWR/PWRX/PPC)\n\ --mregnames Allow symbolic names for registers\n\ --mno-regnames Do not allow symbolic names for registers\n")); -#ifdef OBJ_ELF - fprintf(stream, _("\ --mrelocatable support for GCC's -mrelocatble option\n\ --mrelocatable-lib support for GCC's -mrelocatble-lib option\n\ --memb set PPC_EMB bit in ELF flags\n\ --mlittle, -mlittle-endian\n\ - generate code for a little endian machine\n\ --mbig, -mbig-endian generate code for a big endian machine\n\ --msolaris generate code for Solaris\n\ --mno-solaris do not generate code for Solaris\n\ --V print assembler version number\n\ --Qy, -Qn ignored\n")); -#endif -} - -/* Set ppc_cpu if it is not already set. */ - -static void -ppc_set_cpu () -{ - const char *default_os = TARGET_OS; - const char *default_cpu = TARGET_CPU; - - if (ppc_cpu == 0) - { - if (strncmp (default_os, "aix", 3) == 0 - && default_os[3] >= '4' && default_os[3] <= '9') - ppc_cpu = PPC_OPCODE_COMMON; - else if (strncmp (default_os, "aix3", 4) == 0) - ppc_cpu = PPC_OPCODE_POWER; - else if (strcmp (default_cpu, "rs6000") == 0) - ppc_cpu = PPC_OPCODE_POWER; - else if (strcmp (default_cpu, "powerpc") == 0 - || strcmp (default_cpu, "powerpcle") == 0) - ppc_cpu = PPC_OPCODE_PPC; - else - as_fatal (_("Unknown default cpu = %s, os = %s"), default_cpu, default_os); - } -} - -/* Figure out the BFD architecture to use. */ - -enum bfd_architecture -ppc_arch () -{ - const char *default_cpu = TARGET_CPU; - ppc_set_cpu (); - - if ((ppc_cpu & PPC_OPCODE_PPC) != 0) - return bfd_arch_powerpc; - else if ((ppc_cpu & PPC_OPCODE_POWER) != 0) - return bfd_arch_rs6000; - else if ((ppc_cpu & (PPC_OPCODE_COMMON | PPC_OPCODE_ANY)) != 0) - { - if (strcmp (default_cpu, "rs6000") == 0) - return bfd_arch_rs6000; - else if (strcmp (default_cpu, "powerpc") == 0 - || strcmp (default_cpu, "powerpcle") == 0) - return bfd_arch_powerpc; - } - - as_fatal (_("Neither Power nor PowerPC opcodes were selected.")); - return bfd_arch_unknown; -} - -/* This function is called when the assembler starts up. It is called - after the options have been parsed and the output file has been - opened. */ - -void -md_begin () -{ - register const struct powerpc_opcode *op; - const struct powerpc_opcode *op_end; - const struct powerpc_macro *macro; - const struct powerpc_macro *macro_end; - boolean dup_insn = false; - - ppc_set_cpu (); - -#ifdef OBJ_ELF - /* Set the ELF flags if desired. */ - if (ppc_flags && !msolaris) - bfd_set_private_flags (stdoutput, ppc_flags); -#endif - - /* Insert the opcodes into a hash table. */ - ppc_hash = hash_new (); - - op_end = powerpc_opcodes + powerpc_num_opcodes; - for (op = powerpc_opcodes; op < op_end; op++) - { - know ((op->opcode & op->mask) == op->opcode); - - if ((op->flags & ppc_cpu) != 0 - && ((op->flags & (PPC_OPCODE_32 | PPC_OPCODE_64)) == 0 - || (op->flags & (PPC_OPCODE_32 | PPC_OPCODE_64)) == ppc_size - || (ppc_cpu & PPC_OPCODE_64_BRIDGE) != 0)) - { - const char *retval; - - retval = hash_insert (ppc_hash, op->name, (PTR) op); - if (retval != (const char *) NULL) - { - /* Ignore Power duplicates for -m601 */ - if ((ppc_cpu & PPC_OPCODE_601) != 0 - && (op->flags & PPC_OPCODE_POWER) != 0) - continue; - - as_bad (_("Internal assembler error for instruction %s"), op->name); - dup_insn = true; - } - } - } - - /* Insert the macros into a hash table. */ - ppc_macro_hash = hash_new (); - - macro_end = powerpc_macros + powerpc_num_macros; - for (macro = powerpc_macros; macro < macro_end; macro++) - { - if ((macro->flags & ppc_cpu) != 0) - { - const char *retval; - - retval = hash_insert (ppc_macro_hash, macro->name, (PTR) macro); - if (retval != (const char *) NULL) - { - as_bad (_("Internal assembler error for macro %s"), macro->name); - dup_insn = true; - } - } - } - - if (dup_insn) - abort (); - - /* Tell the main code what the endianness is if it is not overidden by the user. */ - if (!set_target_endian) - { - set_target_endian = 1; - target_big_endian = PPC_BIG_ENDIAN; - } - -#ifdef OBJ_XCOFF - ppc_coff_debug_section = coff_section_from_bfd_index (stdoutput, N_DEBUG); - - /* Create dummy symbols to serve as initial csects. This forces the - text csects to precede the data csects. These symbols will not - be output. */ - ppc_text_csects = symbol_make ("dummy\001"); - symbol_get_tc (ppc_text_csects)->within = ppc_text_csects; - ppc_data_csects = symbol_make ("dummy\001"); - symbol_get_tc (ppc_data_csects)->within = ppc_data_csects; -#endif - -#ifdef TE_PE - - ppc_current_section = text_section; - ppc_previous_section = 0; - -#endif -} - -/* Insert an operand value into an instruction. */ - -static unsigned long -ppc_insert_operand (insn, operand, val, file, line) - unsigned long insn; - const struct powerpc_operand *operand; - offsetT val; - char *file; - unsigned int line; -{ - if (operand->bits != 32) - { - long min, max; - offsetT test; - - if ((operand->flags & PPC_OPERAND_SIGNED) != 0) - { - if ((operand->flags & PPC_OPERAND_SIGNOPT) != 0) - max = (1 << operand->bits) - 1; - else - max = (1 << (operand->bits - 1)) - 1; - min = - (1 << (operand->bits - 1)); - - if (ppc_size == PPC_OPCODE_32) - { - /* Some people write 32 bit hex constants with the sign - extension done by hand. This shouldn't really be - valid, but, to permit this code to assemble on a 64 - bit host, we sign extend the 32 bit value. */ - if (val > 0 - && (val & (offsetT) 0x80000000) != 0 - && (val & (offsetT) 0xffffffff) == val) - { - val -= 0x80000000; - val -= 0x80000000; - } - } - } - else - { - max = (1 << operand->bits) - 1; - min = 0; - } - - if ((operand->flags & PPC_OPERAND_NEGATIVE) != 0) - test = - val; - else - test = val; - - if (test < (offsetT) min || test > (offsetT) max) - { - const char *err = - _("operand out of range (%s not between %ld and %ld)"); - char buf[100]; - - sprint_value (buf, test); - if (file == (char *) NULL) - as_bad (err, buf, min, max); - else - as_bad_where (file, line, err, buf, min, max); - } - } - - if (operand->insert) - { - const char *errmsg; - - errmsg = NULL; - insn = (*operand->insert) (insn, (long) val, &errmsg); - if (errmsg != (const char *) NULL) - as_bad (errmsg); - } - else - insn |= (((long) val & ((1 << operand->bits) - 1)) - << operand->shift); - - return insn; -} - - -#ifdef OBJ_ELF -/* Parse @got, etc. and return the desired relocation. */ -static bfd_reloc_code_real_type -ppc_elf_suffix (str_p, exp_p) - char **str_p; - expressionS *exp_p; -{ - struct map_bfd { - char *string; - int length; - bfd_reloc_code_real_type reloc; - }; - - char ident[20]; - char *str = *str_p; - char *str2; - int ch; - int len; - struct map_bfd *ptr; - -#define MAP(str,reloc) { str, sizeof(str)-1, reloc } - - static struct map_bfd mapping[] = { - MAP ("l", BFD_RELOC_LO16), - MAP ("h", BFD_RELOC_HI16), - MAP ("ha", BFD_RELOC_HI16_S), - MAP ("brtaken", BFD_RELOC_PPC_B16_BRTAKEN), - MAP ("brntaken", BFD_RELOC_PPC_B16_BRNTAKEN), - MAP ("got", BFD_RELOC_16_GOTOFF), - MAP ("got@l", BFD_RELOC_LO16_GOTOFF), - MAP ("got@h", BFD_RELOC_HI16_GOTOFF), - MAP ("got@ha", BFD_RELOC_HI16_S_GOTOFF), - MAP ("fixup", BFD_RELOC_CTOR), /* warnings with -mrelocatable */ - MAP ("plt", BFD_RELOC_24_PLT_PCREL), - MAP ("pltrel24", BFD_RELOC_24_PLT_PCREL), - MAP ("copy", BFD_RELOC_PPC_COPY), - MAP ("globdat", BFD_RELOC_PPC_GLOB_DAT), - MAP ("local24pc", BFD_RELOC_PPC_LOCAL24PC), - MAP ("local", BFD_RELOC_PPC_LOCAL24PC), - MAP ("pltrel", BFD_RELOC_32_PLT_PCREL), - MAP ("plt@l", BFD_RELOC_LO16_PLTOFF), - MAP ("plt@h", BFD_RELOC_HI16_PLTOFF), - MAP ("plt@ha", BFD_RELOC_HI16_S_PLTOFF), - MAP ("sdarel", BFD_RELOC_GPREL16), - MAP ("sectoff", BFD_RELOC_32_BASEREL), - MAP ("sectoff@l", BFD_RELOC_LO16_BASEREL), - MAP ("sectoff@h", BFD_RELOC_HI16_BASEREL), - MAP ("sectoff@ha", BFD_RELOC_HI16_S_BASEREL), - MAP ("naddr", BFD_RELOC_PPC_EMB_NADDR32), - MAP ("naddr16", BFD_RELOC_PPC_EMB_NADDR16), - MAP ("naddr@l", BFD_RELOC_PPC_EMB_NADDR16_LO), - MAP ("naddr@h", BFD_RELOC_PPC_EMB_NADDR16_HI), - MAP ("naddr@ha", BFD_RELOC_PPC_EMB_NADDR16_HA), - MAP ("sdai16", BFD_RELOC_PPC_EMB_SDAI16), - MAP ("sda2rel", BFD_RELOC_PPC_EMB_SDA2REL), - MAP ("sda2i16", BFD_RELOC_PPC_EMB_SDA2I16), - MAP ("sda21", BFD_RELOC_PPC_EMB_SDA21), - MAP ("mrkref", BFD_RELOC_PPC_EMB_MRKREF), - MAP ("relsect", BFD_RELOC_PPC_EMB_RELSEC16), - MAP ("relsect@l", BFD_RELOC_PPC_EMB_RELST_LO), - MAP ("relsect@h", BFD_RELOC_PPC_EMB_RELST_HI), - MAP ("relsect@ha", BFD_RELOC_PPC_EMB_RELST_HA), - MAP ("bitfld", BFD_RELOC_PPC_EMB_BIT_FLD), - MAP ("relsda", BFD_RELOC_PPC_EMB_RELSDA), - MAP ("xgot", BFD_RELOC_PPC_TOC16), - - { (char *)0, 0, BFD_RELOC_UNUSED } - }; - - if (*str++ != '@') - return BFD_RELOC_UNUSED; - - for (ch = *str, str2 = ident; - (str2 < ident + sizeof (ident) - 1 - && (isalnum (ch) || ch == '@')); - ch = *++str) - { - *str2++ = (islower (ch)) ? ch : tolower (ch); - } - - *str2 = '\0'; - len = str2 - ident; - - ch = ident[0]; - for (ptr = &mapping[0]; ptr->length > 0; ptr++) - if (ch == ptr->string[0] - && len == ptr->length - && memcmp (ident, ptr->string, ptr->length) == 0) - { - if (exp_p->X_add_number != 0 - && (ptr->reloc == BFD_RELOC_16_GOTOFF - || ptr->reloc == BFD_RELOC_LO16_GOTOFF - || ptr->reloc == BFD_RELOC_HI16_GOTOFF - || ptr->reloc == BFD_RELOC_HI16_S_GOTOFF)) - as_warn (_("identifier+constant@got means identifier@got+constant")); - - /* Now check for identifier@suffix+constant */ - if (*str == '-' || *str == '+') - { - char *orig_line = input_line_pointer; - expressionS new_exp; - - input_line_pointer = str; - expression (&new_exp); - if (new_exp.X_op == O_constant) - { - exp_p->X_add_number += new_exp.X_add_number; - str = input_line_pointer; - } - - if (&input_line_pointer != str_p) - input_line_pointer = orig_line; - } - - *str_p = str; - return ptr->reloc; - } - - return BFD_RELOC_UNUSED; -} - -/* Like normal .long/.short/.word, except support @got, etc. */ -/* clobbers input_line_pointer, checks */ -/* end-of-line. */ -static void -ppc_elf_cons (nbytes) - register int nbytes; /* 1=.byte, 2=.word, 4=.long */ -{ - expressionS exp; - bfd_reloc_code_real_type reloc; - - if (is_it_end_of_statement ()) - { - demand_empty_rest_of_line (); - return; - } - - do - { - expression (&exp); - if (exp.X_op == O_symbol - && *input_line_pointer == '@' - && (reloc = ppc_elf_suffix (&input_line_pointer, &exp)) != BFD_RELOC_UNUSED) - { - reloc_howto_type *reloc_howto = bfd_reloc_type_lookup (stdoutput, reloc); - int size = bfd_get_reloc_size (reloc_howto); - - if (size > nbytes) - as_bad (_("%s relocations do not fit in %d bytes\n"), reloc_howto->name, nbytes); - - else - { - register char *p = frag_more ((int) nbytes); - int offset = nbytes - size; - - fix_new_exp (frag_now, p - frag_now->fr_literal + offset, size, &exp, 0, reloc); - } - } - else - emit_expr (&exp, (unsigned int) nbytes); - } - while (*input_line_pointer++ == ','); - - input_line_pointer--; /* Put terminator back into stream. */ - demand_empty_rest_of_line (); -} - -/* Solaris pseduo op to change to the .rodata section. */ -static void -ppc_elf_rdata (xxx) - int xxx; -{ - char *save_line = input_line_pointer; - static char section[] = ".rodata\n"; - - /* Just pretend this is .section .rodata */ - input_line_pointer = section; - obj_elf_section (xxx); - - input_line_pointer = save_line; -} - -/* Pseudo op to make file scope bss items */ -static void -ppc_elf_lcomm(xxx) - int xxx ATTRIBUTE_UNUSED; -{ - register char *name; - register char c; - register char *p; - offsetT size; - register symbolS *symbolP; - offsetT align; - segT old_sec; - int old_subsec; - char *pfrag; - int align2; - - name = input_line_pointer; - c = get_symbol_end (); - - /* just after name is now '\0' */ - p = input_line_pointer; - *p = c; - SKIP_WHITESPACE (); - if (*input_line_pointer != ',') - { - as_bad (_("Expected comma after symbol-name: rest of line ignored.")); - ignore_rest_of_line (); - return; - } - - input_line_pointer++; /* skip ',' */ - if ((size = get_absolute_expression ()) < 0) - { - as_warn (_(".COMMon length (%ld.) <0! Ignored."), (long) size); - ignore_rest_of_line (); - return; - } - - /* The third argument to .lcomm is the alignment. */ - if (*input_line_pointer != ',') - align = 8; - else - { - ++input_line_pointer; - align = get_absolute_expression (); - if (align <= 0) - { - as_warn (_("ignoring bad alignment")); - align = 8; - } - } - - *p = 0; - symbolP = symbol_find_or_make (name); - *p = c; - - if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP)) - { - as_bad (_("Ignoring attempt to re-define symbol `%s'."), - S_GET_NAME (symbolP)); - ignore_rest_of_line (); - return; - } - - if (S_GET_VALUE (symbolP) && S_GET_VALUE (symbolP) != (valueT) size) - { - as_bad (_("Length of .lcomm \"%s\" is already %ld. Not changed to %ld."), - S_GET_NAME (symbolP), - (long) S_GET_VALUE (symbolP), - (long) size); - - ignore_rest_of_line (); - return; - } - - /* allocate_bss: */ - old_sec = now_seg; - old_subsec = now_subseg; - if (align) - { - /* convert to a power of 2 alignment */ - for (align2 = 0; (align & 1) == 0; align >>= 1, ++align2); - if (align != 1) - { - as_bad (_("Common alignment not a power of 2")); - ignore_rest_of_line (); - return; - } - } - else - align2 = 0; - - record_alignment (bss_section, align2); - subseg_set (bss_section, 0); - if (align2) - frag_align (align2, 0, 0); - if (S_GET_SEGMENT (symbolP) == bss_section) - symbol_get_frag (symbolP)->fr_symbol = 0; - symbol_set_frag (symbolP, frag_now); - pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP, size, - (char *) 0); - *pfrag = 0; - S_SET_SIZE (symbolP, size); - S_SET_SEGMENT (symbolP, bss_section); - subseg_set (old_sec, old_subsec); - demand_empty_rest_of_line (); -} - -/* Validate any relocations emitted for -mrelocatable, possibly adding - fixups for word relocations in writable segments, so we can adjust - them at runtime. */ -static void -ppc_elf_validate_fix (fixp, seg) - fixS *fixp; - segT seg; -{ - if (fixp->fx_done || fixp->fx_pcrel) - return; - - switch (shlib) - { - case SHLIB_NONE: - case SHLIB_PIC: - return; - - case SHILB_MRELOCATABLE: - if (fixp->fx_r_type <= BFD_RELOC_UNUSED - && fixp->fx_r_type != BFD_RELOC_16_GOTOFF - && fixp->fx_r_type != BFD_RELOC_HI16_GOTOFF - && fixp->fx_r_type != BFD_RELOC_LO16_GOTOFF - && fixp->fx_r_type != BFD_RELOC_HI16_S_GOTOFF - && fixp->fx_r_type != BFD_RELOC_32_BASEREL - && fixp->fx_r_type != BFD_RELOC_LO16_BASEREL - && fixp->fx_r_type != BFD_RELOC_HI16_BASEREL - && fixp->fx_r_type != BFD_RELOC_HI16_S_BASEREL - && strcmp (segment_name (seg), ".got2") != 0 - && strcmp (segment_name (seg), ".dtors") != 0 - && strcmp (segment_name (seg), ".ctors") != 0 - && strcmp (segment_name (seg), ".fixup") != 0 - && strcmp (segment_name (seg), ".stab") != 0 - && strcmp (segment_name (seg), ".gcc_except_table") != 0 - && strcmp (segment_name (seg), ".eh_frame") != 0 - && strcmp (segment_name (seg), ".ex_shared") != 0) - { - if ((seg->flags & (SEC_READONLY | SEC_CODE)) != 0 - || fixp->fx_r_type != BFD_RELOC_CTOR) - { - as_bad_where (fixp->fx_file, fixp->fx_line, - _("Relocation cannot be done when using -mrelocatable")); - } - } - return; - } -} -#endif /* OBJ_ELF */ - -#ifdef TE_PE - -/* - * Summary of parse_toc_entry(). - * - * in: Input_line_pointer points to the '[' in one of: - * - * [toc] [tocv] [toc32] [toc64] - * - * Anything else is an error of one kind or another. - * - * out: - * return value: success or failure - * toc_kind: kind of toc reference - * input_line_pointer: - * success: first char after the ']' - * failure: unchanged - * - * settings: - * - * [toc] - rv == success, toc_kind = default_toc - * [tocv] - rv == success, toc_kind = data_in_toc - * [toc32] - rv == success, toc_kind = must_be_32 - * [toc64] - rv == success, toc_kind = must_be_64 - * - */ - -enum toc_size_qualifier -{ - default_toc, /* The toc cell constructed should be the system default size */ - data_in_toc, /* This is a direct reference to a toc cell */ - must_be_32, /* The toc cell constructed must be 32 bits wide */ - must_be_64 /* The toc cell constructed must be 64 bits wide */ -}; - -static int -parse_toc_entry(toc_kind) - enum toc_size_qualifier *toc_kind; -{ - char *start; - char *toc_spec; - char c; - enum toc_size_qualifier t; - - /* save the input_line_pointer */ - start = input_line_pointer; - - /* skip over the '[' , and whitespace */ - ++input_line_pointer; - SKIP_WHITESPACE (); - - /* find the spelling of the operand */ - toc_spec = input_line_pointer; - c = get_symbol_end (); - - if (strcmp(toc_spec, "toc") == 0) - { - t = default_toc; - } - else if (strcmp(toc_spec, "tocv") == 0) - { - t = data_in_toc; - } - else if (strcmp(toc_spec, "toc32") == 0) - { - t = must_be_32; - } - else if (strcmp(toc_spec, "toc64") == 0) - { - t = must_be_64; - } - else - { - as_bad (_("syntax error: invalid toc specifier `%s'"), toc_spec); - *input_line_pointer = c; /* put back the delimiting char */ - input_line_pointer = start; /* reset input_line pointer */ - return 0; - } - - /* now find the ']' */ - *input_line_pointer = c; /* put back the delimiting char */ - - SKIP_WHITESPACE (); /* leading whitespace could be there. */ - c = *input_line_pointer++; /* input_line_pointer->past char in c. */ - - if (c != ']') - { - as_bad (_("syntax error: expected `]', found `%c'"), c); - input_line_pointer = start; /* reset input_line pointer */ - return 0; - } - - *toc_kind = t; /* set return value */ - return 1; -} -#endif - - -/* We need to keep a list of fixups. We can't simply generate them as - we go, because that would require us to first create the frag, and - that would screw up references to ``.''. */ - -struct ppc_fixup -{ - expressionS exp; - int opindex; - bfd_reloc_code_real_type reloc; -}; - -#define MAX_INSN_FIXUPS (5) - -/* This routine is called for each instruction to be assembled. */ - -void -md_assemble (str) - char *str; -{ - char *s; - const struct powerpc_opcode *opcode; - unsigned long insn; - const unsigned char *opindex_ptr; - int skip_optional; - int need_paren; - int next_opindex; - struct ppc_fixup fixups[MAX_INSN_FIXUPS]; - int fc; - char *f; - int i; -#ifdef OBJ_ELF - bfd_reloc_code_real_type reloc; -#endif - - /* Get the opcode. */ - for (s = str; *s != '\0' && ! isspace (*s); s++) - ; - if (*s != '\0') - *s++ = '\0'; - - /* Look up the opcode in the hash table. */ - opcode = (const struct powerpc_opcode *) hash_find (ppc_hash, str); - if (opcode == (const struct powerpc_opcode *) NULL) - { - const struct powerpc_macro *macro; - - macro = (const struct powerpc_macro *) hash_find (ppc_macro_hash, str); - if (macro == (const struct powerpc_macro *) NULL) - as_bad (_("Unrecognized opcode: `%s'"), str); - else - ppc_macro (s, macro); - - return; - } - - insn = opcode->opcode; - - str = s; - while (isspace (*str)) - ++str; - - /* PowerPC operands are just expressions. The only real issue is - that a few operand types are optional. All cases which might use - an optional operand separate the operands only with commas (in - some cases parentheses are used, as in ``lwz 1,0(1)'' but such - cases never have optional operands). There is never more than - one optional operand for an instruction. So, before we start - seriously parsing the operands, we check to see if we have an - optional operand, and, if we do, we count the number of commas to - see whether the operand should be omitted. */ - skip_optional = 0; - for (opindex_ptr = opcode->operands; *opindex_ptr != 0; opindex_ptr++) - { - const struct powerpc_operand *operand; - - operand = &powerpc_operands[*opindex_ptr]; - if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0) - { - unsigned int opcount; - - /* There is an optional operand. Count the number of - commas in the input line. */ - if (*str == '\0') - opcount = 0; - else - { - opcount = 1; - s = str; - while ((s = strchr (s, ',')) != (char *) NULL) - { - ++opcount; - ++s; - } - } - - /* If there are fewer operands in the line then are called - for by the instruction, we want to skip the optional - operand. */ - if (opcount < strlen (opcode->operands)) - skip_optional = 1; - - break; - } - } - - /* Gather the operands. */ - need_paren = 0; - next_opindex = 0; - fc = 0; - for (opindex_ptr = opcode->operands; *opindex_ptr != 0; opindex_ptr++) - { - const struct powerpc_operand *operand; - const char *errmsg; - char *hold; - expressionS ex; - char endc; - - if (next_opindex == 0) - operand = &powerpc_operands[*opindex_ptr]; - else - { - operand = &powerpc_operands[next_opindex]; - next_opindex = 0; - } - - errmsg = NULL; - - /* If this is a fake operand, then we do not expect anything - from the input. */ - if ((operand->flags & PPC_OPERAND_FAKE) != 0) - { - insn = (*operand->insert) (insn, 0L, &errmsg); - if (errmsg != (const char *) NULL) - as_bad (errmsg); - continue; - } - - /* If this is an optional operand, and we are skipping it, just - insert a zero. */ - if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0 - && skip_optional) - { - if (operand->insert) - { - insn = (*operand->insert) (insn, 0L, &errmsg); - if (errmsg != (const char *) NULL) - as_bad (errmsg); - } - if ((operand->flags & PPC_OPERAND_NEXT) != 0) - next_opindex = *opindex_ptr + 1; - continue; - } - - /* Gather the operand. */ - hold = input_line_pointer; - input_line_pointer = str; - -#ifdef TE_PE - if (*input_line_pointer == '[') - { - /* We are expecting something like the second argument here: - - lwz r4,[toc].GS.0.static_int(rtoc) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - The argument following the `]' must be a symbol name, and the - register must be the toc register: 'rtoc' or '2' - - The effect is to 0 as the displacement field - in the instruction, and issue an IMAGE_REL_PPC_TOCREL16 (or - the appropriate variation) reloc against it based on the symbol. - The linker will build the toc, and insert the resolved toc offset. - - Note: - o The size of the toc entry is currently assumed to be - 32 bits. This should not be assumed to be a hard coded - number. - o In an effort to cope with a change from 32 to 64 bits, - there are also toc entries that are specified to be - either 32 or 64 bits: - lwz r4,[toc32].GS.0.static_int(rtoc) - lwz r4,[toc64].GS.0.static_int(rtoc) - These demand toc entries of the specified size, and the - instruction probably requires it. - */ - - int valid_toc; - enum toc_size_qualifier toc_kind; - bfd_reloc_code_real_type toc_reloc; - - /* go parse off the [tocXX] part */ - valid_toc = parse_toc_entry(&toc_kind); - - if (!valid_toc) - { - /* Note: message has already been issued. */ - /* FIXME: what sort of recovery should we do? */ - /* demand_rest_of_line(); return; ? */ - } - - /* Now get the symbol following the ']' */ - expression(&ex); - - switch (toc_kind) - { - case default_toc: - /* In this case, we may not have seen the symbol yet, since */ - /* it is allowed to appear on a .extern or .globl or just be */ - /* a label in the .data section. */ - toc_reloc = BFD_RELOC_PPC_TOC16; - break; - case data_in_toc: - /* 1. The symbol must be defined and either in the toc */ - /* section, or a global. */ - /* 2. The reloc generated must have the TOCDEFN flag set in */ - /* upper bit mess of the reloc type. */ - /* FIXME: It's a little confusing what the tocv qualifier can */ - /* be used for. At the very least, I've seen three */ - /* uses, only one of which I'm sure I can explain. */ - if (ex.X_op == O_symbol) - { - assert (ex.X_add_symbol != NULL); - if (symbol_get_bfdsym (ex.X_add_symbol)->section - != tocdata_section) - { - as_bad(_("[tocv] symbol is not a toc symbol")); - } - } - - toc_reloc = BFD_RELOC_PPC_TOC16; - break; - case must_be_32: - /* FIXME: these next two specifically specify 32/64 bit toc */ - /* entries. We don't support them today. Is this the */ - /* right way to say that? */ - toc_reloc = BFD_RELOC_UNUSED; - as_bad (_("Unimplemented toc32 expression modifier")); - break; - case must_be_64: - /* FIXME: see above */ - toc_reloc = BFD_RELOC_UNUSED; - as_bad (_("Unimplemented toc64 expression modifier")); - break; - default: - fprintf(stderr, - _("Unexpected return value [%d] from parse_toc_entry!\n"), - toc_kind); - abort(); - break; - } - - /* We need to generate a fixup for this expression. */ - if (fc >= MAX_INSN_FIXUPS) - as_fatal (_("too many fixups")); - - fixups[fc].reloc = toc_reloc; - fixups[fc].exp = ex; - fixups[fc].opindex = *opindex_ptr; - ++fc; - - /* Ok. We've set up the fixup for the instruction. Now make it - look like the constant 0 was found here */ - ex.X_unsigned = 1; - ex.X_op = O_constant; - ex.X_add_number = 0; - ex.X_add_symbol = NULL; - ex.X_op_symbol = NULL; - } - - else -#endif /* TE_PE */ - { - if (! register_name (&ex)) - { - if ((operand->flags & PPC_OPERAND_CR) != 0) - cr_operand = true; - expression (&ex); - cr_operand = false; - } - } - - str = input_line_pointer; - input_line_pointer = hold; - - if (ex.X_op == O_illegal) - as_bad (_("illegal operand")); - else if (ex.X_op == O_absent) - as_bad (_("missing operand")); - else if (ex.X_op == O_register) - { - insn = ppc_insert_operand (insn, operand, ex.X_add_number, - (char *) NULL, 0); - } - else if (ex.X_op == O_constant) - { -#ifdef OBJ_ELF - /* Allow @HA, @L, @H on constants. */ - char *orig_str = str; - - if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_UNUSED) - switch (reloc) - { - default: - str = orig_str; - break; - - case BFD_RELOC_LO16: - /* X_unsigned is the default, so if the user has done - something which cleared it, we always produce a - signed value. */ - if (ex.X_unsigned - && (operand->flags & PPC_OPERAND_SIGNED) == 0) - ex.X_add_number &= 0xffff; - else - ex.X_add_number = (((ex.X_add_number & 0xffff) - ^ 0x8000) - - 0x8000); - break; - - case BFD_RELOC_HI16: - ex.X_add_number = (ex.X_add_number >> 16) & 0xffff; - break; - - case BFD_RELOC_HI16_S: - ex.X_add_number = ((((ex.X_add_number >> 16) & 0xffff) - + ((ex.X_add_number >> 15) & 1)) - & 0xffff); - break; - } -#endif - insn = ppc_insert_operand (insn, operand, ex.X_add_number, - (char *) NULL, 0); - } -#ifdef OBJ_ELF - else if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_UNUSED) - { - /* For the absoulte forms of branchs, convert the PC relative form back into - the absolute. */ - if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0) - { - switch (reloc) - { - case BFD_RELOC_PPC_B26: - reloc = BFD_RELOC_PPC_BA26; - break; - case BFD_RELOC_PPC_B16: - reloc = BFD_RELOC_PPC_BA16; - break; - case BFD_RELOC_PPC_B16_BRTAKEN: - reloc = BFD_RELOC_PPC_BA16_BRTAKEN; - break; - case BFD_RELOC_PPC_B16_BRNTAKEN: - reloc = BFD_RELOC_PPC_BA16_BRNTAKEN; - break; - default: - break; - } - } - - /* We need to generate a fixup for this expression. */ - if (fc >= MAX_INSN_FIXUPS) - as_fatal (_("too many fixups")); - fixups[fc].exp = ex; - fixups[fc].opindex = 0; - fixups[fc].reloc = reloc; - ++fc; - } -#endif /* OBJ_ELF */ - - else - { - /* We need to generate a fixup for this expression. */ - if (fc >= MAX_INSN_FIXUPS) - as_fatal (_("too many fixups")); - fixups[fc].exp = ex; - fixups[fc].opindex = *opindex_ptr; - fixups[fc].reloc = BFD_RELOC_UNUSED; - ++fc; - } - - if (need_paren) - { - endc = ')'; - need_paren = 0; - } - else if ((operand->flags & PPC_OPERAND_PARENS) != 0) - { - endc = '('; - need_paren = 1; - } - else - endc = ','; - - /* The call to expression should have advanced str past any - whitespace. */ - if (*str != endc - && (endc != ',' || *str != '\0')) - { - as_bad (_("syntax error; found `%c' but expected `%c'"), *str, endc); - break; - } - - if (*str != '\0') - ++str; - } - - while (isspace (*str)) - ++str; - - if (*str != '\0') - as_bad (_("junk at end of line: `%s'"), str); - - /* Write out the instruction. */ - f = frag_more (4); - md_number_to_chars (f, insn, 4); - - /* Create any fixups. At this point we do not use a - bfd_reloc_code_real_type, but instead just use the - BFD_RELOC_UNUSED plus the operand index. This lets us easily - handle fixups for any operand type, although that is admittedly - not a very exciting feature. We pick a BFD reloc type in - md_apply_fix. */ - for (i = 0; i < fc; i++) - { - const struct powerpc_operand *operand; - - operand = &powerpc_operands[fixups[i].opindex]; - if (fixups[i].reloc != BFD_RELOC_UNUSED) - { - reloc_howto_type *reloc_howto = bfd_reloc_type_lookup (stdoutput, fixups[i].reloc); - int size; - int offset; - fixS *fixP; - - if (!reloc_howto) - abort (); - - size = bfd_get_reloc_size (reloc_howto); - offset = target_big_endian ? (4 - size) : 0; - - if (size < 1 || size > 4) - abort(); - - fixP = fix_new_exp (frag_now, f - frag_now->fr_literal + offset, size, - &fixups[i].exp, reloc_howto->pc_relative, - fixups[i].reloc); - - /* Turn off complaints that the addend is too large for things like - foo+100000@ha. */ - switch (fixups[i].reloc) - { - case BFD_RELOC_16_GOTOFF: - case BFD_RELOC_PPC_TOC16: - case BFD_RELOC_LO16: - case BFD_RELOC_HI16: - case BFD_RELOC_HI16_S: - fixP->fx_no_overflow = 1; - break; - default: - break; - } - } - else - fix_new_exp (frag_now, f - frag_now->fr_literal, 4, - &fixups[i].exp, - (operand->flags & PPC_OPERAND_RELATIVE) != 0, - ((bfd_reloc_code_real_type) - (fixups[i].opindex + (int) BFD_RELOC_UNUSED))); - } -} - -/* Handle a macro. Gather all the operands, transform them as - described by the macro, and call md_assemble recursively. All the - operands are separated by commas; we don't accept parentheses - around operands here. */ - -static void -ppc_macro (str, macro) - char *str; - const struct powerpc_macro *macro; -{ - char *operands[10]; - unsigned int count; - char *s; - unsigned int len; - const char *format; - int arg; - char *send; - char *complete; - - /* Gather the users operands into the operands array. */ - count = 0; - s = str; - while (1) - { - if (count >= sizeof operands / sizeof operands[0]) - break; - operands[count++] = s; - s = strchr (s, ','); - if (s == (char *) NULL) - break; - *s++ = '\0'; - } - - if (count != macro->operands) - { - as_bad (_("wrong number of operands")); - return; - } - - /* Work out how large the string must be (the size is unbounded - because it includes user input). */ - len = 0; - format = macro->format; - while (*format != '\0') - { - if (*format != '%') - { - ++len; - ++format; - } - else - { - arg = strtol (format + 1, &send, 10); - know (send != format && arg >= 0 && arg < count); - len += strlen (operands[arg]); - format = send; - } - } - - /* Put the string together. */ - complete = s = (char *) alloca (len + 1); - format = macro->format; - while (*format != '\0') - { - if (*format != '%') - *s++ = *format++; - else - { - arg = strtol (format + 1, &send, 10); - strcpy (s, operands[arg]); - s += strlen (s); - format = send; - } - } - *s = '\0'; - - /* Assemble the constructed instruction. */ - md_assemble (complete); -} - -#ifdef OBJ_ELF -/* For ELF, add support for SHF_EXCLUDE and SHT_ORDERED */ - -int -ppc_section_letter (letter, ptr_msg) - int letter; - char **ptr_msg; -{ - if (letter == 'e') - return SHF_EXCLUDE; - - *ptr_msg = _("Bad .section directive: want a,w,x,e in string"); - return 0; -} - -int -ppc_section_word (str, len) - char *str; - size_t len; -{ - if (len == 7 && strncmp (str, "exclude", 7) == 0) - return SHF_EXCLUDE; - - return -1; -} - -int -ppc_section_type (str, len) - char *str; - size_t len; -{ - if (len == 7 && strncmp (str, "ordered", 7) == 0) - return SHT_ORDERED; - - return -1; -} - -int -ppc_section_flags (flags, attr, type) - int flags; - int attr; - int type; -{ - if (type == SHT_ORDERED) - flags |= SEC_ALLOC | SEC_LOAD | SEC_SORT_ENTRIES; - - if (attr & SHF_EXCLUDE) - flags |= SEC_EXCLUDE; - - return flags; -} -#endif /* OBJ_ELF */ - - -/* Pseudo-op handling. */ - -/* The .byte pseudo-op. This is similar to the normal .byte - pseudo-op, but it can also take a single ASCII string. */ - -static void -ppc_byte (ignore) - int ignore ATTRIBUTE_UNUSED; -{ - if (*input_line_pointer != '\"') - { - cons (1); - return; - } - - /* Gather characters. A real double quote is doubled. Unusual - characters are not permitted. */ - ++input_line_pointer; - while (1) - { - char c; - - c = *input_line_pointer++; - - if (c == '\"') - { - if (*input_line_pointer != '\"') - break; - ++input_line_pointer; - } - - FRAG_APPEND_1_CHAR (c); - } - - demand_empty_rest_of_line (); -} - -#ifdef OBJ_XCOFF - -/* XCOFF specific pseudo-op handling. */ - -/* This is set if we are creating a .stabx symbol, since we don't want - to handle symbol suffixes for such symbols. */ -static boolean ppc_stab_symbol; - -/* The .comm and .lcomm pseudo-ops for XCOFF. XCOFF puts common - symbols in the .bss segment as though they were local common - symbols, and uses a different smclas. */ - -static void -ppc_comm (lcomm) - int lcomm; -{ - asection *current_seg = now_seg; - subsegT current_subseg = now_subseg; - char *name; - char endc; - char *end_name; - offsetT size; - offsetT align; - symbolS *lcomm_sym = NULL; - symbolS *sym; - char *pfrag; - - name = input_line_pointer; - endc = get_symbol_end (); - end_name = input_line_pointer; - *end_name = endc; - - if (*input_line_pointer != ',') - { - as_bad (_("missing size")); - ignore_rest_of_line (); - return; - } - ++input_line_pointer; - - size = get_absolute_expression (); - if (size < 0) - { - as_bad (_("negative size")); - ignore_rest_of_line (); - return; - } - - if (! lcomm) - { - /* The third argument to .comm is the alignment. */ - if (*input_line_pointer != ',') - align = 3; - else - { - ++input_line_pointer; - align = get_absolute_expression (); - if (align <= 0) - { - as_warn (_("ignoring bad alignment")); - align = 3; - } - } - } - else - { - char *lcomm_name; - char lcomm_endc; - - if (size <= 1) - align = 0; - else if (size <= 2) - align = 1; - else if (size <= 4) - align = 2; - else - align = 3; - - /* The third argument to .lcomm appears to be the real local - common symbol to create. References to the symbol named in - the first argument are turned into references to the third - argument. */ - if (*input_line_pointer != ',') - { - as_bad (_("missing real symbol name")); - ignore_rest_of_line (); - return; - } - ++input_line_pointer; - - lcomm_name = input_line_pointer; - lcomm_endc = get_symbol_end (); - - lcomm_sym = symbol_find_or_make (lcomm_name); - - *input_line_pointer = lcomm_endc; - } - - *end_name = '\0'; - sym = symbol_find_or_make (name); - *end_name = endc; - - if (S_IS_DEFINED (sym) - || S_GET_VALUE (sym) != 0) - { - as_bad (_("attempt to redefine symbol")); - ignore_rest_of_line (); - return; - } - - record_alignment (bss_section, align); - - if (! lcomm - || ! S_IS_DEFINED (lcomm_sym)) - { - symbolS *def_sym; - offsetT def_size; - - if (! lcomm) - { - def_sym = sym; - def_size = size; - S_SET_EXTERNAL (sym); - } - else - { - symbol_get_tc (lcomm_sym)->output = 1; - def_sym = lcomm_sym; - def_size = 0; - } - - subseg_set (bss_section, 1); - frag_align (align, 0, 0); - - symbol_set_frag (def_sym, frag_now); - pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, def_sym, - def_size, (char *) NULL); - *pfrag = 0; - S_SET_SEGMENT (def_sym, bss_section); - symbol_get_tc (def_sym)->align = align; - } - else if (lcomm) - { - /* Align the size of lcomm_sym. */ - symbol_get_frag (lcomm_sym)->fr_offset = - ((symbol_get_frag (lcomm_sym)->fr_offset + (1 << align) - 1) - &~ ((1 << align) - 1)); - if (align > symbol_get_tc (lcomm_sym)->align) - symbol_get_tc (lcomm_sym)->align = align; - } - - if (lcomm) - { - /* Make sym an offset from lcomm_sym. */ - S_SET_SEGMENT (sym, bss_section); - symbol_set_frag (sym, symbol_get_frag (lcomm_sym)); - S_SET_VALUE (sym, symbol_get_frag (lcomm_sym)->fr_offset); - symbol_get_frag (lcomm_sym)->fr_offset += size; - } - - subseg_set (current_seg, current_subseg); - - demand_empty_rest_of_line (); -} - -/* The .csect pseudo-op. This switches us into a different - subsegment. The first argument is a symbol whose value is the - start of the .csect. In COFF, csect symbols get special aux - entries defined by the x_csect field of union internal_auxent. The - optional second argument is the alignment (the default is 2). */ - -static void -ppc_csect (ignore) - int ignore; -{ - char *name; - char endc; - symbolS *sym; - - name = input_line_pointer; - endc = get_symbol_end (); - - sym = symbol_find_or_make (name); - - *input_line_pointer = endc; - - if (S_GET_NAME (sym)[0] == '\0') - { - /* An unnamed csect is assumed to be [PR]. */ - symbol_get_tc (sym)->class = XMC_PR; - } - - ppc_change_csect (sym); - - if (*input_line_pointer == ',') - { - ++input_line_pointer; - symbol_get_tc (sym)->align = get_absolute_expression (); - } - - demand_empty_rest_of_line (); -} - -/* Change to a different csect. */ - -static void -ppc_change_csect (sym) - symbolS *sym; -{ - if (S_IS_DEFINED (sym)) - subseg_set (S_GET_SEGMENT (sym), symbol_get_tc (sym)->subseg); - else - { - symbolS **list_ptr; - int after_toc; - int hold_chunksize; - symbolS *list; - - /* This is a new csect. We need to look at the symbol class to - figure out whether it should go in the text section or the - data section. */ - after_toc = 0; - switch (symbol_get_tc (sym)->class) - { - case XMC_PR: - case XMC_RO: - case XMC_DB: - case XMC_GL: - case XMC_XO: - case XMC_SV: - case XMC_TI: - case XMC_TB: - S_SET_SEGMENT (sym, text_section); - symbol_get_tc (sym)->subseg = ppc_text_subsegment; - ++ppc_text_subsegment; - list_ptr = &ppc_text_csects; - break; - case XMC_RW: - case XMC_TC0: - case XMC_TC: - case XMC_DS: - case XMC_UA: - case XMC_BS: - case XMC_UC: - if (ppc_toc_csect != NULL - && (symbol_get_tc (ppc_toc_csect)->subseg + 1 - == ppc_data_subsegment)) - after_toc = 1; - S_SET_SEGMENT (sym, data_section); - symbol_get_tc (sym)->subseg = ppc_data_subsegment; - ++ppc_data_subsegment; - list_ptr = &ppc_data_csects; - break; - default: - abort (); - } - - /* We set the obstack chunk size to a small value before - changing subsegments, so that we don't use a lot of memory - space for what may be a small section. */ - hold_chunksize = chunksize; - chunksize = 64; - - subseg_new (segment_name (S_GET_SEGMENT (sym)), - symbol_get_tc (sym)->subseg); - - chunksize = hold_chunksize; - - if (after_toc) - ppc_after_toc_frag = frag_now; - - symbol_set_frag (sym, frag_now); - S_SET_VALUE (sym, (valueT) frag_now_fix ()); - - symbol_get_tc (sym)->align = 2; - symbol_get_tc (sym)->output = 1; - symbol_get_tc (sym)->within = sym; - - for (list = *list_ptr; - symbol_get_tc (list)->next != (symbolS *) NULL; - list = symbol_get_tc (list)->next) - ; - symbol_get_tc (list)->next = sym; - - symbol_remove (sym, &symbol_rootP, &symbol_lastP); - symbol_append (sym, symbol_get_tc (list)->within, &symbol_rootP, - &symbol_lastP); - } - - ppc_current_csect = sym; -} - -/* This function handles the .text and .data pseudo-ops. These - pseudo-ops aren't really used by XCOFF; we implement them for the - convenience of people who aren't used to XCOFF. */ - -static void -ppc_section (type) - int type; -{ - const char *name; - symbolS *sym; - - if (type == 't') - name = ".text[PR]"; - else if (type == 'd') - name = ".data[RW]"; - else - abort (); - - sym = symbol_find_or_make (name); - - ppc_change_csect (sym); - - demand_empty_rest_of_line (); -} - -/* This function handles the .section pseudo-op. This is mostly to - give an error, since XCOFF only supports .text, .data and .bss, but - we do permit the user to name the text or data section. */ - -static void -ppc_named_section (ignore) - int ignore; -{ - char *user_name; - const char *real_name; - char c; - symbolS *sym; - - user_name = input_line_pointer; - c = get_symbol_end (); - - if (strcmp (user_name, ".text") == 0) - real_name = ".text[PR]"; - else if (strcmp (user_name, ".data") == 0) - real_name = ".data[RW]"; - else - { - as_bad (_("The XCOFF file format does not support arbitrary sections")); - *input_line_pointer = c; - ignore_rest_of_line (); - return; - } - - *input_line_pointer = c; - - sym = symbol_find_or_make (real_name); - - ppc_change_csect (sym); - - demand_empty_rest_of_line (); -} - -/* The .extern pseudo-op. We create an undefined symbol. */ - -static void -ppc_extern (ignore) - int ignore; -{ - char *name; - char endc; - - name = input_line_pointer; - endc = get_symbol_end (); - - (void) symbol_find_or_make (name); - - *input_line_pointer = endc; - - demand_empty_rest_of_line (); -} - -/* The .lglobl pseudo-op. Keep the symbol in the symbol table. */ - -static void -ppc_lglobl (ignore) - int ignore; -{ - char *name; - char endc; - symbolS *sym; - - name = input_line_pointer; - endc = get_symbol_end (); - - sym = symbol_find_or_make (name); - - *input_line_pointer = endc; - - symbol_get_tc (sym)->output = 1; - - demand_empty_rest_of_line (); -} - -/* The .rename pseudo-op. The RS/6000 assembler can rename symbols, - although I don't know why it bothers. */ - -static void -ppc_rename (ignore) - int ignore; -{ - char *name; - char endc; - symbolS *sym; - int len; - - name = input_line_pointer; - endc = get_symbol_end (); - - sym = symbol_find_or_make (name); - - *input_line_pointer = endc; - - if (*input_line_pointer != ',') - { - as_bad (_("missing rename string")); - ignore_rest_of_line (); - return; - } - ++input_line_pointer; - - symbol_get_tc (sym)->real_name = demand_copy_C_string (&len); - - demand_empty_rest_of_line (); -} - -/* The .stabx pseudo-op. This is similar to a normal .stabs - pseudo-op, but slightly different. A sample is - .stabx "main:F-1",.main,142,0 - The first argument is the symbol name to create. The second is the - value, and the third is the storage class. The fourth seems to be - always zero, and I am assuming it is the type. */ - -static void -ppc_stabx (ignore) - int ignore; -{ - char *name; - int len; - symbolS *sym; - expressionS exp; - - name = demand_copy_C_string (&len); - - if (*input_line_pointer != ',') - { - as_bad (_("missing value")); - return; - } - ++input_line_pointer; - - ppc_stab_symbol = true; - sym = symbol_make (name); - ppc_stab_symbol = false; - - symbol_get_tc (sym)->real_name = name; - - (void) expression (&exp); - - switch (exp.X_op) - { - case O_illegal: - case O_absent: - case O_big: - as_bad (_("illegal .stabx expression; zero assumed")); - exp.X_add_number = 0; - /* Fall through. */ - case O_constant: - S_SET_VALUE (sym, (valueT) exp.X_add_number); - symbol_set_frag (sym, &zero_address_frag); - break; - - case O_symbol: - if (S_GET_SEGMENT (exp.X_add_symbol) == undefined_section) - symbol_set_value_expression (sym, &exp); - else - { - S_SET_VALUE (sym, - exp.X_add_number + S_GET_VALUE (exp.X_add_symbol)); - symbol_set_frag (sym, symbol_get_frag (exp.X_add_symbol)); - } - break; - - default: - /* The value is some complex expression. This will probably - fail at some later point, but this is probably the right - thing to do here. */ - symbol_set_value_expression (sym, &exp); - break; - } - - S_SET_SEGMENT (sym, ppc_coff_debug_section); - symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING; - - if (*input_line_pointer != ',') - { - as_bad (_("missing class")); - return; - } - ++input_line_pointer; - - S_SET_STORAGE_CLASS (sym, get_absolute_expression ()); - - if (*input_line_pointer != ',') - { - as_bad (_("missing type")); - return; - } - ++input_line_pointer; - - S_SET_DATA_TYPE (sym, get_absolute_expression ()); - - symbol_get_tc (sym)->output = 1; - - if (S_GET_STORAGE_CLASS (sym) == C_STSYM) - symbol_get_tc (sym)->within = ppc_current_block; - - if (exp.X_op != O_symbol - || ! S_IS_EXTERNAL (exp.X_add_symbol) - || S_GET_SEGMENT (exp.X_add_symbol) != bss_section) - ppc_frob_label (sym); - else - { - symbol_remove (sym, &symbol_rootP, &symbol_lastP); - symbol_append (sym, exp.X_add_symbol, &symbol_rootP, &symbol_lastP); - if (symbol_get_tc (ppc_current_csect)->within == exp.X_add_symbol) - symbol_get_tc (ppc_current_csect)->within = sym; - } - - demand_empty_rest_of_line (); -} - -/* The .function pseudo-op. This takes several arguments. The first - argument seems to be the external name of the symbol. The second - argment seems to be the label for the start of the function. gcc - uses the same name for both. I have no idea what the third and - fourth arguments are meant to be. The optional fifth argument is - an expression for the size of the function. In COFF this symbol - gets an aux entry like that used for a csect. */ - -static void -ppc_function (ignore) - int ignore; -{ - char *name; - char endc; - char *s; - symbolS *ext_sym; - symbolS *lab_sym; - - name = input_line_pointer; - endc = get_symbol_end (); - - /* Ignore any [PR] suffix. */ - name = ppc_canonicalize_symbol_name (name); - s = strchr (name, '['); - if (s != (char *) NULL - && strcmp (s + 1, "PR]") == 0) - *s = '\0'; - - ext_sym = symbol_find_or_make (name); - - *input_line_pointer = endc; - - if (*input_line_pointer != ',') - { - as_bad (_("missing symbol name")); - ignore_rest_of_line (); - return; - } - ++input_line_pointer; - - name = input_line_pointer; - endc = get_symbol_end (); - - lab_sym = symbol_find_or_make (name); - - *input_line_pointer = endc; - - if (ext_sym != lab_sym) - { - expressionS exp; - - exp.X_op = O_symbol; - exp.X_add_symbol = lab_sym; - exp.X_op_symbol = NULL; - exp.X_add_number = 0; - exp.X_unsigned = 0; - symbol_set_value_expression (ext_sym, &exp); - } - - if (symbol_get_tc (ext_sym)->class == -1) - symbol_get_tc (ext_sym)->class = XMC_PR; - symbol_get_tc (ext_sym)->output = 1; - - if (*input_line_pointer == ',') - { - expressionS ignore; - - /* Ignore the third argument. */ - ++input_line_pointer; - expression (&ignore); - if (*input_line_pointer == ',') - { - /* Ignore the fourth argument. */ - ++input_line_pointer; - expression (&ignore); - if (*input_line_pointer == ',') - { - /* The fifth argument is the function size. */ - ++input_line_pointer; - symbol_get_tc (ext_sym)->size = symbol_new ("L0\001", - absolute_section, - (valueT) 0, - &zero_address_frag); - pseudo_set (symbol_get_tc (ext_sym)->size); - } - } - } - - S_SET_DATA_TYPE (ext_sym, DT_FCN << N_BTSHFT); - SF_SET_FUNCTION (ext_sym); - SF_SET_PROCESS (ext_sym); - coff_add_linesym (ext_sym); - - demand_empty_rest_of_line (); -} - -/* The .bf pseudo-op. This is just like a COFF C_FCN symbol named - ".bf". */ - -static void -ppc_bf (ignore) - int ignore; -{ - symbolS *sym; - - sym = symbol_make (".bf"); - S_SET_SEGMENT (sym, text_section); - symbol_set_frag (sym, frag_now); - S_SET_VALUE (sym, frag_now_fix ()); - S_SET_STORAGE_CLASS (sym, C_FCN); - - coff_line_base = get_absolute_expression (); - - S_SET_NUMBER_AUXILIARY (sym, 1); - SA_SET_SYM_LNNO (sym, coff_line_base); - - symbol_get_tc (sym)->output = 1; - - ppc_frob_label (sym); - - demand_empty_rest_of_line (); -} - -/* The .ef pseudo-op. This is just like a COFF C_FCN symbol named - ".ef", except that the line number is absolute, not relative to the - most recent ".bf" symbol. */ - -static void -ppc_ef (ignore) - int ignore; -{ - symbolS *sym; - - sym = symbol_make (".ef"); - S_SET_SEGMENT (sym, text_section); - symbol_set_frag (sym, frag_now); - S_SET_VALUE (sym, frag_now_fix ()); - S_SET_STORAGE_CLASS (sym, C_FCN); - S_SET_NUMBER_AUXILIARY (sym, 1); - SA_SET_SYM_LNNO (sym, get_absolute_expression ()); - symbol_get_tc (sym)->output = 1; - - ppc_frob_label (sym); - - demand_empty_rest_of_line (); -} - -/* The .bi and .ei pseudo-ops. These take a string argument and - generates a C_BINCL or C_EINCL symbol, which goes at the start of - the symbol list. */ - -static void -ppc_biei (ei) - int ei; -{ - static symbolS *last_biei; - - char *name; - int len; - symbolS *sym; - symbolS *look; - - name = demand_copy_C_string (&len); - - /* The value of these symbols is actually file offset. Here we set - the value to the index into the line number entries. In - ppc_frob_symbols we set the fix_line field, which will cause BFD - to do the right thing. */ - - sym = symbol_make (name); - /* obj-coff.c currently only handles line numbers correctly in the - .text section. */ - S_SET_SEGMENT (sym, text_section); - S_SET_VALUE (sym, coff_n_line_nos); - symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING; - - S_SET_STORAGE_CLASS (sym, ei ? C_EINCL : C_BINCL); - symbol_get_tc (sym)->output = 1; - - for (look = last_biei ? last_biei : symbol_rootP; - (look != (symbolS *) NULL - && (S_GET_STORAGE_CLASS (look) == C_FILE - || S_GET_STORAGE_CLASS (look) == C_BINCL - || S_GET_STORAGE_CLASS (look) == C_EINCL)); - look = symbol_next (look)) - ; - if (look != (symbolS *) NULL) - { - symbol_remove (sym, &symbol_rootP, &symbol_lastP); - symbol_insert (sym, look, &symbol_rootP, &symbol_lastP); - last_biei = sym; - } - - demand_empty_rest_of_line (); -} - -/* The .bs pseudo-op. This generates a C_BSTAT symbol named ".bs". - There is one argument, which is a csect symbol. The value of the - .bs symbol is the index of this csect symbol. */ - -static void -ppc_bs (ignore) - int ignore; -{ - char *name; - char endc; - symbolS *csect; - symbolS *sym; - - if (ppc_current_block != NULL) - as_bad (_("nested .bs blocks")); - - name = input_line_pointer; - endc = get_symbol_end (); - - csect = symbol_find_or_make (name); - - *input_line_pointer = endc; - - sym = symbol_make (".bs"); - S_SET_SEGMENT (sym, now_seg); - S_SET_STORAGE_CLASS (sym, C_BSTAT); - symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING; - symbol_get_tc (sym)->output = 1; - - symbol_get_tc (sym)->within = csect; - - ppc_frob_label (sym); - - ppc_current_block = sym; - - demand_empty_rest_of_line (); -} - -/* The .es pseudo-op. Generate a C_ESTART symbol named .es. */ - -static void -ppc_es (ignore) - int ignore; -{ - symbolS *sym; - - if (ppc_current_block == NULL) - as_bad (_(".es without preceding .bs")); - - sym = symbol_make (".es"); - S_SET_SEGMENT (sym, now_seg); - S_SET_STORAGE_CLASS (sym, C_ESTAT); - symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING; - symbol_get_tc (sym)->output = 1; - - ppc_frob_label (sym); - - ppc_current_block = NULL; - - demand_empty_rest_of_line (); -} - -/* The .bb pseudo-op. Generate a C_BLOCK symbol named .bb, with a - line number. */ - -static void -ppc_bb (ignore) - int ignore; -{ - symbolS *sym; - - sym = symbol_make (".bb"); - S_SET_SEGMENT (sym, text_section); - symbol_set_frag (sym, frag_now); - S_SET_VALUE (sym, frag_now_fix ()); - S_SET_STORAGE_CLASS (sym, C_BLOCK); - - S_SET_NUMBER_AUXILIARY (sym, 1); - SA_SET_SYM_LNNO (sym, get_absolute_expression ()); - - symbol_get_tc (sym)->output = 1; - - SF_SET_PROCESS (sym); - - ppc_frob_label (sym); - - demand_empty_rest_of_line (); -} - -/* The .eb pseudo-op. Generate a C_BLOCK symbol named .eb, with a - line number. */ - -static void -ppc_eb (ignore) - int ignore; -{ - symbolS *sym; - - sym = symbol_make (".eb"); - S_SET_SEGMENT (sym, text_section); - symbol_set_frag (sym, frag_now); - S_SET_VALUE (sym, frag_now_fix ()); - S_SET_STORAGE_CLASS (sym, C_BLOCK); - S_SET_NUMBER_AUXILIARY (sym, 1); - SA_SET_SYM_LNNO (sym, get_absolute_expression ()); - symbol_get_tc (sym)->output = 1; - - SF_SET_PROCESS (sym); - - ppc_frob_label (sym); - - demand_empty_rest_of_line (); -} - -/* The .bc pseudo-op. This just creates a C_BCOMM symbol with a - specified name. */ - -static void -ppc_bc (ignore) - int ignore; -{ - char *name; - int len; - symbolS *sym; - - name = demand_copy_C_string (&len); - sym = symbol_make (name); - S_SET_SEGMENT (sym, ppc_coff_debug_section); - symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING; - S_SET_STORAGE_CLASS (sym, C_BCOMM); - S_SET_VALUE (sym, 0); - symbol_get_tc (sym)->output = 1; - - ppc_frob_label (sym); - - demand_empty_rest_of_line (); -} - -/* The .ec pseudo-op. This just creates a C_ECOMM symbol. */ - -static void -ppc_ec (ignore) - int ignore; -{ - symbolS *sym; - - sym = symbol_make (".ec"); - S_SET_SEGMENT (sym, ppc_coff_debug_section); - symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING; - S_SET_STORAGE_CLASS (sym, C_ECOMM); - S_SET_VALUE (sym, 0); - symbol_get_tc (sym)->output = 1; - - ppc_frob_label (sym); - - demand_empty_rest_of_line (); -} - -/* The .toc pseudo-op. Switch to the .toc subsegment. */ - -static void -ppc_toc (ignore) - int ignore; -{ - if (ppc_toc_csect != (symbolS *) NULL) - subseg_set (data_section, symbol_get_tc (ppc_toc_csect)->subseg); - else - { - subsegT subseg; - symbolS *sym; - symbolS *list; - - subseg = ppc_data_subsegment; - ++ppc_data_subsegment; - - subseg_new (segment_name (data_section), subseg); - ppc_toc_frag = frag_now; - - sym = symbol_find_or_make ("TOC[TC0]"); - symbol_set_frag (sym, frag_now); - S_SET_SEGMENT (sym, data_section); - S_SET_VALUE (sym, (valueT) frag_now_fix ()); - symbol_get_tc (sym)->subseg = subseg; - symbol_get_tc (sym)->output = 1; - symbol_get_tc (sym)->within = sym; - - ppc_toc_csect = sym; - - for (list = ppc_data_csects; - symbol_get_tc (list)->next != (symbolS *) NULL; - list = symbol_get_tc (list)->next) - ; - symbol_get_tc (list)->next = sym; - - symbol_remove (sym, &symbol_rootP, &symbol_lastP); - symbol_append (sym, symbol_get_tc (list)->within, &symbol_rootP, - &symbol_lastP); - } - - ppc_current_csect = ppc_toc_csect; - - demand_empty_rest_of_line (); -} - -/* The AIX assembler automatically aligns the operands of a .long or - .short pseudo-op, and we want to be compatible. */ - -static void -ppc_xcoff_cons (log_size) - int log_size; -{ - frag_align (log_size, 0, 0); - record_alignment (now_seg, log_size); - cons (1 << log_size); -} - -static void -ppc_vbyte (dummy) - int dummy; -{ - expressionS exp; - int byte_count; - - (void) expression (&exp); - - if (exp.X_op != O_constant) - { - as_bad (_("non-constant byte count")); - return; - } - - byte_count = exp.X_add_number; - - if (*input_line_pointer != ',') - { - as_bad (_("missing value")); - return; - } - - ++input_line_pointer; - cons (byte_count); -} - -#endif /* OBJ_XCOFF */ - -/* The .tc pseudo-op. This is used when generating either XCOFF or - ELF. This takes two or more arguments. - - When generating XCOFF output, the first argument is the name to - give to this location in the toc; this will be a symbol with class - TC. The rest of the arguments are 4 byte values to actually put at - this location in the TOC; often there is just one more argument, a - relocateable symbol reference. - - When not generating XCOFF output, the arguments are the same, but - the first argument is simply ignored. */ - -static void -ppc_tc (ignore) - int ignore ATTRIBUTE_UNUSED; -{ -#ifdef OBJ_XCOFF - - /* Define the TOC symbol name. */ - { - char *name; - char endc; - symbolS *sym; - - if (ppc_toc_csect == (symbolS *) NULL - || ppc_toc_csect != ppc_current_csect) - { - as_bad (_(".tc not in .toc section")); - ignore_rest_of_line (); - return; - } - - name = input_line_pointer; - endc = get_symbol_end (); - - sym = symbol_find_or_make (name); - - *input_line_pointer = endc; - - if (S_IS_DEFINED (sym)) - { - symbolS *label; - - label = symbol_get_tc (ppc_current_csect)->within; - if (symbol_get_tc (label)->class != XMC_TC0) - { - as_bad (_(".tc with no label")); - ignore_rest_of_line (); - return; - } - - S_SET_SEGMENT (label, S_GET_SEGMENT (sym)); - symbol_set_frag (label, symbol_get_frag (sym)); - S_SET_VALUE (label, S_GET_VALUE (sym)); - - while (! is_end_of_line[(unsigned char) *input_line_pointer]) - ++input_line_pointer; - - return; - } - - S_SET_SEGMENT (sym, now_seg); - symbol_set_frag (sym, frag_now); - S_SET_VALUE (sym, (valueT) frag_now_fix ()); - symbol_get_tc (sym)->class = XMC_TC; - symbol_get_tc (sym)->output = 1; - - ppc_frob_label (sym); - } - -#else /* ! defined (OBJ_XCOFF) */ - - /* Skip the TOC symbol name. */ - while (is_part_of_name (*input_line_pointer) - || *input_line_pointer == '[' - || *input_line_pointer == ']' - || *input_line_pointer == '{' - || *input_line_pointer == '}') - ++input_line_pointer; - - /* Align to a four byte boundary. */ - frag_align (2, 0, 0); - record_alignment (now_seg, 2); - -#endif /* ! defined (OBJ_XCOFF) */ - - if (*input_line_pointer != ',') - demand_empty_rest_of_line (); - else - { - ++input_line_pointer; - cons (4); - } -} - -#ifdef TE_PE - -/* Pseudo-ops specific to the Windows NT PowerPC PE (coff) format */ - -/* Set the current section. */ -static void -ppc_set_current_section (new) - segT new; -{ - ppc_previous_section = ppc_current_section; - ppc_current_section = new; -} - -/* pseudo-op: .previous - behaviour: toggles the current section with the previous section. - errors: None - warnings: "No previous section" -*/ -static void -ppc_previous(ignore) - int ignore; -{ - symbolS *tmp; - - if (ppc_previous_section == NULL) - { - as_warn(_("No previous section to return to. Directive ignored.")); - return; - } - - subseg_set(ppc_previous_section, 0); - - ppc_set_current_section(ppc_previous_section); -} - -/* pseudo-op: .pdata - behaviour: predefined read only data section - double word aligned - errors: None - warnings: None - initial: .section .pdata "adr3" - a - don't know -- maybe a misprint - d - initialized data - r - readable - 3 - double word aligned (that would be 4 byte boundary) - - commentary: - Tag index tables (also known as the function table) for exception - handling, debugging, etc. - -*/ -static void -ppc_pdata(ignore) - int ignore; -{ - if (pdata_section == 0) - { - pdata_section = subseg_new (".pdata", 0); - - bfd_set_section_flags (stdoutput, pdata_section, - (SEC_ALLOC | SEC_LOAD | SEC_RELOC - | SEC_READONLY | SEC_DATA )); - - bfd_set_section_alignment (stdoutput, pdata_section, 2); - } - else - { - pdata_section = subseg_new(".pdata", 0); - } - ppc_set_current_section(pdata_section); -} - -/* pseudo-op: .ydata - behaviour: predefined read only data section - double word aligned - errors: None - warnings: None - initial: .section .ydata "drw3" - a - don't know -- maybe a misprint - d - initialized data - r - readable - 3 - double word aligned (that would be 4 byte boundary) - commentary: - Tag tables (also known as the scope table) for exception handling, - debugging, etc. -*/ -static void -ppc_ydata(ignore) - int ignore; -{ - if (ydata_section == 0) - { - ydata_section = subseg_new (".ydata", 0); - bfd_set_section_flags (stdoutput, ydata_section, - (SEC_ALLOC | SEC_LOAD | SEC_RELOC - | SEC_READONLY | SEC_DATA )); - - bfd_set_section_alignment (stdoutput, ydata_section, 3); - } - else - { - ydata_section = subseg_new (".ydata", 0); - } - ppc_set_current_section(ydata_section); -} - -/* pseudo-op: .reldata - behaviour: predefined read write data section - double word aligned (4-byte) - FIXME: relocation is applied to it - FIXME: what's the difference between this and .data? - errors: None - warnings: None - initial: .section .reldata "drw3" - d - initialized data - r - readable - w - writeable - 3 - double word aligned (that would be 8 byte boundary) - - commentary: - Like .data, but intended to hold data subject to relocation, such as - function descriptors, etc. -*/ -static void -ppc_reldata(ignore) - int ignore; -{ - if (reldata_section == 0) - { - reldata_section = subseg_new (".reldata", 0); - - bfd_set_section_flags (stdoutput, reldata_section, - ( SEC_ALLOC | SEC_LOAD | SEC_RELOC - | SEC_DATA )); - - bfd_set_section_alignment (stdoutput, reldata_section, 2); - } - else - { - reldata_section = subseg_new (".reldata", 0); - } - ppc_set_current_section(reldata_section); -} - -/* pseudo-op: .rdata - behaviour: predefined read only data section - double word aligned - errors: None - warnings: None - initial: .section .rdata "dr3" - d - initialized data - r - readable - 3 - double word aligned (that would be 4 byte boundary) -*/ -static void -ppc_rdata(ignore) - int ignore; -{ - if (rdata_section == 0) - { - rdata_section = subseg_new (".rdata", 0); - bfd_set_section_flags (stdoutput, rdata_section, - (SEC_ALLOC | SEC_LOAD | SEC_RELOC - | SEC_READONLY | SEC_DATA )); - - bfd_set_section_alignment (stdoutput, rdata_section, 2); - } - else - { - rdata_section = subseg_new (".rdata", 0); - } - ppc_set_current_section(rdata_section); -} - -/* pseudo-op: .ualong - behaviour: much like .int, with the exception that no alignment is - performed. - FIXME: test the alignment statement - errors: None - warnings: None -*/ -static void -ppc_ualong(ignore) - int ignore; -{ - /* try for long */ - cons ( 4 ); -} - -/* pseudo-op: .znop <symbol name> - behaviour: Issue a nop instruction - Issue a IMAGE_REL_PPC_IFGLUE relocation against it, using - the supplied symbol name. - errors: None - warnings: Missing symbol name -*/ -static void -ppc_znop(ignore) - int ignore; -{ - unsigned long insn; - const struct powerpc_opcode *opcode; - expressionS ex; - char *f; - - symbolS *sym; - - /* Strip out the symbol name */ - char *symbol_name; - char c; - char *name; - unsigned int exp; - flagword flags; - asection *sec; - - symbol_name = input_line_pointer; - c = get_symbol_end (); - - name = xmalloc (input_line_pointer - symbol_name + 1); - strcpy (name, symbol_name); - - sym = symbol_find_or_make (name); - - *input_line_pointer = c; - - SKIP_WHITESPACE (); - - /* Look up the opcode in the hash table. */ - opcode = (const struct powerpc_opcode *) hash_find (ppc_hash, "nop"); - - /* stick in the nop */ - insn = opcode->opcode; - - /* Write out the instruction. */ - f = frag_more (4); - md_number_to_chars (f, insn, 4); - fix_new (frag_now, - f - frag_now->fr_literal, - 4, - sym, - 0, - 0, - BFD_RELOC_16_GOT_PCREL); - -} - -/* pseudo-op: - behaviour: - errors: - warnings: -*/ -static void -ppc_pe_comm(lcomm) - int lcomm; -{ - register char *name; - register char c; - register char *p; - offsetT temp; - register symbolS *symbolP; - offsetT align; - - name = input_line_pointer; - c = get_symbol_end (); - - /* just after name is now '\0' */ - p = input_line_pointer; - *p = c; - SKIP_WHITESPACE (); - if (*input_line_pointer != ',') - { - as_bad (_("Expected comma after symbol-name: rest of line ignored.")); - ignore_rest_of_line (); - return; - } - - input_line_pointer++; /* skip ',' */ - if ((temp = get_absolute_expression ()) < 0) - { - as_warn (_(".COMMon length (%ld.) <0! Ignored."), (long) temp); - ignore_rest_of_line (); - return; - } - - if (! lcomm) - { - /* The third argument to .comm is the alignment. */ - if (*input_line_pointer != ',') - align = 3; - else - { - ++input_line_pointer; - align = get_absolute_expression (); - if (align <= 0) - { - as_warn (_("ignoring bad alignment")); - align = 3; - } - } - } - - *p = 0; - symbolP = symbol_find_or_make (name); - - *p = c; - if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP)) - { - as_bad (_("Ignoring attempt to re-define symbol `%s'."), - S_GET_NAME (symbolP)); - ignore_rest_of_line (); - return; - } - - if (S_GET_VALUE (symbolP)) - { - if (S_GET_VALUE (symbolP) != (valueT) temp) - as_bad (_("Length of .comm \"%s\" is already %ld. Not changed to %ld."), - S_GET_NAME (symbolP), - (long) S_GET_VALUE (symbolP), - (long) temp); - } - else - { - S_SET_VALUE (symbolP, (valueT) temp); - S_SET_EXTERNAL (symbolP); - } - - demand_empty_rest_of_line (); -} - -/* - * implement the .section pseudo op: - * .section name {, "flags"} - * ^ ^ - * | +--- optional flags: 'b' for bss - * | 'i' for info - * +-- section name 'l' for lib - * 'n' for noload - * 'o' for over - * 'w' for data - * 'd' (apparently m88k for data) - * 'x' for text - * But if the argument is not a quoted string, treat it as a - * subsegment number. - * - * FIXME: this is a copy of the section processing from obj-coff.c, with - * additions/changes for the moto-pas assembler support. There are three - * categories: - * - * FIXME: I just noticed this. This doesn't work at all really. It it - * setting bits that bfd probably neither understands or uses. The - * correct approach (?) will have to incorporate extra fields attached - * to the section to hold the system specific stuff. (krk) - * - * Section Contents: - * 'a' - unknown - referred to in documentation, but no definition supplied - * 'c' - section has code - * 'd' - section has initialized data - * 'u' - section has uninitialized data - * 'i' - section contains directives (info) - * 'n' - section can be discarded - * 'R' - remove section at link time - * - * Section Protection: - * 'r' - section is readable - * 'w' - section is writeable - * 'x' - section is executable - * 's' - section is sharable - * - * Section Alignment: - * '0' - align to byte boundary - * '1' - align to halfword undary - * '2' - align to word boundary - * '3' - align to doubleword boundary - * '4' - align to quadword boundary - * '5' - align to 32 byte boundary - * '6' - align to 64 byte boundary - * - */ - -void -ppc_pe_section (ignore) - int ignore; -{ - /* Strip out the section name */ - char *section_name; - char c; - char *name; - unsigned int exp; - flagword flags; - segT sec; - int align; - - section_name = input_line_pointer; - c = get_symbol_end (); - - name = xmalloc (input_line_pointer - section_name + 1); - strcpy (name, section_name); - - *input_line_pointer = c; - - SKIP_WHITESPACE (); - - exp = 0; - flags = SEC_NO_FLAGS; - - if (strcmp (name, ".idata$2") == 0) - { - align = 0; - } - else if (strcmp (name, ".idata$3") == 0) - { - align = 0; - } - else if (strcmp (name, ".idata$4") == 0) - { - align = 2; - } - else if (strcmp (name, ".idata$5") == 0) - { - align = 2; - } - else if (strcmp (name, ".idata$6") == 0) - { - align = 1; - } - else - align = 4; /* default alignment to 16 byte boundary */ - - if (*input_line_pointer == ',') - { - ++input_line_pointer; - SKIP_WHITESPACE (); - if (*input_line_pointer != '"') - exp = get_absolute_expression (); - else - { - ++input_line_pointer; - while (*input_line_pointer != '"' - && ! is_end_of_line[(unsigned char) *input_line_pointer]) - { - switch (*input_line_pointer) - { - /* Section Contents */ - case 'a': /* unknown */ - as_bad (_("Unsupported section attribute -- 'a'")); - break; - case 'c': /* code section */ - flags |= SEC_CODE; - break; - case 'd': /* section has initialized data */ - flags |= SEC_DATA; - break; - case 'u': /* section has uninitialized data */ - /* FIXME: This is IMAGE_SCN_CNT_UNINITIALIZED_DATA - in winnt.h */ - flags |= SEC_ROM; - break; - case 'i': /* section contains directives (info) */ - /* FIXME: This is IMAGE_SCN_LNK_INFO - in winnt.h */ - flags |= SEC_HAS_CONTENTS; - break; - case 'n': /* section can be discarded */ - flags &=~ SEC_LOAD; - break; - case 'R': /* Remove section at link time */ - flags |= SEC_NEVER_LOAD; - break; - - /* Section Protection */ - case 'r': /* section is readable */ - flags |= IMAGE_SCN_MEM_READ; - break; - case 'w': /* section is writeable */ - flags |= IMAGE_SCN_MEM_WRITE; - break; - case 'x': /* section is executable */ - flags |= IMAGE_SCN_MEM_EXECUTE; - break; - case 's': /* section is sharable */ - flags |= IMAGE_SCN_MEM_SHARED; - break; - - /* Section Alignment */ - case '0': /* align to byte boundary */ - flags |= IMAGE_SCN_ALIGN_1BYTES; - align = 0; - break; - case '1': /* align to halfword boundary */ - flags |= IMAGE_SCN_ALIGN_2BYTES; - align = 1; - break; - case '2': /* align to word boundary */ - flags |= IMAGE_SCN_ALIGN_4BYTES; - align = 2; - break; - case '3': /* align to doubleword boundary */ - flags |= IMAGE_SCN_ALIGN_8BYTES; - align = 3; - break; - case '4': /* align to quadword boundary */ - flags |= IMAGE_SCN_ALIGN_16BYTES; - align = 4; - break; - case '5': /* align to 32 byte boundary */ - flags |= IMAGE_SCN_ALIGN_32BYTES; - align = 5; - break; - case '6': /* align to 64 byte boundary */ - flags |= IMAGE_SCN_ALIGN_64BYTES; - align = 6; - break; - - default: - as_bad(_("unknown section attribute '%c'"), - *input_line_pointer); - break; - } - ++input_line_pointer; - } - if (*input_line_pointer == '"') - ++input_line_pointer; - } - } - - sec = subseg_new (name, (subsegT) exp); - - ppc_set_current_section(sec); - - if (flags != SEC_NO_FLAGS) - { - if (! bfd_set_section_flags (stdoutput, sec, flags)) - as_bad (_("error setting flags for \"%s\": %s"), - bfd_section_name (stdoutput, sec), - bfd_errmsg (bfd_get_error ())); - } - - bfd_set_section_alignment(stdoutput, sec, align); - -} - -static void -ppc_pe_function (ignore) - int ignore; -{ - char *name; - char endc; - symbolS *ext_sym; - - name = input_line_pointer; - endc = get_symbol_end (); - - ext_sym = symbol_find_or_make (name); - - *input_line_pointer = endc; - - S_SET_DATA_TYPE (ext_sym, DT_FCN << N_BTSHFT); - SF_SET_FUNCTION (ext_sym); - SF_SET_PROCESS (ext_sym); - coff_add_linesym (ext_sym); - - demand_empty_rest_of_line (); -} - -static void -ppc_pe_tocd (ignore) - int ignore; -{ - if (tocdata_section == 0) - { - tocdata_section = subseg_new (".tocd", 0); - /* FIXME: section flags won't work */ - bfd_set_section_flags (stdoutput, tocdata_section, - (SEC_ALLOC | SEC_LOAD | SEC_RELOC - | SEC_READONLY | SEC_DATA )); - - bfd_set_section_alignment (stdoutput, tocdata_section, 2); - } - else - { - rdata_section = subseg_new (".tocd", 0); - } - - ppc_set_current_section(tocdata_section); - - demand_empty_rest_of_line (); -} - -/* Don't adjust TOC relocs to use the section symbol. */ - -int -ppc_pe_fix_adjustable (fix) - fixS *fix; -{ - return fix->fx_r_type != BFD_RELOC_PPC_TOC16; -} - -#endif - -#ifdef OBJ_XCOFF - -/* XCOFF specific symbol and file handling. */ - -/* Canonicalize the symbol name. We use the to force the suffix, if - any, to use square brackets, and to be in upper case. */ - -char * -ppc_canonicalize_symbol_name (name) - char *name; -{ - char *s; - - if (ppc_stab_symbol) - return name; - - for (s = name; *s != '\0' && *s != '{' && *s != '['; s++) - ; - if (*s != '\0') - { - char brac; - - if (*s == '[') - brac = ']'; - else - { - *s = '['; - brac = '}'; - } - - for (s++; *s != '\0' && *s != brac; s++) - if (islower (*s)) - *s = toupper (*s); - - if (*s == '\0' || s[1] != '\0') - as_bad (_("bad symbol suffix")); - - *s = ']'; - } - - return name; -} - -/* Set the class of a symbol based on the suffix, if any. This is - called whenever a new symbol is created. */ - -void -ppc_symbol_new_hook (sym) - symbolS *sym; -{ - struct ppc_tc_sy *tc; - const char *s; - - tc = symbol_get_tc (sym); - tc->next = NULL; - tc->output = 0; - tc->class = -1; - tc->real_name = NULL; - tc->subseg = 0; - tc->align = 0; - tc->size = NULL; - tc->within = NULL; - - if (ppc_stab_symbol) - return; - - s = strchr (S_GET_NAME (sym), '['); - if (s == (const char *) NULL) - { - /* There is no suffix. */ - return; - } - - ++s; - - switch (s[0]) - { - case 'B': - if (strcmp (s, "BS]") == 0) - tc->class = XMC_BS; - break; - case 'D': - if (strcmp (s, "DB]") == 0) - tc->class = XMC_DB; - else if (strcmp (s, "DS]") == 0) - tc->class = XMC_DS; - break; - case 'G': - if (strcmp (s, "GL]") == 0) - tc->class = XMC_GL; - break; - case 'P': - if (strcmp (s, "PR]") == 0) - tc->class = XMC_PR; - break; - case 'R': - if (strcmp (s, "RO]") == 0) - tc->class = XMC_RO; - else if (strcmp (s, "RW]") == 0) - tc->class = XMC_RW; - break; - case 'S': - if (strcmp (s, "SV]") == 0) - tc->class = XMC_SV; - break; - case 'T': - if (strcmp (s, "TC]") == 0) - tc->class = XMC_TC; - else if (strcmp (s, "TI]") == 0) - tc->class = XMC_TI; - else if (strcmp (s, "TB]") == 0) - tc->class = XMC_TB; - else if (strcmp (s, "TC0]") == 0 || strcmp (s, "T0]") == 0) - tc->class = XMC_TC0; - break; - case 'U': - if (strcmp (s, "UA]") == 0) - tc->class = XMC_UA; - else if (strcmp (s, "UC]") == 0) - tc->class = XMC_UC; - break; - case 'X': - if (strcmp (s, "XO]") == 0) - tc->class = XMC_XO; - break; - } - - if (tc->class == -1) - as_bad (_("Unrecognized symbol suffix")); -} - -/* Set the class of a label based on where it is defined. This - handles symbols without suffixes. Also, move the symbol so that it - follows the csect symbol. */ - -void -ppc_frob_label (sym) - symbolS *sym; -{ - if (ppc_current_csect != (symbolS *) NULL) - { - if (symbol_get_tc (sym)->class == -1) - symbol_get_tc (sym)->class = symbol_get_tc (ppc_current_csect)->class; - - symbol_remove (sym, &symbol_rootP, &symbol_lastP); - symbol_append (sym, symbol_get_tc (ppc_current_csect)->within, - &symbol_rootP, &symbol_lastP); - symbol_get_tc (ppc_current_csect)->within = sym; - } -} - -/* This variable is set by ppc_frob_symbol if any absolute symbols are - seen. It tells ppc_adjust_symtab whether it needs to look through - the symbols. */ - -static boolean ppc_saw_abs; - -/* Change the name of a symbol just before writing it out. Set the - real name if the .rename pseudo-op was used. Otherwise, remove any - class suffix. Return 1 if the symbol should not be included in the - symbol table. */ - -int -ppc_frob_symbol (sym) - symbolS *sym; -{ - static symbolS *ppc_last_function; - static symbolS *set_end; - - /* Discard symbols that should not be included in the output symbol - table. */ - if (! symbol_used_in_reloc_p (sym) - && ((symbol_get_bfdsym (sym)->flags & BSF_SECTION_SYM) != 0 - || (! S_IS_EXTERNAL (sym) - && ! symbol_get_tc (sym)->output - && S_GET_STORAGE_CLASS (sym) != C_FILE))) - return 1; - - if (symbol_get_tc (sym)->real_name != (char *) NULL) - S_SET_NAME (sym, symbol_get_tc (sym)->real_name); - else - { - const char *name; - const char *s; - - name = S_GET_NAME (sym); - s = strchr (name, '['); - if (s != (char *) NULL) - { - unsigned int len; - char *snew; - - len = s - name; - snew = xmalloc (len + 1); - memcpy (snew, name, len); - snew[len] = '\0'; - - S_SET_NAME (sym, snew); - } - } - - if (set_end != (symbolS *) NULL) - { - SA_SET_SYM_ENDNDX (set_end, sym); - set_end = NULL; - } - - if (SF_GET_FUNCTION (sym)) - { - if (ppc_last_function != (symbolS *) NULL) - as_bad (_("two .function pseudo-ops with no intervening .ef")); - ppc_last_function = sym; - if (symbol_get_tc (sym)->size != (symbolS *) NULL) - { - resolve_symbol_value (symbol_get_tc (sym)->size, 1); - SA_SET_SYM_FSIZE (sym, - (long) S_GET_VALUE (symbol_get_tc (sym)->size)); - } - } - else if (S_GET_STORAGE_CLASS (sym) == C_FCN - && strcmp (S_GET_NAME (sym), ".ef") == 0) - { - if (ppc_last_function == (symbolS *) NULL) - as_bad (_(".ef with no preceding .function")); - else - { - set_end = ppc_last_function; - ppc_last_function = NULL; - - /* We don't have a C_EFCN symbol, but we need to force the - COFF backend to believe that it has seen one. */ - coff_last_function = NULL; - } - } - - if (! S_IS_EXTERNAL (sym) - && (symbol_get_bfdsym (sym)->flags & BSF_SECTION_SYM) == 0 - && S_GET_STORAGE_CLASS (sym) != C_FILE - && S_GET_STORAGE_CLASS (sym) != C_FCN - && S_GET_STORAGE_CLASS (sym) != C_BLOCK - && S_GET_STORAGE_CLASS (sym) != C_BSTAT - && S_GET_STORAGE_CLASS (sym) != C_ESTAT - && S_GET_STORAGE_CLASS (sym) != C_BINCL - && S_GET_STORAGE_CLASS (sym) != C_EINCL - && S_GET_SEGMENT (sym) != ppc_coff_debug_section) - S_SET_STORAGE_CLASS (sym, C_HIDEXT); - - if (S_GET_STORAGE_CLASS (sym) == C_EXT - || S_GET_STORAGE_CLASS (sym) == C_HIDEXT) - { - int i; - union internal_auxent *a; - - /* Create a csect aux. */ - i = S_GET_NUMBER_AUXILIARY (sym); - S_SET_NUMBER_AUXILIARY (sym, i + 1); - a = &coffsymbol (symbol_get_bfdsym (sym))->native[i + 1].u.auxent; - if (symbol_get_tc (sym)->class == XMC_TC0) - { - /* This is the TOC table. */ - know (strcmp (S_GET_NAME (sym), "TOC") == 0); - a->x_csect.x_scnlen.l = 0; - a->x_csect.x_smtyp = (2 << 3) | XTY_SD; - } - else if (symbol_get_tc (sym)->subseg != 0) - { - /* This is a csect symbol. x_scnlen is the size of the - csect. */ - if (symbol_get_tc (sym)->next == (symbolS *) NULL) - a->x_csect.x_scnlen.l = (bfd_section_size (stdoutput, - S_GET_SEGMENT (sym)) - - S_GET_VALUE (sym)); - else - { - resolve_symbol_value (symbol_get_tc (sym)->next, 1); - a->x_csect.x_scnlen.l = (S_GET_VALUE (symbol_get_tc (sym)->next) - - S_GET_VALUE (sym)); - } - a->x_csect.x_smtyp = (symbol_get_tc (sym)->align << 3) | XTY_SD; - } - else if (S_GET_SEGMENT (sym) == bss_section) - { - /* This is a common symbol. */ - a->x_csect.x_scnlen.l = symbol_get_frag (sym)->fr_offset; - a->x_csect.x_smtyp = (symbol_get_tc (sym)->align << 3) | XTY_CM; - if (S_IS_EXTERNAL (sym)) - symbol_get_tc (sym)->class = XMC_RW; - else - symbol_get_tc (sym)->class = XMC_BS; - } - else if (S_GET_SEGMENT (sym) == absolute_section) - { - /* This is an absolute symbol. The csect will be created by - ppc_adjust_symtab. */ - ppc_saw_abs = true; - a->x_csect.x_smtyp = XTY_LD; - if (symbol_get_tc (sym)->class == -1) - symbol_get_tc (sym)->class = XMC_XO; - } - else if (! S_IS_DEFINED (sym)) - { - /* This is an external symbol. */ - a->x_csect.x_scnlen.l = 0; - a->x_csect.x_smtyp = XTY_ER; - } - else if (symbol_get_tc (sym)->class == XMC_TC) - { - symbolS *next; - - /* This is a TOC definition. x_scnlen is the size of the - TOC entry. */ - next = symbol_next (sym); - while (symbol_get_tc (next)->class == XMC_TC0) - next = symbol_next (next); - if (next == (symbolS *) NULL - || symbol_get_tc (next)->class != XMC_TC) - { - if (ppc_after_toc_frag == (fragS *) NULL) - a->x_csect.x_scnlen.l = (bfd_section_size (stdoutput, - data_section) - - S_GET_VALUE (sym)); - else - a->x_csect.x_scnlen.l = (ppc_after_toc_frag->fr_address - - S_GET_VALUE (sym)); - } - else - { - resolve_symbol_value (next, 1); - a->x_csect.x_scnlen.l = (S_GET_VALUE (next) - - S_GET_VALUE (sym)); - } - a->x_csect.x_smtyp = (2 << 3) | XTY_SD; - } - else - { - symbolS *csect; - - /* This is a normal symbol definition. x_scnlen is the - symbol index of the containing csect. */ - if (S_GET_SEGMENT (sym) == text_section) - csect = ppc_text_csects; - else if (S_GET_SEGMENT (sym) == data_section) - csect = ppc_data_csects; - else - abort (); - - /* Skip the initial dummy symbol. */ - csect = symbol_get_tc (csect)->next; - - if (csect == (symbolS *) NULL) - { - as_warn (_("warning: symbol %s has no csect"), S_GET_NAME (sym)); - a->x_csect.x_scnlen.l = 0; - } - else - { - while (symbol_get_tc (csect)->next != (symbolS *) NULL) - { - resolve_symbol_value (symbol_get_tc (csect)->next, 1); - if (S_GET_VALUE (symbol_get_tc (csect)->next) - > S_GET_VALUE (sym)) - break; - csect = symbol_get_tc (csect)->next; - } - - a->x_csect.x_scnlen.p = - coffsymbol (symbol_get_bfdsym (csect))->native; - coffsymbol (symbol_get_bfdsym (sym))->native[i + 1].fix_scnlen = - 1; - } - a->x_csect.x_smtyp = XTY_LD; - } - - a->x_csect.x_parmhash = 0; - a->x_csect.x_snhash = 0; - if (symbol_get_tc (sym)->class == -1) - a->x_csect.x_smclas = XMC_PR; - else - a->x_csect.x_smclas = symbol_get_tc (sym)->class; - a->x_csect.x_stab = 0; - a->x_csect.x_snstab = 0; - - /* Don't let the COFF backend resort these symbols. */ - symbol_get_bfdsym (sym)->flags |= BSF_NOT_AT_END; - } - else if (S_GET_STORAGE_CLASS (sym) == C_BSTAT) - { - /* We want the value to be the symbol index of the referenced - csect symbol. BFD will do that for us if we set the right - flags. */ - S_SET_VALUE (sym, - ((valueT) - coffsymbol (symbol_get_bfdsym - (symbol_get_tc (sym)->within))->native)); - coffsymbol (symbol_get_bfdsym (sym))->native->fix_value = 1; - } - else if (S_GET_STORAGE_CLASS (sym) == C_STSYM) - { - symbolS *block; - symbolS *csect; - - /* The value is the offset from the enclosing csect. */ - block = symbol_get_tc (sym)->within; - csect = symbol_get_tc (block)->within; - resolve_symbol_value (csect, 1); - S_SET_VALUE (sym, S_GET_VALUE (sym) - S_GET_VALUE (csect)); - } - else if (S_GET_STORAGE_CLASS (sym) == C_BINCL - || S_GET_STORAGE_CLASS (sym) == C_EINCL) - { - /* We want the value to be a file offset into the line numbers. - BFD will do that for us if we set the right flags. We have - already set the value correctly. */ - coffsymbol (symbol_get_bfdsym (sym))->native->fix_line = 1; - } - - return 0; -} - -/* Adjust the symbol table. This creates csect symbols for all - absolute symbols. */ - -void -ppc_adjust_symtab () -{ - symbolS *sym; - - if (! ppc_saw_abs) - return; - - for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym)) - { - symbolS *csect; - int i; - union internal_auxent *a; - - if (S_GET_SEGMENT (sym) != absolute_section) - continue; - - csect = symbol_create (".abs[XO]", absolute_section, - S_GET_VALUE (sym), &zero_address_frag); - symbol_get_bfdsym (csect)->value = S_GET_VALUE (sym); - S_SET_STORAGE_CLASS (csect, C_HIDEXT); - i = S_GET_NUMBER_AUXILIARY (csect); - S_SET_NUMBER_AUXILIARY (csect, i + 1); - a = &coffsymbol (symbol_get_bfdsym (csect))->native[i + 1].u.auxent; - a->x_csect.x_scnlen.l = 0; - a->x_csect.x_smtyp = XTY_SD; - a->x_csect.x_parmhash = 0; - a->x_csect.x_snhash = 0; - a->x_csect.x_smclas = XMC_XO; - a->x_csect.x_stab = 0; - a->x_csect.x_snstab = 0; - - symbol_insert (csect, sym, &symbol_rootP, &symbol_lastP); - - i = S_GET_NUMBER_AUXILIARY (sym); - a = &coffsymbol (symbol_get_bfdsym (sym))->native[i].u.auxent; - a->x_csect.x_scnlen.p = coffsymbol (symbol_get_bfdsym (csect))->native; - coffsymbol (symbol_get_bfdsym (sym))->native[i].fix_scnlen = 1; - } - - ppc_saw_abs = false; -} - -/* Set the VMA for a section. This is called on all the sections in - turn. */ - -void -ppc_frob_section (sec) - asection *sec; -{ - static bfd_size_type vma = 0; - - bfd_set_section_vma (stdoutput, sec, vma); - vma += bfd_section_size (stdoutput, sec); -} - -#endif /* OBJ_XCOFF */ - -/* Turn a string in input_line_pointer into a floating point constant - of type type, and store the appropriate bytes in *litp. The number - of LITTLENUMS emitted is stored in *sizep . An error message is - returned, or NULL on OK. */ - -char * -md_atof (type, litp, sizep) - int type; - char *litp; - int *sizep; -{ - int prec; - LITTLENUM_TYPE words[4]; - char *t; - int i; - - switch (type) - { - case 'f': - prec = 2; - break; - - case 'd': - prec = 4; - break; - - default: - *sizep = 0; - return _("bad call to md_atof"); - } - - t = atof_ieee (input_line_pointer, type, words); - if (t) - input_line_pointer = t; - - *sizep = prec * 2; - - if (target_big_endian) - { - for (i = 0; i < prec; i++) - { - md_number_to_chars (litp, (valueT) words[i], 2); - litp += 2; - } - } - else - { - for (i = prec - 1; i >= 0; i--) - { - md_number_to_chars (litp, (valueT) words[i], 2); - litp += 2; - } - } - - return NULL; -} - -/* Write a value out to the object file, using the appropriate - endianness. */ - -void -md_number_to_chars (buf, val, n) - char *buf; - valueT val; - int n; -{ - if (target_big_endian) - number_to_chars_bigendian (buf, val, n); - else - number_to_chars_littleendian (buf, val, n); -} - -/* Align a section (I don't know why this is machine dependent). */ - -valueT -md_section_align (seg, addr) - asection *seg; - valueT addr; -{ - int align = bfd_get_section_alignment (stdoutput, seg); - - return ((addr + (1 << align) - 1) & (-1 << align)); -} - -/* We don't have any form of relaxing. */ - -int -md_estimate_size_before_relax (fragp, seg) - fragS *fragp ATTRIBUTE_UNUSED; - asection *seg ATTRIBUTE_UNUSED; -{ - abort (); - return 0; -} - -/* Convert a machine dependent frag. We never generate these. */ - -void -md_convert_frag (abfd, sec, fragp) - bfd *abfd ATTRIBUTE_UNUSED; - asection *sec ATTRIBUTE_UNUSED; - fragS *fragp ATTRIBUTE_UNUSED; -{ - abort (); -} - -/* We have no need to default values of symbols. */ - -/*ARGSUSED*/ -symbolS * -md_undefined_symbol (name) - char *name ATTRIBUTE_UNUSED; -{ - return 0; -} - -/* Functions concerning relocs. */ - -/* The location from which a PC relative jump should be calculated, - given a PC relative reloc. */ - -long -md_pcrel_from_section (fixp, sec) - fixS *fixp; - segT sec ATTRIBUTE_UNUSED; -{ - return fixp->fx_frag->fr_address + fixp->fx_where; -} - -#ifdef OBJ_XCOFF - -/* This is called to see whether a fixup should be adjusted to use a - section symbol. We take the opportunity to change a fixup against - a symbol in the TOC subsegment into a reloc against the - corresponding .tc symbol. */ - -int -ppc_fix_adjustable (fix) - fixS *fix; -{ - valueT val; - - resolve_symbol_value (fix->fx_addsy, 1); - val = S_GET_VALUE (fix->fx_addsy); - if (ppc_toc_csect != (symbolS *) NULL - && fix->fx_addsy != (symbolS *) NULL - && fix->fx_addsy != ppc_toc_csect - && S_GET_SEGMENT (fix->fx_addsy) == data_section - && val >= ppc_toc_frag->fr_address - && (ppc_after_toc_frag == (fragS *) NULL - || val < ppc_after_toc_frag->fr_address)) - { - symbolS *sy; - - for (sy = symbol_next (ppc_toc_csect); - sy != (symbolS *) NULL; - sy = symbol_next (sy)) - { - if (symbol_get_tc (sy)->class == XMC_TC0) - continue; - if (symbol_get_tc (sy)->class != XMC_TC) - break; - resolve_symbol_value (sy, 1); - if (val == S_GET_VALUE (sy)) - { - fix->fx_addsy = sy; - fix->fx_addnumber = val - ppc_toc_frag->fr_address; - return 0; - } - } - - as_bad_where (fix->fx_file, fix->fx_line, - _("symbol in .toc does not match any .tc")); - } - - /* Possibly adjust the reloc to be against the csect. */ - if (fix->fx_addsy != (symbolS *) NULL - && symbol_get_tc (fix->fx_addsy)->subseg == 0 - && symbol_get_tc (fix->fx_addsy)->class != XMC_TC0 - && symbol_get_tc (fix->fx_addsy)->class != XMC_TC - && S_GET_SEGMENT (fix->fx_addsy) != bss_section - /* Don't adjust if this is a reloc in the toc section. */ - && (S_GET_SEGMENT (fix->fx_addsy) != data_section - || ppc_toc_csect == NULL - || val < ppc_toc_frag->fr_address - || (ppc_after_toc_frag != NULL - && val >= ppc_after_toc_frag->fr_address))) - { - symbolS *csect; - - if (S_GET_SEGMENT (fix->fx_addsy) == text_section) - csect = ppc_text_csects; - else if (S_GET_SEGMENT (fix->fx_addsy) == data_section) - csect = ppc_data_csects; - else - abort (); - - /* Skip the initial dummy symbol. */ - csect = symbol_get_tc (csect)->next; - - if (csect != (symbolS *) NULL) - { - while (symbol_get_tc (csect)->next != (symbolS *) NULL - && (symbol_get_frag (symbol_get_tc (csect)->next)->fr_address - <= val)) - { - /* If the csect address equals the symbol value, then we - have to look through the full symbol table to see - whether this is the csect we want. Note that we will - only get here if the csect has zero length. */ - if ((symbol_get_frag (csect)->fr_address == val) - && S_GET_VALUE (csect) == S_GET_VALUE (fix->fx_addsy)) - { - symbolS *scan; - - for (scan = symbol_next (csect); - scan != NULL; - scan = symbol_next (scan)) - { - if (symbol_get_tc (scan)->subseg != 0) - break; - if (scan == fix->fx_addsy) - break; - } - - /* If we found the symbol before the next csect - symbol, then this is the csect we want. */ - if (scan == fix->fx_addsy) - break; - } - - csect = symbol_get_tc (csect)->next; - } - - fix->fx_offset += (S_GET_VALUE (fix->fx_addsy) - - symbol_get_frag (csect)->fr_address); - fix->fx_addsy = csect; - } - } - - /* Adjust a reloc against a .lcomm symbol to be against the base - .lcomm. */ - if (fix->fx_addsy != (symbolS *) NULL - && S_GET_SEGMENT (fix->fx_addsy) == bss_section - && ! S_IS_EXTERNAL (fix->fx_addsy)) - { - resolve_symbol_value (symbol_get_frag (fix->fx_addsy)->fr_symbol, 1); - fix->fx_offset += - (S_GET_VALUE (fix->fx_addsy) - - S_GET_VALUE (symbol_get_frag (fix->fx_addsy)->fr_symbol)); - fix->fx_addsy = symbol_get_frag (fix->fx_addsy)->fr_symbol; - } - - return 0; -} - -/* A reloc from one csect to another must be kept. The assembler - will, of course, keep relocs between sections, and it will keep - absolute relocs, but we need to force it to keep PC relative relocs - between two csects in the same section. */ - -int -ppc_force_relocation (fix) - fixS *fix; -{ - /* At this point fix->fx_addsy should already have been converted to - a csect symbol. If the csect does not include the fragment, then - we need to force the relocation. */ - if (fix->fx_pcrel - && fix->fx_addsy != NULL - && symbol_get_tc (fix->fx_addsy)->subseg != 0 - && ((symbol_get_frag (fix->fx_addsy)->fr_address - > fix->fx_frag->fr_address) - || (symbol_get_tc (fix->fx_addsy)->next != NULL - && (symbol_get_frag (symbol_get_tc (fix->fx_addsy)->next)->fr_address - <= fix->fx_frag->fr_address)))) - return 1; - - return 0; -} - -#endif /* OBJ_XCOFF */ - -/* See whether a symbol is in the TOC section. */ - -static int -ppc_is_toc_sym (sym) - symbolS *sym; -{ -#ifdef OBJ_XCOFF - return symbol_get_tc (sym)->class == XMC_TC; -#else - return strcmp (segment_name (S_GET_SEGMENT (sym)), ".got") == 0; -#endif -} - -/* Apply a fixup to the object code. This is called for all the - fixups we generated by the call to fix_new_exp, above. In the call - above we used a reloc code which was the largest legal reloc code - plus the operand index. Here we undo that to recover the operand - index. At this point all symbol values should be fully resolved, - and we attempt to completely resolve the reloc. If we can not do - that, we determine the correct reloc code and put it back in the - fixup. */ - -int -md_apply_fix3 (fixp, valuep, seg) - fixS *fixp; - valueT *valuep; - segT seg; -{ - valueT value; - -#ifdef OBJ_ELF - value = *valuep; - if (fixp->fx_addsy != NULL) - { - /* `*valuep' may contain the value of the symbol on which the reloc - will be based; we have to remove it. */ - if (symbol_used_in_reloc_p (fixp->fx_addsy) - && S_GET_SEGMENT (fixp->fx_addsy) != absolute_section - && S_GET_SEGMENT (fixp->fx_addsy) != undefined_section - && ! bfd_is_com_section (S_GET_SEGMENT (fixp->fx_addsy))) - value -= S_GET_VALUE (fixp->fx_addsy); - - /* FIXME: Why '+'? Better yet, what exactly is '*valuep' - supposed to be? I think this is related to various similar - FIXMEs in tc-i386.c and tc-sparc.c. */ - if (fixp->fx_pcrel) - value += fixp->fx_frag->fr_address + fixp->fx_where; - } - else - { - fixp->fx_done = 1; - } -#else - /* FIXME FIXME FIXME: The value we are passed in *valuep includes - the symbol values. Since we are using BFD_ASSEMBLER, if we are - doing this relocation the code in write.c is going to call - bfd_install_relocation, which is also going to use the symbol - value. That means that if the reloc is fully resolved we want to - use *valuep since bfd_install_relocation is not being used. - However, if the reloc is not fully resolved we do not want to use - *valuep, and must use fx_offset instead. However, if the reloc - is PC relative, we do want to use *valuep since it includes the - result of md_pcrel_from. This is confusing. */ - if (fixp->fx_addsy == (symbolS *) NULL) - { - value = *valuep; - fixp->fx_done = 1; - } - else if (fixp->fx_pcrel) - value = *valuep; - else - { - value = fixp->fx_offset; - if (fixp->fx_subsy != (symbolS *) NULL) - { - if (S_GET_SEGMENT (fixp->fx_subsy) == absolute_section) - value -= S_GET_VALUE (fixp->fx_subsy); - else - { - /* We can't actually support subtracting a symbol. */ - as_bad_where (fixp->fx_file, fixp->fx_line, - _("expression too complex")); - } - } - } -#endif - - if ((int) fixp->fx_r_type >= (int) BFD_RELOC_UNUSED) - { - int opindex; - const struct powerpc_operand *operand; - char *where; - unsigned long insn; - - opindex = (int) fixp->fx_r_type - (int) BFD_RELOC_UNUSED; - - operand = &powerpc_operands[opindex]; - -#ifdef OBJ_XCOFF - /* It appears that an instruction like - l 9,LC..1(30) - when LC..1 is not a TOC symbol does not generate a reloc. It - uses the offset of LC..1 within its csect. However, .long - LC..1 will generate a reloc. I can't find any documentation - on how these cases are to be distinguished, so this is a wild - guess. These cases are generated by gcc -mminimal-toc. */ - if ((operand->flags & PPC_OPERAND_PARENS) != 0 - && operand->bits == 16 - && operand->shift == 0 - && operand->insert == NULL - && fixp->fx_addsy != NULL - && symbol_get_tc (fixp->fx_addsy)->subseg != 0 - && symbol_get_tc (fixp->fx_addsy)->class != XMC_TC - && symbol_get_tc (fixp->fx_addsy)->class != XMC_TC0 - && S_GET_SEGMENT (fixp->fx_addsy) != bss_section) - { - value = fixp->fx_offset; - fixp->fx_done = 1; - } -#endif - - /* Fetch the instruction, insert the fully resolved operand - value, and stuff the instruction back again. */ - where = fixp->fx_frag->fr_literal + fixp->fx_where; - if (target_big_endian) - insn = bfd_getb32 ((unsigned char *) where); - else - insn = bfd_getl32 ((unsigned char *) where); - insn = ppc_insert_operand (insn, operand, (offsetT) value, - fixp->fx_file, fixp->fx_line); - if (target_big_endian) - bfd_putb32 ((bfd_vma) insn, (unsigned char *) where); - else - bfd_putl32 ((bfd_vma) insn, (unsigned char *) where); - - if (fixp->fx_done) - { - /* Nothing else to do here. */ - return 1; - } - - /* Determine a BFD reloc value based on the operand information. - We are only prepared to turn a few of the operands into - relocs. - FIXME: We need to handle the DS field at the very least. - FIXME: Selecting the reloc type is a bit haphazard; perhaps - there should be a new field in the operand table. */ - if ((operand->flags & PPC_OPERAND_RELATIVE) != 0 - && operand->bits == 26 - && operand->shift == 0) - fixp->fx_r_type = BFD_RELOC_PPC_B26; - else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0 - && operand->bits == 16 - && operand->shift == 0) - fixp->fx_r_type = BFD_RELOC_PPC_B16; - else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0 - && operand->bits == 26 - && operand->shift == 0) - fixp->fx_r_type = BFD_RELOC_PPC_BA26; - else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0 - && operand->bits == 16 - && operand->shift == 0) - fixp->fx_r_type = BFD_RELOC_PPC_BA16; - else if ((operand->flags & PPC_OPERAND_PARENS) != 0 - && operand->bits == 16 - && operand->shift == 0 - && operand->insert == NULL - && fixp->fx_addsy != NULL - && ppc_is_toc_sym (fixp->fx_addsy)) - { - fixp->fx_size = 2; - if (target_big_endian) - fixp->fx_where += 2; - fixp->fx_r_type = BFD_RELOC_PPC_TOC16; - } - else - { - char *sfile; - unsigned int sline; - - /* Use expr_symbol_where to see if this is an expression - symbol. */ - if (expr_symbol_where (fixp->fx_addsy, &sfile, &sline)) - as_bad_where (fixp->fx_file, fixp->fx_line, - _("unresolved expression that must be resolved")); - else - as_bad_where (fixp->fx_file, fixp->fx_line, - _("unsupported relocation type")); - fixp->fx_done = 1; - return 1; - } - } - else - { -#ifdef OBJ_ELF - ppc_elf_validate_fix (fixp, seg); -#endif - switch (fixp->fx_r_type) - { - case BFD_RELOC_32: - case BFD_RELOC_CTOR: - if (fixp->fx_pcrel) - fixp->fx_r_type = BFD_RELOC_32_PCREL; - /* fall through */ - - case BFD_RELOC_RVA: - case BFD_RELOC_32_PCREL: - case BFD_RELOC_32_BASEREL: - case BFD_RELOC_PPC_EMB_NADDR32: - md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where, - value, 4); - break; - - case BFD_RELOC_LO16: - case BFD_RELOC_16: - case BFD_RELOC_GPREL16: - case BFD_RELOC_16_GOT_PCREL: - case BFD_RELOC_16_GOTOFF: - case BFD_RELOC_LO16_GOTOFF: - case BFD_RELOC_HI16_GOTOFF: - case BFD_RELOC_HI16_S_GOTOFF: - case BFD_RELOC_LO16_BASEREL: - case BFD_RELOC_HI16_BASEREL: - case BFD_RELOC_HI16_S_BASEREL: - case BFD_RELOC_PPC_EMB_NADDR16: - case BFD_RELOC_PPC_EMB_NADDR16_LO: - case BFD_RELOC_PPC_EMB_NADDR16_HI: - case BFD_RELOC_PPC_EMB_NADDR16_HA: - case BFD_RELOC_PPC_EMB_SDAI16: - case BFD_RELOC_PPC_EMB_SDA2REL: - case BFD_RELOC_PPC_EMB_SDA2I16: - case BFD_RELOC_PPC_EMB_RELSEC16: - case BFD_RELOC_PPC_EMB_RELST_LO: - case BFD_RELOC_PPC_EMB_RELST_HI: - case BFD_RELOC_PPC_EMB_RELST_HA: - case BFD_RELOC_PPC_EMB_RELSDA: - case BFD_RELOC_PPC_TOC16: - if (fixp->fx_pcrel) - { - if (fixp->fx_addsy != NULL) - as_bad_where (fixp->fx_file, fixp->fx_line, - _("cannot emit PC relative %s relocation against %s"), - bfd_get_reloc_code_name (fixp->fx_r_type), - S_GET_NAME (fixp->fx_addsy)); - else - as_bad_where (fixp->fx_file, fixp->fx_line, - _("cannot emit PC relative %s relocation"), - bfd_get_reloc_code_name (fixp->fx_r_type)); - } - - md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where, - value, 2); - break; - - /* This case happens when you write, for example, - lis %r3,(L1-L2)@ha - where L1 and L2 are defined later. */ - case BFD_RELOC_HI16: - if (fixp->fx_pcrel) - abort (); - md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where, - value >> 16, 2); - break; - case BFD_RELOC_HI16_S: - if (fixp->fx_pcrel) - abort (); - md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where, - (value + 0x8000) >> 16, 2); - break; - - /* Because SDA21 modifies the register field, the size is set to 4 - bytes, rather than 2, so offset it here appropriately */ - case BFD_RELOC_PPC_EMB_SDA21: - if (fixp->fx_pcrel) - abort (); - - md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where - + ((target_big_endian) ? 2 : 0), - value, 2); - break; - - case BFD_RELOC_8: - if (fixp->fx_pcrel) - abort (); - - md_number_to_chars (fixp->fx_frag->fr_literal + fixp->fx_where, - value, 1); - break; - - case BFD_RELOC_24_PLT_PCREL: - case BFD_RELOC_PPC_LOCAL24PC: - if (!fixp->fx_pcrel && !fixp->fx_done) - abort (); - - if (fixp->fx_done) - { - char *where; - unsigned long insn; - - /* Fetch the instruction, insert the fully resolved operand - value, and stuff the instruction back again. */ - where = fixp->fx_frag->fr_literal + fixp->fx_where; - if (target_big_endian) - insn = bfd_getb32 ((unsigned char *) where); - else - insn = bfd_getl32 ((unsigned char *) where); - if ((value & 3) != 0) - as_bad_where (fixp->fx_file, fixp->fx_line, - _("must branch to an address a multiple of 4")); - if ((offsetT) value < -0x40000000 - || (offsetT) value >= 0x40000000) - as_bad_where (fixp->fx_file, fixp->fx_line, - _("@local or @plt branch destination is too far away, %ld bytes"), - value); - insn = insn | (value & 0x03fffffc); - if (target_big_endian) - bfd_putb32 ((bfd_vma) insn, (unsigned char *) where); - else - bfd_putl32 ((bfd_vma) insn, (unsigned char *) where); - } - break; - - case BFD_RELOC_VTABLE_INHERIT: - fixp->fx_done = 0; - if (fixp->fx_addsy - && !S_IS_DEFINED (fixp->fx_addsy) - && !S_IS_WEAK (fixp->fx_addsy)) - S_SET_WEAK (fixp->fx_addsy); - break; - - case BFD_RELOC_VTABLE_ENTRY: - fixp->fx_done = 0; - break; - - default: - fprintf(stderr, - _("Gas failure, reloc value %d\n"), fixp->fx_r_type); - fflush(stderr); - abort (); - } - } - -#ifdef OBJ_ELF - fixp->fx_addnumber = value; -#else - if (fixp->fx_r_type != BFD_RELOC_PPC_TOC16) - fixp->fx_addnumber = 0; - else - { -#ifdef TE_PE - fixp->fx_addnumber = 0; -#else - /* We want to use the offset within the data segment of the - symbol, not the actual VMA of the symbol. */ - fixp->fx_addnumber = - - bfd_get_section_vma (stdoutput, S_GET_SEGMENT (fixp->fx_addsy)); -#endif - } -#endif - - return 1; -} - -/* Generate a reloc for a fixup. */ - -arelent * -tc_gen_reloc (seg, fixp) - asection *seg ATTRIBUTE_UNUSED; - fixS *fixp; -{ - arelent *reloc; - - reloc = (arelent *) xmalloc (sizeof (arelent)); - - reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); - *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); - reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; - reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); - if (reloc->howto == (reloc_howto_type *) NULL) - { - as_bad_where (fixp->fx_file, fixp->fx_line, - _("reloc %d not supported by object file format"), (int)fixp->fx_r_type); - return NULL; - } - reloc->addend = fixp->fx_addnumber; - - return reloc; -} diff --git a/contrib/binutils/gas/config/tc-ppc.h b/contrib/binutils/gas/config/tc-ppc.h deleted file mode 100644 index 783a215d9ecf6..0000000000000 --- a/contrib/binutils/gas/config/tc-ppc.h +++ /dev/null @@ -1,289 +0,0 @@ -/* tc-ppc.h -- Header file for tc-ppc.c. - Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000 - Free Software Foundation, Inc. - Written by Ian Lance Taylor, Cygnus Support. - - 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. */ - -#define TC_PPC - -#ifdef ANSI_PROTOTYPES -struct fix; -#endif - -/* Set the endianness we are using. Default to big endian. */ -#ifndef TARGET_BYTES_BIG_ENDIAN -#define TARGET_BYTES_BIG_ENDIAN 1 -#endif - -#ifndef BFD_ASSEMBLER - #error PowerPC support requires BFD_ASSEMBLER -#endif - -/* If OBJ_COFF is defined, and TE_PE is not defined, we are assembling - XCOFF for AIX or PowerMac. If TE_PE is defined, we are assembling - COFF for Windows NT. */ - -#ifdef OBJ_COFF -#ifndef TE_PE -#define OBJ_XCOFF -#endif -#endif - -/* The target BFD architecture. */ -#define TARGET_ARCH (ppc_arch ()) -extern enum bfd_architecture ppc_arch PARAMS ((void)); - -/* Whether or not the target is big endian */ -extern int target_big_endian; - -/* The target BFD format. */ -#ifdef OBJ_COFF -#ifdef TE_PE -#define TARGET_FORMAT (target_big_endian ? "pe-powerpc" : "pe-powerpcle") -#else -#define TARGET_FORMAT "aixcoff-rs6000" -#endif -#endif - -/* PowerMac has a BFD slightly different from AIX's. */ -#ifdef TE_POWERMAC -#ifdef TARGET_FORMAT -#undef TARGET_FORMAT -#endif -#define TARGET_FORMAT "xcoff-powermac" -#endif - -#ifdef OBJ_ELF -#define TARGET_FORMAT (target_big_endian ? "elf32-powerpc" : "elf32-powerpcle") -#endif - -/* Permit temporary numeric labels. */ -#define LOCAL_LABELS_FB 1 - -/* $ is used to refer to the current location. */ -#define DOLLAR_DOT - -/* Strings do not use backslash escapes under COFF. */ -#ifdef OBJ_COFF -#define NO_STRING_ESCAPES -#endif - -#ifdef OBJ_ELF -#define DIFF_EXPR_OK /* foo-. gets turned into PC relative relocs */ -#endif - -#if TARGET_BYTES_BIG_ENDIAN -#define PPC_BIG_ENDIAN 1 -#else -#define PPC_BIG_ENDIAN 0 -#endif - -/* We don't need to handle .word strangely. */ -#define WORKING_DOT_WORD - -/* We set the fx_done field appropriately in md_apply_fix. */ -#define TC_HANDLES_FX_DONE - -#ifdef TE_PE - -/* Question marks are permitted in symbol names. */ -#define LEX_QM 1 - -/* Don't adjust TOC relocs. */ -#define tc_fix_adjustable(fixp) ppc_pe_fix_adjustable (fixp) -extern int ppc_pe_fix_adjustable PARAMS ((struct fix *)); - -#endif - -#ifdef OBJ_XCOFF - -/* Declarations needed when generating XCOFF code. XCOFF is an - extension of COFF, used only on the RS/6000. Rather than create an - obj-xcoff, we just use obj-coff, and handle the extensions here in - tc-ppc. */ - -/* We need to keep some information for symbols. */ -struct ppc_tc_sy -{ - /* We keep a few linked lists of symbols. */ - symbolS *next; - /* Non-zero if the symbol should be output. The RS/6000 assembler - only outputs symbols that are external or are mentioned in a - .globl or .lglobl statement. */ - int output; - /* The symbol class. */ - int class; - /* The real name, if the symbol was renamed. */ - char *real_name; - /* For a csect symbol, the subsegment we are using. This is zero - for symbols that are not csects. */ - subsegT subseg; - /* For a csect or common symbol, the alignment to use. */ - int align; - /* For a function symbol, a symbol whose value is the size. The - field is NULL if there is no size. */ - symbolS *size; - /* For a csect symbol, the last symbol which has been defined in - this csect, or NULL if none have been defined so far. For a .bs - symbol, the referenced csect symbol. */ - symbolS *within; -}; - -#define TC_SYMFIELD_TYPE struct ppc_tc_sy - -/* We need an additional auxent for function symbols. */ -#define OBJ_COFF_MAX_AUXENTRIES 2 - -/* Square and curly brackets are permitted in symbol names. */ -#define LEX_BR 3 - -/* Canonicalize the symbol name. */ -#define tc_canonicalize_symbol_name(name) ppc_canonicalize_symbol_name (name) -extern char *ppc_canonicalize_symbol_name PARAMS ((char *)); - -/* Get the symbol class from the name. */ -#define tc_symbol_new_hook(sym) ppc_symbol_new_hook (sym) -extern void ppc_symbol_new_hook PARAMS ((symbolS *)); - -/* Set the symbol class of a label based on the csect. */ -#define tc_frob_label(sym) ppc_frob_label (sym) -extern void ppc_frob_label PARAMS ((symbolS *)); - -/* TOC relocs requires special handling. */ -#define tc_fix_adjustable(fixp) ppc_fix_adjustable (fixp) -extern int ppc_fix_adjustable PARAMS ((struct fix *)); - -/* A relocation from one csect to another must be kept. */ -#define TC_FORCE_RELOCATION(FIXP) ppc_force_relocation (FIXP) -extern int ppc_force_relocation PARAMS ((struct fix *)); - -/* We need to set the section VMA. */ -#define tc_frob_section(sec) ppc_frob_section (sec) -extern void ppc_frob_section PARAMS ((asection *)); - -/* Finish up the symbol. */ -#define tc_frob_symbol(sym, punt) punt = ppc_frob_symbol (sym) -extern int ppc_frob_symbol PARAMS ((symbolS *)); - -/* Finish up the entire symtab. */ -#define tc_adjust_symtab() ppc_adjust_symtab () -extern void ppc_adjust_symtab PARAMS ((void)); - -/* Niclas Andersson <nican@ida.liu.se> says this is needed. */ -#define SUB_SEGMENT_ALIGN(SEG) 2 - -/* We also need to copy, in particular, the class of the symbol, - over what obj-coff would otherwise have copied. */ -#define OBJ_COPY_SYMBOL_ATTRIBUTES(dest,src) \ -do { \ - if (SF_GET_GET_SEGMENT (dest)) \ - S_SET_SEGMENT (dest, S_GET_SEGMENT (src)); \ - symbol_get_tc (dest)->size = symbol_get_tc (src)->size; \ - symbol_get_tc (dest)->align = symbol_get_tc (src)->align; \ - symbol_get_tc (dest)->class = symbol_get_tc (src)->class; \ - symbol_get_tc (dest)->within = symbol_get_tc (src)->within; \ -} while (0) - - -#endif /* OBJ_XCOFF */ - -#ifdef OBJ_ELF - -/* Branch prediction relocations must force relocation, as must - the vtable description relocs. */ -#define TC_FORCE_RELOCATION(FIXP) \ -((FIXP)->fx_r_type == BFD_RELOC_PPC_B16_BRTAKEN \ - || (FIXP)->fx_r_type == BFD_RELOC_PPC_B16_BRNTAKEN \ - || (FIXP)->fx_r_type == BFD_RELOC_PPC_BA16_BRTAKEN \ - || (FIXP)->fx_r_type == BFD_RELOC_PPC_BA16_BRNTAKEN \ - || (FIXP)->fx_r_type == BFD_RELOC_VTABLE_INHERIT \ - || (FIXP)->fx_r_type == BFD_RELOC_VTABLE_ENTRY) - -#define TC_FORCE_RELOCATION_SECTION(FIXP,SEC) \ -(TC_FORCE_RELOCATION (FIXP) \ - || ((FIXP)->fx_addsy && !(FIXP)->fx_subsy \ - && S_GET_SEGMENT ((FIXP)->fx_addsy) != SEC)) - -/* Support for SHF_EXCLUDE and SHT_ORDERED */ -extern int ppc_section_letter PARAMS ((int, char **)); -extern int ppc_section_type PARAMS ((char *, size_t)); -extern int ppc_section_word PARAMS ((char *, size_t)); -extern int ppc_section_flags PARAMS ((int, int, int)); - -#define md_elf_section_letter(LETTER, PTR_MSG) ppc_section_letter (LETTER, PTR_MSG) -#define md_elf_section_type(STR, LEN) ppc_section_type (STR, LEN) -#define md_elf_section_word(STR, LEN) ppc_section_word (STR, LEN) -#define md_elf_section_flags(FLAGS, ATTR, TYPE) ppc_section_flags (FLAGS, ATTR, TYPE) - -/* Add extra PPC sections -- Note, for now, make .sbss2 and .PPC.EMB.sbss0 a - normal section, and not a bss section so that the linker doesn't crater - when trying to make more than 2 sections. */ -#define ELF_TC_SPECIAL_SECTIONS \ - { ".tags", SHT_ORDERED, SHF_ALLOC }, \ - { ".sdata", SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, \ - { ".sbss", SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, \ - { ".sdata2", SHT_PROGBITS, SHF_ALLOC }, \ - { ".sbss2", SHT_PROGBITS, SHF_ALLOC }, \ - { ".PPC.EMB.sdata0", SHT_PROGBITS, SHF_ALLOC }, \ - { ".PPC.EMB.sbss0", SHT_PROGBITS, SHF_ALLOC }, - -#define tc_comment_chars ppc_comment_chars -extern const char *ppc_comment_chars; - -/* Keep relocations relative to the GOT, or non-PC relative. */ -#define tc_fix_adjustable(FIX) \ - ((FIX)->fx_r_type != BFD_RELOC_16_GOTOFF \ - && (FIX)->fx_r_type != BFD_RELOC_LO16_GOTOFF \ - && (FIX)->fx_r_type != BFD_RELOC_HI16_GOTOFF \ - && (FIX)->fx_r_type != BFD_RELOC_HI16_S_GOTOFF \ - && (FIX)->fx_r_type != BFD_RELOC_GPREL16 \ - && (FIX)->fx_r_type != BFD_RELOC_VTABLE_INHERIT \ - && (FIX)->fx_r_type != BFD_RELOC_VTABLE_ENTRY \ - && ! S_IS_EXTERNAL ((FIX)->fx_addsy) \ - && ! S_IS_WEAK ((FIX)->fx_addsy) \ - && ((FIX)->fx_pcrel \ - || ((FIX)->fx_subsy != NULL \ - && (S_GET_SEGMENT ((FIX)->fx_subsy) \ - == S_GET_SEGMENT ((FIX)->fx_addsy))) \ - || S_IS_LOCAL ((FIX)->fx_addsy))) - -/* We must never ever try to resolve references to externally visible - symbols in the assembler, because the .o file might go into a shared - library, and some other shared library might override that symbol. */ -#define TC_RELOC_RTSYM_LOC_FIXUP(FIX) \ - ((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 /* OBJ_ELF */ - -/* call md_apply_fix3 with segment instead of md_apply_fix */ -#define MD_APPLY_FIX3 - -/* call md_pcrel_from_section, not md_pcrel_from */ -#define MD_PCREL_FROM_SECTION(FIXP, SEC) md_pcrel_from_section(FIXP, SEC) -extern long md_pcrel_from_section PARAMS ((struct fix *, segT)); - -#define md_parse_name(name, exp) ppc_parse_name (name, exp) -extern int ppc_parse_name PARAMS ((const char *, struct expressionS *)); - -#define md_operand(x) - diff --git a/contrib/binutils/gas/config/tc-sh.c b/contrib/binutils/gas/config/tc-sh.c deleted file mode 100644 index eaa6146eea751..0000000000000 --- a/contrib/binutils/gas/config/tc-sh.c +++ /dev/null @@ -1,2335 +0,0 @@ -/* tc-sh.c -- Assemble code for the Hitachi Super-H - Copyright (C) 1993, 94, 95, 96, 1997 Free Software Foundation. - - 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. */ - -/* - Written By Steve Chamberlain - sac@cygnus.com - */ - -#include <stdio.h> -#include "as.h" -#include "bfd.h" -#include "subsegs.h" -#define DEFINE_TABLE -#include "opcodes/sh-opc.h" -#include <ctype.h> -const char comment_chars[] = "!"; -const char line_separator_chars[] = ";"; -const char line_comment_chars[] = "!#"; - -static void s_uses PARAMS ((int)); - -static void sh_count_relocs PARAMS ((bfd *, segT, PTR)); -static void sh_frob_section PARAMS ((bfd *, segT, PTR)); - -/* This table describes all the machine specific pseudo-ops the assembler - has to support. The fields are: - pseudo-op name without dot - function to call to execute this pseudo-op - Integer arg to pass to the function - */ - -void cons (); -void s_align_bytes (); -static void s_uacons PARAMS ((int)); - -int shl = 0; - -static void -little (ignore) - int ignore; -{ - shl = 1; - target_big_endian = 0; -} - -const pseudo_typeS md_pseudo_table[] = -{ - {"int", cons, 4}, - {"word", cons, 2}, - {"form", listing_psize, 0}, - {"little", little, 0}, - {"heading", listing_title, 0}, - {"import", s_ignore, 0}, - {"page", listing_eject, 0}, - {"program", s_ignore, 0}, - {"uses", s_uses, 0}, - {"uaword", s_uacons, 2}, - {"ualong", s_uacons, 4}, - {0, 0, 0} -}; - -/*int md_reloc_size; */ - -int sh_relax; /* set if -relax seen */ - -/* Whether -small was seen. */ - -int sh_small; - -const char EXP_CHARS[] = "eE"; - -/* Chars that mean this number is a floating point constant */ -/* As in 0f12.456 */ -/* or 0d1.2345e12 */ -const char FLT_CHARS[] = "rRsSfFdDxXpP"; - -#define C(a,b) ENCODE_RELAX(a,b) - -#define JREG 14 /* Register used as a temp when relaxing */ -#define ENCODE_RELAX(what,length) (((what) << 4) + (length)) -#define GET_WHAT(x) ((x>>4)) - -/* These are the two types of relaxable instrction */ -#define COND_JUMP 1 -#define UNCOND_JUMP 2 - -#define UNDEF_DISP 0 -#define COND8 1 -#define COND12 2 -#define COND32 3 -#define UNCOND12 1 -#define UNCOND32 2 -#define UNDEF_WORD_DISP 4 -#define END 5 - -#define UNCOND12 1 -#define UNCOND32 2 - -/* Branch displacements are from the address of the branch plus - four, thus all minimum and maximum values have 4 added to them. */ -#define COND8_F 258 -#define COND8_M -252 -#define COND8_LENGTH 2 - -/* There is one extra instruction before the branch, so we must add - two more bytes to account for it. */ -#define COND12_F 4100 -#define COND12_M -4090 -#define COND12_LENGTH 6 - -/* ??? The minimum and maximum values are wrong, but this does not matter - since this relocation type is not supported yet. */ -#define COND32_F (1<<30) -#define COND32_M -(1<<30) -#define COND32_LENGTH 14 - -#define UNCOND12_F 4098 -#define UNCOND12_M -4092 -#define UNCOND12_LENGTH 2 - -/* ??? The minimum and maximum values are wrong, but this does not matter - since this relocation type is not supported yet. */ -#define UNCOND32_F (1<<30) -#define UNCOND32_M -(1<<30) -#define UNCOND32_LENGTH 14 - -const relax_typeS md_relax_table[C (END, 0)] = { - { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, - { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, - - { 0 }, - /* C (COND_JUMP, COND8) */ - { COND8_F, COND8_M, COND8_LENGTH, C (COND_JUMP, COND12) }, - /* C (COND_JUMP, COND12) */ - { COND12_F, COND12_M, COND12_LENGTH, C (COND_JUMP, COND32), }, - /* C (COND_JUMP, COND32) */ - { COND32_F, COND32_M, COND32_LENGTH, 0, }, - { 0 }, { 0 }, { 0 }, { 0 }, - { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, - - { 0 }, - /* C (UNCOND_JUMP, UNCOND12) */ - { UNCOND12_F, UNCOND12_M, UNCOND12_LENGTH, C (UNCOND_JUMP, UNCOND32), }, - /* C (UNCOND_JUMP, UNCOND32) */ - { UNCOND32_F, UNCOND32_M, UNCOND32_LENGTH, 0, }, - { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, - { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, -}; - -static struct hash_control *opcode_hash_control; /* Opcode mnemonics */ - -/* - This function is called once, at assembler startup time. This should - set up all the tables, etc that the MD part of the assembler needs - */ - -void -md_begin () -{ - sh_opcode_info *opcode; - char *prev_name = ""; - - if (! shl) - target_big_endian = 1; - - opcode_hash_control = hash_new (); - - /* Insert unique names into hash table */ - for (opcode = sh_table; opcode->name; opcode++) - { - if (strcmp (prev_name, opcode->name)) - { - prev_name = opcode->name; - hash_insert (opcode_hash_control, opcode->name, (char *) opcode); - } - else - { - /* Make all the opcodes with the same name point to the same - string */ - opcode->name = prev_name; - } - } -} - -static int reg_m; -static int reg_n; -static int reg_b; - -static expressionS immediate; /* absolute expression */ - -typedef struct - { - sh_arg_type type; - int reg; - } - -sh_operand_info; - -/* try and parse a reg name, returns number of chars consumed */ -static int -parse_reg (src, mode, reg) - char *src; - int *mode; - int *reg; -{ - /* We use !isalnum for the next character after the register name, to - make sure that we won't accidentally recognize a symbol name such as - 'sram' as being a reference to the register 'sr'. */ - - if (src[0] == 'r') - { - if (src[1] >= '0' && src[1] <= '7' && strncmp(&src[2], "_bank", 5) == 0 - && ! isalnum (src[7])) - { - *mode = A_REG_B; - *reg = (src[1] - '0'); - return 7; - } - } - - if (src[0] == 'r') - { - if (src[1] == '1') - { - if (src[2] >= '0' && src[2] <= '5' && ! isalnum (src[3])) - { - *mode = A_REG_N; - *reg = 10 + src[2] - '0'; - return 3; - } - } - if (src[1] >= '0' && src[1] <= '9' && ! isalnum (src[2])) - { - *mode = A_REG_N; - *reg = (src[1] - '0'); - return 2; - } - } - - if (src[0] == 's' && src[1] == 's' && src[2] == 'r' && ! isalnum (src[3])) - { - *mode = A_SSR; - return 3; - } - - if (src[0] == 's' && src[1] == 'p' && src[2] == 'c' && ! isalnum (src[3])) - { - *mode = A_SPC; - return 3; - } - - if (src[0] == 's' && src[1] == 'g' && src[2] == 'r' && ! isalnum (src[3])) - { - *mode = A_SGR; - return 3; - } - - if (src[0] == 'd' && src[1] == 'b' && src[2] == 'r' && ! isalnum (src[3])) - { - *mode = A_DBR; - return 3; - } - - if (src[0] == 's' && src[1] == 'r' && ! isalnum (src[2])) - { - *mode = A_SR; - return 2; - } - - if (src[0] == 's' && src[1] == 'p' && ! isalnum (src[2])) - { - *mode = A_REG_N; - *reg = 15; - return 2; - } - - if (src[0] == 'p' && src[1] == 'r' && ! isalnum (src[2])) - { - *mode = A_PR; - return 2; - } - if (src[0] == 'p' && src[1] == 'c' && ! isalnum (src[2])) - { - *mode = A_DISP_PC; - return 2; - } - if (src[0] == 'g' && src[1] == 'b' && src[2] == 'r' && ! isalnum (src[3])) - { - *mode = A_GBR; - return 3; - } - if (src[0] == 'v' && src[1] == 'b' && src[2] == 'r' && ! isalnum (src[3])) - { - *mode = A_VBR; - return 3; - } - - if (src[0] == 'm' && src[1] == 'a' && src[2] == 'c' && ! isalnum (src[4])) - { - if (src[3] == 'l') - { - *mode = A_MACL; - return 4; - } - if (src[3] == 'h') - { - *mode = A_MACH; - return 4; - } - } - if (src[0] == 'f' && src[1] == 'r') - { - if (src[2] == '1') - { - if (src[3] >= '0' && src[3] <= '5' && ! isalnum (src[4])) - { - *mode = F_REG_N; - *reg = 10 + src[3] - '0'; - return 4; - } - } - if (src[2] >= '0' && src[2] <= '9' && ! isalnum (src[3])) - { - *mode = F_REG_N; - *reg = (src[2] - '0'); - return 3; - } - } - if (src[0] == 'd' && src[1] == 'r') - { - if (src[2] == '1') - { - if (src[3] >= '0' && src[3] <= '4' && ! ((src[3] - '0') & 1) - && ! isalnum (src[4])) - { - *mode = D_REG_N; - *reg = 10 + src[3] - '0'; - return 4; - } - } - if (src[2] >= '0' && src[2] <= '8' && ! ((src[2] - '0') & 1) - && ! isalnum (src[3])) - { - *mode = D_REG_N; - *reg = (src[2] - '0'); - return 3; - } - } - if (src[0] == 'x' && src[1] == 'd') - { - if (src[2] == '1') - { - if (src[3] >= '0' && src[3] <= '4' && ! ((src[3] - '0') & 1) - && ! isalnum (src[4])) - { - *mode = X_REG_N; - *reg = 11 + src[3] - '0'; - return 4; - } - } - if (src[2] >= '0' && src[2] <= '8' && ! ((src[2] - '0') & 1) - && ! isalnum (src[3])) - { - *mode = X_REG_N; - *reg = (src[2] - '0') + 1; - return 3; - } - } - if (src[0] == 'f' && src[1] == 'v') - { - if (src[2] == '1'&& src[3] == '2' && ! isalnum (src[4])) - { - *mode = V_REG_N; - *reg = 12; - return 4; - } - if ((src[2] == '0' || src[2] == '4' || src[2] == '8') && ! isalnum (src[3])) - { - *mode = V_REG_N; - *reg = (src[2] - '0'); - return 3; - } - } - if (src[0] == 'f' && src[1] == 'p' && src[2] == 'u' && src[3] == 'l' - && ! isalnum (src[4])) - { - *mode = FPUL_N; - return 4; - } - - if (src[0] == 'f' && src[1] == 'p' && src[2] == 's' && src[3] == 'c' - && src[4] == 'r' && ! isalnum (src[5])) - { - *mode = FPSCR_N; - return 5; - } - - if (src[0] == 'x' && src[1] == 'm' && src[2] == 't' && src[3] == 'r' - && src[4] == 'x' && ! isalnum (src[5])) - { - *mode = XMTRX_M4; - return 5; - } - - return 0; -} - -static symbolS *dot() -{ - const char *fake; - - /* JF: '.' is pseudo symbol with value of current location - in current segment. */ - fake = FAKE_LABEL_NAME; - return symbol_new (fake, - now_seg, - (valueT) frag_now_fix (), - frag_now); - -} - - -static -char * -parse_exp (s) - char *s; -{ - char *save; - char *new; - - save = input_line_pointer; - input_line_pointer = s; - expression (&immediate); - if (immediate.X_op == O_absent) - as_bad ("missing operand"); - new = input_line_pointer; - input_line_pointer = save; - return new; -} - - -/* The many forms of operand: - - Rn Register direct - @Rn Register indirect - @Rn+ Autoincrement - @-Rn Autodecrement - @(disp:4,Rn) - @(disp:8,GBR) - @(disp:8,PC) - - @(R0,Rn) - @(R0,GBR) - - disp:8 - disp:12 - #imm8 - pr, gbr, vbr, macl, mach - - */ - -static -char * -parse_at (src, op) - char *src; - sh_operand_info *op; -{ - int len; - int mode; - src++; - if (src[0] == '-') - { - /* Must be predecrement */ - src++; - - len = parse_reg (src, &mode, &(op->reg)); - if (mode != A_REG_N) - as_bad ("illegal register after @-"); - - op->type = A_DEC_N; - src += len; - } - else if (src[0] == '(') - { - /* Could be @(disp, rn), @(disp, gbr), @(disp, pc), @(r0, gbr) or - @(r0, rn) */ - src++; - len = parse_reg (src, &mode, &(op->reg)); - if (len && mode == A_REG_N) - { - src += len; - if (op->reg != 0) - { - as_bad ("must be @(r0,...)"); - } - if (src[0] == ',') - src++; - /* Now can be rn or gbr */ - len = parse_reg (src, &mode, &(op->reg)); - if (mode == A_GBR) - { - op->type = A_R0_GBR; - } - else if (mode == A_REG_N) - { - op->type = A_IND_R0_REG_N; - } - else - { - as_bad ("syntax error in @(r0,...)"); - } - } - else - { - /* Must be an @(disp,.. thing) */ - src = parse_exp (src); - if (src[0] == ',') - src++; - /* Now can be rn, gbr or pc */ - len = parse_reg (src, &mode, &op->reg); - if (len) - { - if (mode == A_REG_N) - { - op->type = A_DISP_REG_N; - } - else if (mode == A_GBR) - { - op->type = A_DISP_GBR; - } - else if (mode == A_DISP_PC) - { - /* Turn a plain @(4,pc) into @(.+4,pc) */ - if (immediate.X_op == O_constant) { - immediate.X_add_symbol = dot(); - immediate.X_op = O_symbol; - } - op->type = A_DISP_PC; - } - else - { - as_bad ("syntax error in @(disp,[Rn, gbr, pc])"); - } - } - else - { - as_bad ("syntax error in @(disp,[Rn, gbr, pc])"); - } - } - src += len; - if (src[0] != ')') - as_bad ("expecting )"); - else - src++; - } - else - { - src += parse_reg (src, &mode, &(op->reg)); - if (mode != A_REG_N) - { - as_bad ("illegal register after @"); - } - if (src[0] == '+') - { - op->type = A_INC_N; - src++; - } - else - { - op->type = A_IND_N; - } - } - return src; -} - -static void -get_operand (ptr, op) - char **ptr; - sh_operand_info *op; -{ - char *src = *ptr; - int mode = -1; - unsigned int len; - - if (src[0] == '#') - { - src++; - *ptr = parse_exp (src); - op->type = A_IMM; - return; - } - - else if (src[0] == '@') - { - *ptr = parse_at (src, op); - return; - } - len = parse_reg (src, &mode, &(op->reg)); - if (len) - { - *ptr = src + len; - op->type = mode; - return; - } - else - { - /* Not a reg, the only thing left is a displacement */ - *ptr = parse_exp (src); - op->type = A_DISP_PC; - return; - } -} - -static -char * -get_operands (info, args, operand) - sh_opcode_info *info; - char *args; - sh_operand_info *operand; - -{ - char *ptr = args; - if (info->arg[0]) - { - ptr++; - - get_operand (&ptr, operand + 0); - if (info->arg[1]) - { - if (*ptr == ',') - { - ptr++; - } - get_operand (&ptr, operand + 1); - if (info->arg[2]) - { - if (*ptr == ',') - { - ptr++; - } - get_operand (&ptr, operand + 2); - } - else - { - operand[2].type = 0; - } - } - else - { - operand[1].type = 0; - operand[2].type = 0; - } - } - else - { - operand[0].type = 0; - operand[1].type = 0; - operand[2].type = 0; - } - return ptr; -} - -/* Passed a pointer to a list of opcodes which use different - addressing modes, return the opcode which matches the opcodes - provided - */ - -static -sh_opcode_info * -get_specific (opcode, operands) - sh_opcode_info *opcode; - sh_operand_info *operands; -{ - sh_opcode_info *this_try = opcode; - char *name = opcode->name; - int n = 0; - while (opcode->name) - { - this_try = opcode++; - if (this_try->name != name) - { - /* We've looked so far down the table that we've run out of - opcodes with the same name */ - return 0; - } - /* look at both operands needed by the opcodes and provided by - the user - since an arg test will often fail on the same arg - again and again, we'll try and test the last failing arg the - first on each opcode try */ - - for (n = 0; this_try->arg[n]; n++) - { - sh_operand_info *user = operands + n; - sh_arg_type arg = this_try->arg[n]; - switch (arg) - { - case A_IMM: - case A_BDISP12: - case A_BDISP8: - case A_DISP_GBR: - case A_DISP_PC: - case A_MACH: - case A_PR: - case A_MACL: - if (user->type != arg) - goto fail; - break; - case A_R0: - /* opcode needs r0 */ - if (user->type != A_REG_N || user->reg != 0) - goto fail; - break; - case A_R0_GBR: - if (user->type != A_R0_GBR || user->reg != 0) - goto fail; - break; - case F_FR0: - if (user->type != F_REG_N || user->reg != 0) - goto fail; - break; - - case A_REG_N: - case A_INC_N: - case A_DEC_N: - case A_IND_N: - case A_IND_R0_REG_N: - case A_DISP_REG_N: - case F_REG_N: - case D_REG_N: - case X_REG_N: - case V_REG_N: - case FPUL_N: - case FPSCR_N: - /* Opcode needs rn */ - if (user->type != arg) - goto fail; - reg_n = user->reg; - break; - case FD_REG_N: - if (user->type != F_REG_N && user->type != D_REG_N) - goto fail; - reg_n = user->reg; - break; - case DX_REG_N: - if (user->type != D_REG_N && user->type != X_REG_N) - goto fail; - reg_n = user->reg; - break; - case A_GBR: - case A_SR: - case A_VBR: - case A_SSR: - case A_SPC: - case A_SGR: - case A_DBR: - if (user->type != arg) - goto fail; - break; - - case A_REG_B: - if (user->type != arg) - goto fail; - reg_b = user->reg; - break; - - case A_REG_M: - case A_INC_M: - case A_DEC_M: - case A_IND_M: - case A_IND_R0_REG_M: - case A_DISP_REG_M: - /* Opcode needs rn */ - if (user->type != arg - A_REG_M + A_REG_N) - goto fail; - reg_m = user->reg; - break; - - case F_REG_M: - case D_REG_M: - case X_REG_M: - case V_REG_M: - case FPUL_M: - case FPSCR_M: - /* Opcode needs rn */ - if (user->type != arg - F_REG_M + F_REG_N) - goto fail; - reg_m = user->reg; - break; - case DX_REG_M: - if (user->type != D_REG_N && user->type != X_REG_N) - goto fail; - reg_m = user->reg; - break; - case XMTRX_M4: - if (user->type != XMTRX_M4) - goto fail; - reg_m = 4; - break; - - default: - printf ("unhandled %d\n", arg); - goto fail; - } - } - return this_try; - fail:; - } - - return 0; -} - -int -check (operand, low, high) - expressionS *operand; - int low; - int high; -{ - if (operand->X_op != O_constant - || operand->X_add_number < low - || operand->X_add_number > high) - { - as_bad ("operand must be absolute in range %d..%d", low, high); - } - return operand->X_add_number; -} - - -static void -insert (where, how, pcrel) - char *where; - int how; - int pcrel; -{ - fix_new_exp (frag_now, - where - frag_now->fr_literal, - 2, - &immediate, - pcrel, - how); -} - -static void -build_relax (opcode) - sh_opcode_info *opcode; -{ - int high_byte = target_big_endian ? 0 : 1; - char *p; - - if (opcode->arg[0] == A_BDISP8) - { - p = frag_var (rs_machine_dependent, - md_relax_table[C (COND_JUMP, COND32)].rlx_length, - md_relax_table[C (COND_JUMP, COND8)].rlx_length, - C (COND_JUMP, 0), - immediate.X_add_symbol, - immediate.X_add_number, - 0); - p[high_byte] = (opcode->nibbles[0] << 4) | (opcode->nibbles[1]); - } - else if (opcode->arg[0] == A_BDISP12) - { - p = frag_var (rs_machine_dependent, - md_relax_table[C (UNCOND_JUMP, UNCOND32)].rlx_length, - md_relax_table[C (UNCOND_JUMP, UNCOND12)].rlx_length, - C (UNCOND_JUMP, 0), - immediate.X_add_symbol, - immediate.X_add_number, - 0); - p[high_byte] = (opcode->nibbles[0] << 4); - } - -} - -/* Now we know what sort of opcodes it is, lets build the bytes - - */ -static void -build_Mytes (opcode, operand) - sh_opcode_info *opcode; - sh_operand_info *operand; - -{ - int index; - char nbuf[4]; - char *output = frag_more (2); - int low_byte = target_big_endian ? 1 : 0; - nbuf[0] = 0; - nbuf[1] = 0; - nbuf[2] = 0; - nbuf[3] = 0; - - for (index = 0; index < 4; index++) - { - sh_nibble_type i = opcode->nibbles[index]; - if (i < 16) - { - nbuf[index] = i; - } - else - { - switch (i) - { - case REG_N: - nbuf[index] = reg_n; - break; - case REG_M: - nbuf[index] = reg_m; - break; - case REG_NM: - nbuf[index] = reg_n | (reg_m >> 2); - break; - case REG_B: - nbuf[index] = reg_b | 0x08; - break; - case DISP_4: - insert (output + low_byte, BFD_RELOC_SH_IMM4, 0); - break; - case IMM_4BY4: - insert (output + low_byte, BFD_RELOC_SH_IMM4BY4, 0); - break; - case IMM_4BY2: - insert (output + low_byte, BFD_RELOC_SH_IMM4BY2, 0); - break; - case IMM_4: - insert (output + low_byte, BFD_RELOC_SH_IMM4, 0); - break; - case IMM_8BY4: - insert (output + low_byte, BFD_RELOC_SH_IMM8BY4, 0); - break; - case IMM_8BY2: - insert (output + low_byte, BFD_RELOC_SH_IMM8BY2, 0); - break; - case IMM_8: - insert (output + low_byte, BFD_RELOC_SH_IMM8, 0); - break; - case PCRELIMM_8BY4: - insert (output, BFD_RELOC_SH_PCRELIMM8BY4, 1); - break; - case PCRELIMM_8BY2: - insert (output, BFD_RELOC_SH_PCRELIMM8BY2, 1); - break; - default: - printf ("failed for %d\n", i); - } - } - } - if (! target_big_endian) { - output[1] = (nbuf[0] << 4) | (nbuf[1]); - output[0] = (nbuf[2] << 4) | (nbuf[3]); - } - else { - output[0] = (nbuf[0] << 4) | (nbuf[1]); - output[1] = (nbuf[2] << 4) | (nbuf[3]); - } -} - -/* This is the guts of the machine-dependent assembler. STR points to a - machine dependent instruction. This function is supposed to emit - the frags/bytes it assembles to. - */ - -void -md_assemble (str) - char *str; -{ - unsigned char *op_start; - unsigned char *op_end; - sh_operand_info operand[3]; - sh_opcode_info *opcode; - char name[20]; - int nlen = 0; - /* Drop leading whitespace */ - while (*str == ' ') - str++; - - /* find the op code end */ - for (op_start = op_end = (unsigned char *) (str); - *op_end - && nlen < 20 - && !is_end_of_line[*op_end] && *op_end != ' '; - op_end++) - { - name[nlen] = op_start[nlen]; - nlen++; - } - name[nlen] = 0; - - if (nlen == 0) - { - as_bad ("can't find opcode "); - } - - opcode = (sh_opcode_info *) hash_find (opcode_hash_control, name); - - if (opcode == NULL) - { - as_bad ("unknown opcode"); - return; - } - - if (sh_relax - && ! seg_info (now_seg)->tc_segment_info_data.in_code) - { - /* Output a CODE reloc to tell the linker that the following - bytes are instructions, not data. */ - fix_new (frag_now, frag_now_fix (), 2, &abs_symbol, 0, 0, - BFD_RELOC_SH_CODE); - seg_info (now_seg)->tc_segment_info_data.in_code = 1; - } - - if (opcode->arg[0] == A_BDISP12 - || opcode->arg[0] == A_BDISP8) - { - parse_exp (op_end + 1); - build_relax (opcode); - } - else - { - if (opcode->arg[0] != A_END) - { - get_operands (opcode, op_end, operand); - } - opcode = get_specific (opcode, operand); - - if (opcode == 0) - { - /* Couldn't find an opcode which matched the operands */ - char *where = frag_more (2); - - where[0] = 0x0; - where[1] = 0x0; - as_bad ("invalid operands for opcode"); - return; - } - - build_Mytes (opcode, operand); - } - -} - -/* This routine is called each time a label definition is seen. It - emits a BFD_RELOC_SH_LABEL reloc if necessary. */ - -void -sh_frob_label () -{ - static fragS *last_label_frag; - static int last_label_offset; - - if (sh_relax - && seg_info (now_seg)->tc_segment_info_data.in_code) - { - int offset; - - offset = frag_now_fix (); - if (frag_now != last_label_frag - || offset != last_label_offset) - { - fix_new (frag_now, offset, 2, &abs_symbol, 0, 0, BFD_RELOC_SH_LABEL); - last_label_frag = frag_now; - last_label_offset = offset; - } - } -} - -/* This routine is called when the assembler is about to output some - data. It emits a BFD_RELOC_SH_DATA reloc if necessary. */ - -void -sh_flush_pending_output () -{ - if (sh_relax - && seg_info (now_seg)->tc_segment_info_data.in_code) - { - fix_new (frag_now, frag_now_fix (), 2, &abs_symbol, 0, 0, - BFD_RELOC_SH_DATA); - seg_info (now_seg)->tc_segment_info_data.in_code = 0; - } -} - -symbolS * -DEFUN (md_undefined_symbol, (name), - char *name) -{ - return 0; -} - -#ifdef OBJ_COFF - -void -DEFUN (tc_crawl_symbol_chain, (headers), - object_headers * headers) -{ - printf ("call to tc_crawl_symbol_chain \n"); -} - -void -DEFUN (tc_headers_hook, (headers), - object_headers * headers) -{ - printf ("call to tc_headers_hook \n"); -} - -#endif - -/* Various routines to kill one day */ -/* Equal to MAX_PRECISION in atof-ieee.c */ -#define MAX_LITTLENUMS 6 - -/* Turn a string in input_line_pointer into a floating point constant of type - type, and store the appropriate bytes in *litP. The number of LITTLENUMS - emitted is stored in *sizeP . An error message is returned, or NULL on OK. - */ -char * -md_atof (type, litP, sizeP) - int type; - char *litP; - int *sizeP; -{ - int prec; - LITTLENUM_TYPE words[4]; - char *t; - int i; - - switch (type) - { - case 'f': - prec = 2; - break; - - case 'd': - prec = 4; - break; - - default: - *sizeP = 0; - return "bad call to md_atof"; - } - - t = atof_ieee (input_line_pointer, type, words); - if (t) - input_line_pointer = t; - - *sizeP = prec * 2; - - if (! target_big_endian) - { - for (i = prec - 1; i >= 0; i--) - { - md_number_to_chars (litP, (valueT) words[i], 2); - litP += 2; - } - } - else - { - for (i = 0; i < prec; i++) - { - md_number_to_chars (litP, (valueT) words[i], 2); - litP += 2; - } - } - - return NULL; -} - -/* Handle the .uses pseudo-op. This pseudo-op is used just before a - call instruction. It refers to a label of the instruction which - loads the register which the call uses. We use it to generate a - special reloc for the linker. */ - -static void -s_uses (ignore) - int ignore; -{ - expressionS ex; - - if (! sh_relax) - as_warn (".uses pseudo-op seen when not relaxing"); - - expression (&ex); - - if (ex.X_op != O_symbol || ex.X_add_number != 0) - { - as_bad ("bad .uses format"); - ignore_rest_of_line (); - return; - } - - fix_new_exp (frag_now, frag_now_fix (), 2, &ex, 1, BFD_RELOC_SH_USES); - - demand_empty_rest_of_line (); -} - -CONST char *md_shortopts = ""; -struct option md_longopts[] = { - -#define OPTION_RELAX (OPTION_MD_BASE) -#define OPTION_LITTLE (OPTION_MD_BASE + 1) -#define OPTION_SMALL (OPTION_LITTLE + 1) - - {"relax", no_argument, NULL, OPTION_RELAX}, - {"little", no_argument, NULL, OPTION_LITTLE}, - {"small", no_argument, NULL, OPTION_SMALL}, - {NULL, no_argument, NULL, 0} -}; -size_t md_longopts_size = sizeof(md_longopts); - -int -md_parse_option (c, arg) - int c; - char *arg; -{ - switch (c) - { - case OPTION_RELAX: - sh_relax = 1; - break; - - case OPTION_LITTLE: - shl = 1; - target_big_endian = 0; - break; - - case OPTION_SMALL: - sh_small = 1; - break; - - default: - return 0; - } - - return 1; -} - -void -md_show_usage (stream) - FILE *stream; -{ - fprintf(stream, "\ -SH options:\n\ --little generate little endian code\n\ --relax alter jump instructions for long displacements\n\ --small align sections to 4 byte boundaries, not 16\n"); -} - -int md_short_jump_size; - -void -tc_Nout_fix_to_chars () -{ - printf ("call to tc_Nout_fix_to_chars \n"); - abort (); -} - -void -md_create_short_jump (ptr, from_Nddr, to_Nddr, frag, to_symbol) - char *ptr; - addressT from_Nddr; - addressT to_Nddr; - fragS *frag; - symbolS *to_symbol; -{ - as_fatal ("failed sanity check."); -} - -void -md_create_long_jump (ptr, from_Nddr, to_Nddr, frag, to_symbol) - char *ptr; - addressT from_Nddr, to_Nddr; - fragS *frag; - symbolS *to_symbol; -{ - as_fatal ("failed sanity check."); -} - -/* This struct is used to pass arguments to sh_count_relocs through - bfd_map_over_sections. */ - -struct sh_count_relocs -{ - /* Symbol we are looking for. */ - symbolS *sym; - /* Count of relocs found. */ - int count; -}; - -/* Count the number of fixups in a section which refer to a particular - symbol. When using BFD_ASSEMBLER, this is called via - bfd_map_over_sections. */ - -/*ARGSUSED*/ -static void -sh_count_relocs (abfd, sec, data) - bfd *abfd; - segT sec; - PTR data; -{ - struct sh_count_relocs *info = (struct sh_count_relocs *) data; - segment_info_type *seginfo; - symbolS *sym; - fixS *fix; - - seginfo = seg_info (sec); - if (seginfo == NULL) - return; - - sym = info->sym; - for (fix = seginfo->fix_root; fix != NULL; fix = fix->fx_next) - { - if (fix->fx_addsy == sym) - { - ++info->count; - fix->fx_tcbit = 1; - } - } -} - -/* Handle the count relocs for a particular section. When using - BFD_ASSEMBLER, this is called via bfd_map_over_sections. */ - -/*ARGSUSED*/ -static void -sh_frob_section (abfd, sec, ignore) - bfd *abfd; - segT sec; - PTR ignore; -{ - segment_info_type *seginfo; - fixS *fix; - - seginfo = seg_info (sec); - if (seginfo == NULL) - return; - - for (fix = seginfo->fix_root; fix != NULL; fix = fix->fx_next) - { - symbolS *sym; - bfd_vma val; - fixS *fscan; - struct sh_count_relocs info; - - if (fix->fx_r_type != BFD_RELOC_SH_USES) - continue; - - /* The BFD_RELOC_SH_USES reloc should refer to a defined local - symbol in the same section. */ - sym = fix->fx_addsy; - if (sym == NULL - || fix->fx_subsy != NULL - || fix->fx_addnumber != 0 - || S_GET_SEGMENT (sym) != sec -#if ! defined (BFD_ASSEMBLER) && defined (OBJ_COFF) - || S_GET_STORAGE_CLASS (sym) == C_EXT -#endif - || S_IS_EXTERNAL (sym)) - { - as_warn_where (fix->fx_file, fix->fx_line, - ".uses does not refer to a local symbol in the same section"); - continue; - } - - /* Look through the fixups again, this time looking for one - at the same location as sym. */ - val = S_GET_VALUE (sym); - for (fscan = seginfo->fix_root; - fscan != NULL; - fscan = fscan->fx_next) - if (val == fscan->fx_frag->fr_address + fscan->fx_where - && fscan->fx_r_type != BFD_RELOC_SH_ALIGN - && fscan->fx_r_type != BFD_RELOC_SH_CODE - && fscan->fx_r_type != BFD_RELOC_SH_DATA - && fscan->fx_r_type != BFD_RELOC_SH_LABEL) - break; - if (fscan == NULL) - { - as_warn_where (fix->fx_file, fix->fx_line, - "can't find fixup pointed to by .uses"); - continue; - } - - if (fscan->fx_tcbit) - { - /* We've already done this one. */ - continue; - } - - /* fscan should also be a fixup to a local symbol in the same - section. */ - sym = fscan->fx_addsy; - if (sym == NULL - || fscan->fx_subsy != NULL - || fscan->fx_addnumber != 0 - || S_GET_SEGMENT (sym) != sec -#if ! defined (BFD_ASSEMBLER) && defined (OBJ_COFF) - || S_GET_STORAGE_CLASS (sym) == C_EXT -#endif - || S_IS_EXTERNAL (sym)) - { - as_warn_where (fix->fx_file, fix->fx_line, - ".uses target does not refer to a local symbol in the same section"); - continue; - } - - /* Now we look through all the fixups of all the sections, - counting the number of times we find a reference to sym. */ - info.sym = sym; - info.count = 0; -#ifdef BFD_ASSEMBLER - bfd_map_over_sections (stdoutput, sh_count_relocs, (PTR) &info); -#else - { - int iscan; - - for (iscan = SEG_E0; iscan < SEG_UNKNOWN; iscan++) - sh_count_relocs ((bfd *) NULL, iscan, (PTR) &info); - } -#endif - - if (info.count < 1) - abort (); - - /* Generate a BFD_RELOC_SH_COUNT fixup at the location of sym. - We have already adjusted the value of sym to include the - fragment address, so we undo that adjustment here. */ - subseg_change (sec, 0); - fix_new (sym->sy_frag, S_GET_VALUE (sym) - sym->sy_frag->fr_address, - 4, &abs_symbol, info.count, 0, BFD_RELOC_SH_COUNT); - } -} - -/* This function is called after the symbol table has been completed, - but before the relocs or section contents have been written out. - If we have seen any .uses pseudo-ops, they point to an instruction - which loads a register with the address of a function. We look - through the fixups to find where the function address is being - loaded from. We then generate a COUNT reloc giving the number of - times that function address is referred to. The linker uses this - information when doing relaxing, to decide when it can eliminate - the stored function address entirely. */ - -void -sh_frob_file () -{ - if (! sh_relax) - return; - -#ifdef BFD_ASSEMBLER - bfd_map_over_sections (stdoutput, sh_frob_section, (PTR) NULL); -#else - { - int iseg; - - for (iseg = SEG_E0; iseg < SEG_UNKNOWN; iseg++) - sh_frob_section ((bfd *) NULL, iseg, (PTR) NULL); - } -#endif -} - -/* Called after relaxing. Set the correct sizes of the fragments, and - create relocs so that md_apply_fix will fill in the correct values. */ - -void -md_convert_frag (headers, seg, fragP) -#ifdef BFD_ASSEMBLER - bfd *headers; -#else - object_headers *headers; -#endif - segT seg; - fragS *fragP; -{ - int donerelax = 0; - - switch (fragP->fr_subtype) - { - case C (COND_JUMP, COND8): - subseg_change (seg, 0); - fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset, - 1, BFD_RELOC_SH_PCDISP8BY2); - fragP->fr_fix += 2; - fragP->fr_var = 0; - break; - - case C (UNCOND_JUMP, UNCOND12): - subseg_change (seg, 0); - fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, fragP->fr_offset, - 1, BFD_RELOC_SH_PCDISP12BY2); - fragP->fr_fix += 2; - fragP->fr_var = 0; - break; - - case C (UNCOND_JUMP, UNCOND32): - case C (UNCOND_JUMP, UNDEF_WORD_DISP): - if (fragP->fr_symbol == NULL) - as_bad ("at 0x%lx, displacement overflows 12-bit field", - (unsigned long) fragP->fr_address); - else - as_bad ("at 0x%lx, displacement to %sdefined symbol %s overflows 12-bit field", - (unsigned long) fragP->fr_address, - S_IS_DEFINED (fragP->fr_symbol) ? "" : "un", - S_GET_NAME (fragP->fr_symbol)); - -#if 0 /* This code works, but generates poor code and the compiler - should never produce a sequence that requires it to be used. */ - - /* A jump wont fit in 12 bits, make code which looks like - bra foo - mov.w @(0, PC), r14 - .long disp - foo: bra @r14 - */ - int t = buffer[0] & 0x10; - - buffer[highbyte] = 0xa0; /* branch over move and disp */ - buffer[lowbyte] = 3; - buffer[highbyte+2] = 0xd0 | JREG; /* Build mov insn */ - buffer[lowbyte+2] = 0x00; - - buffer[highbyte+4] = 0; /* space for 32 bit jump disp */ - buffer[lowbyte+4] = 0; - buffer[highbyte+6] = 0; - buffer[lowbyte+6] = 0; - - buffer[highbyte+8] = 0x40 | JREG; /* Build jmp @JREG */ - buffer[lowbyte+8] = t ? 0xb : 0x2b; - - buffer[highbyte+10] = 0x20; /* build nop */ - buffer[lowbyte+10] = 0x0b; - - /* Make reloc for the long disp */ - fix_new (fragP, - fragP->fr_fix + 4, - 4, - fragP->fr_symbol, - fragP->fr_offset, - 0, - BFD_RELOC_32); - fragP->fr_fix += UNCOND32_LENGTH; - fragP->fr_var = 0; - donerelax = 1; -#endif - - break; - - case C (COND_JUMP, COND12): - /* A bcond won't fit, so turn it into a b!cond; bra disp; nop */ - { - unsigned char *buffer = - (unsigned char *) (fragP->fr_fix + fragP->fr_literal); - int highbyte = target_big_endian ? 0 : 1; - int lowbyte = target_big_endian ? 1 : 0; - - /* Toggle the true/false bit of the bcond. */ - buffer[highbyte] ^= 0x2; - - /* Build a relocation to six bytes farther on. */ - subseg_change (seg, 0); - fix_new (fragP, fragP->fr_fix, 2, -#ifdef BFD_ASSEMBLER - section_symbol (seg), -#else - seg_info (seg)->dot, -#endif - fragP->fr_address + fragP->fr_fix + 6, - 1, BFD_RELOC_SH_PCDISP8BY2); - - /* Set up a jump instruction. */ - buffer[highbyte + 2] = 0xa0; - buffer[lowbyte + 2] = 0; - fix_new (fragP, fragP->fr_fix + 2, 2, fragP->fr_symbol, - fragP->fr_offset, 1, BFD_RELOC_SH_PCDISP12BY2); - - /* Fill in a NOP instruction. */ - buffer[highbyte + 4] = 0x0; - buffer[lowbyte + 4] = 0x9; - - fragP->fr_fix += 6; - fragP->fr_var = 0; - donerelax = 1; - } - break; - - case C (COND_JUMP, COND32): - case C (COND_JUMP, UNDEF_WORD_DISP): - if (fragP->fr_symbol == NULL) - as_bad ("at 0x%lx, displacement overflows 8-bit field", - (unsigned long) fragP->fr_address); - else - as_bad ("at 0x%lx, displacement to %sdefined symbol %s overflows 8-bit field ", - (unsigned long) fragP->fr_address, - S_IS_DEFINED (fragP->fr_symbol) ? "" : "un", - S_GET_NAME (fragP->fr_symbol)); - -#if 0 /* This code works, but generates poor code, and the compiler - should never produce a sequence that requires it to be used. */ - - /* A bcond won't fit and it won't go into a 12 bit - displacement either, the code sequence looks like: - b!cond foop - mov.w @(n, PC), r14 - jmp @r14 - nop - .long where - foop: - */ - - buffer[0] ^= 0x2; /* Toggle T/F bit */ -#define JREG 14 - buffer[1] = 5; /* branch over mov, jump, nop and ptr */ - buffer[2] = 0xd0 | JREG; /* Build mov insn */ - buffer[3] = 0x2; - buffer[4] = 0x40 | JREG; /* Build jmp @JREG */ - buffer[5] = 0x0b; - buffer[6] = 0x20; /* build nop */ - buffer[7] = 0x0b; - buffer[8] = 0; /* space for 32 bit jump disp */ - buffer[9] = 0; - buffer[10] = 0; - buffer[11] = 0; - buffer[12] = 0; - buffer[13] = 0; - /* Make reloc for the long disp */ - fix_new (fragP, - fragP->fr_fix + 8, - 4, - fragP->fr_symbol, - fragP->fr_offset, - 0, - BFD_RELOC_32); - fragP->fr_fix += COND32_LENGTH; - fragP->fr_var = 0; - donerelax = 1; -#endif - - break; - - default: - abort (); - } - - if (donerelax && !sh_relax) - as_warn_where (fragP->fr_file, fragP->fr_line, - "overflow in branch to %s; converted into longer instruction sequence", - (fragP->fr_symbol != NULL - ? S_GET_NAME (fragP->fr_symbol) - : "")); -} - -valueT -DEFUN (md_section_align, (seg, size), - segT seg AND - valueT size) -{ -#ifdef BFD_ASSEMBLER -#ifdef OBJ_ELF - return size; -#else /* ! OBJ_ELF */ - return ((size + (1 << bfd_get_section_alignment (stdoutput, seg)) - 1) - & (-1 << bfd_get_section_alignment (stdoutput, seg))); -#endif /* ! OBJ_ELF */ -#else /* ! BFD_ASSEMBLER */ - return ((size + (1 << section_alignment[(int) seg]) - 1) - & (-1 << section_alignment[(int) seg])); -#endif /* ! BFD_ASSEMBLER */ -} - -/* This static variable is set by s_uacons to tell sh_cons_align that - the expession does not need to be aligned. */ - -static int sh_no_align_cons = 0; - -/* This handles the unaligned space allocation pseudo-ops, such as - .uaword. .uaword is just like .word, but the value does not need - to be aligned. */ - -static void -s_uacons (bytes) - int bytes; -{ - /* Tell sh_cons_align not to align this value. */ - sh_no_align_cons = 1; - cons (bytes); -} - -/* If a .word, et. al., pseud-op is seen, warn if the value is not - aligned correctly. Note that this can cause warnings to be issued - when assembling initialized structured which were declared with the - packed attribute. FIXME: Perhaps we should require an option to - enable this warning? */ - -void -sh_cons_align (nbytes) - int nbytes; -{ - int nalign; - char *p; - - if (sh_no_align_cons) - { - /* This is an unaligned pseudo-op. */ - sh_no_align_cons = 0; - return; - } - - nalign = 0; - while ((nbytes & 1) == 0) - { - ++nalign; - nbytes >>= 1; - } - - if (nalign == 0) - return; - - if (now_seg == absolute_section) - { - if ((abs_section_offset & ((1 << nalign) - 1)) != 0) - as_warn ("misaligned data"); - return; - } - - p = frag_var (rs_align_code, 1, 1, (relax_substateT) 0, - (symbolS *) NULL, (offsetT) nalign, (char *) NULL); - - record_alignment (now_seg, nalign); -} - -/* When relaxing, we need to output a reloc for any .align directive - that requests alignment to a four byte boundary or larger. This is - also where we check for misaligned data. */ - -void -sh_handle_align (frag) - fragS *frag; -{ - if (sh_relax - && frag->fr_type == rs_align - && frag->fr_address + frag->fr_fix > 0 - && frag->fr_offset > 1 - && now_seg != bss_section) - fix_new (frag, frag->fr_fix, 2, &abs_symbol, frag->fr_offset, 0, - BFD_RELOC_SH_ALIGN); - - if (frag->fr_type == rs_align_code - && frag->fr_next->fr_address - frag->fr_address - frag->fr_fix != 0) - as_warn_where (frag->fr_file, frag->fr_line, "misaligned data"); -} - -/* This macro decides whether a particular reloc is an entry in a - switch table. It is used when relaxing, because the linker needs - to know about all such entries so that it can adjust them if - necessary. */ - -#ifdef BFD_ASSEMBLER -#define SWITCH_TABLE_CONS(fix) (0) -#else -#define SWITCH_TABLE_CONS(fix) \ - ((fix)->fx_r_type == 0 \ - && ((fix)->fx_size == 2 \ - || (fix)->fx_size == 1 \ - || (fix)->fx_size == 4)) -#endif - -#define SWITCH_TABLE(fix) \ - ((fix)->fx_addsy != NULL \ - && (fix)->fx_subsy != NULL \ - && S_GET_SEGMENT ((fix)->fx_addsy) == text_section \ - && S_GET_SEGMENT ((fix)->fx_subsy) == text_section \ - && ((fix)->fx_r_type == BFD_RELOC_32 \ - || (fix)->fx_r_type == BFD_RELOC_16 \ - || (fix)->fx_r_type == BFD_RELOC_8 \ - || SWITCH_TABLE_CONS (fix))) - -/* See whether we need to force a relocation into the output file. - This is used to force out switch and PC relative relocations when - relaxing. */ - -int -sh_force_relocation (fix) - fixS *fix; -{ - if (! sh_relax) - return 0; - - return (fix->fx_pcrel - || SWITCH_TABLE (fix) - || fix->fx_r_type == BFD_RELOC_SH_COUNT - || fix->fx_r_type == BFD_RELOC_SH_ALIGN - || fix->fx_r_type == BFD_RELOC_SH_CODE - || fix->fx_r_type == BFD_RELOC_SH_DATA - || fix->fx_r_type == BFD_RELOC_SH_LABEL); -} - -/* Apply a fixup to the object file. */ - -#ifdef BFD_ASSEMBLER -int -md_apply_fix (fixP, valp) - fixS *fixP; - valueT *valp; -#else -void -md_apply_fix (fixP, val) - fixS *fixP; - long val; -#endif -{ - char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; - int lowbyte = target_big_endian ? 1 : 0; - int highbyte = target_big_endian ? 0 : 1; -#ifdef BFD_ASSEMBLER - long val = *valp; -#endif - long max, min; - int shift; - -#ifndef BFD_ASSEMBLER - if (fixP->fx_r_type == 0) - { - if (fixP->fx_size == 2) - fixP->fx_r_type = BFD_RELOC_16; - else if (fixP->fx_size == 4) - fixP->fx_r_type = BFD_RELOC_32; - else if (fixP->fx_size == 1) - fixP->fx_r_type = BFD_RELOC_8; - else - abort (); - } -#endif - - max = min = 0; - shift = 0; - switch (fixP->fx_r_type) - { - case BFD_RELOC_SH_IMM4: - max = 0xf; - *buf = (*buf & 0xf0) | (val & 0xf); - break; - - case BFD_RELOC_SH_IMM4BY2: - max = 0xf; - shift = 1; - *buf = (*buf & 0xf0) | ((val >> 1) & 0xf); - break; - - case BFD_RELOC_SH_IMM4BY4: - max = 0xf; - shift = 2; - *buf = (*buf & 0xf0) | ((val >> 2) & 0xf); - break; - - case BFD_RELOC_SH_IMM8BY2: - max = 0xff; - shift = 1; - *buf = val >> 1; - break; - - case BFD_RELOC_SH_IMM8BY4: - max = 0xff; - shift = 2; - *buf = val >> 2; - break; - - case BFD_RELOC_8: - case BFD_RELOC_SH_IMM8: - /* Sometimes the 8 bit value is sign extended (e.g., add) and - sometimes it is not (e.g., and). We permit any 8 bit value. - Note that adding further restrictions may invalidate - reasonable looking assembly code, such as ``and -0x1,r0''. */ - max = 0xff; - min = - 0xff; - *buf++ = val; - break; - - case BFD_RELOC_SH_PCRELIMM8BY4: - /* The lower two bits of the PC are cleared before the - displacement is added in. We can assume that the destination - is on a 4 byte bounday. If this instruction is also on a 4 - byte boundary, then we want - (target - here) / 4 - and target - here is a multiple of 4. - Otherwise, we are on a 2 byte boundary, and we want - (target - (here - 2)) / 4 - and target - here is not a multiple of 4. Computing - (target - (here - 2)) / 4 == (target - here + 2) / 4 - works for both cases, since in the first case the addition of - 2 will be removed by the division. target - here is in the - variable val. */ - val = (val + 2) / 4; - if (val & ~0xff) - as_bad_where (fixP->fx_file, fixP->fx_line, "pcrel too far"); - buf[lowbyte] = val; - break; - - case BFD_RELOC_SH_PCRELIMM8BY2: - val /= 2; - if (val & ~0xff) - as_bad_where (fixP->fx_file, fixP->fx_line, "pcrel too far"); - buf[lowbyte] = val; - break; - - case BFD_RELOC_SH_PCDISP8BY2: - val /= 2; - if (val < -0x80 || val > 0x7f) - as_bad_where (fixP->fx_file, fixP->fx_line, "pcrel too far"); - buf[lowbyte] = val; - break; - - case BFD_RELOC_SH_PCDISP12BY2: - val /= 2; - if (val < -0x800 || val >= 0x7ff) - as_bad_where (fixP->fx_file, fixP->fx_line, "pcrel too far"); - buf[lowbyte] = val & 0xff; - buf[highbyte] |= (val >> 8) & 0xf; - break; - - case BFD_RELOC_32: - if (! target_big_endian) - { - *buf++ = val >> 0; - *buf++ = val >> 8; - *buf++ = val >> 16; - *buf++ = val >> 24; - } - else - { - *buf++ = val >> 24; - *buf++ = val >> 16; - *buf++ = val >> 8; - *buf++ = val >> 0; - } - break; - - case BFD_RELOC_16: - if (! target_big_endian) - { - *buf++ = val >> 0; - *buf++ = val >> 8; - } - else - { - *buf++ = val >> 8; - *buf++ = val >> 0; - } - break; - - case BFD_RELOC_SH_USES: - /* Pass the value into sh_coff_reloc_mangle. */ - fixP->fx_addnumber = val; - break; - - case BFD_RELOC_SH_COUNT: - case BFD_RELOC_SH_ALIGN: - case BFD_RELOC_SH_CODE: - case BFD_RELOC_SH_DATA: - case BFD_RELOC_SH_LABEL: - /* Nothing to do here. */ - break; - - default: - abort (); - } - - if (shift != 0) - { - if ((val & ((1 << shift) - 1)) != 0) - as_bad_where (fixP->fx_file, fixP->fx_line, "misaligned offset"); - if (val >= 0) - val >>= shift; - else - val = ((val >> shift) - | ((long) -1 & ~ ((long) -1 >> shift))); - } - if (max != 0 && (val < min || val > max)) - as_bad_where (fixP->fx_file, fixP->fx_line, "offset out of range"); - -#ifdef BFD_ASSEMBLER - return 0; -#endif -} - -int md_long_jump_size; - -/* Called just before address relaxation. Return the length - by which a fragment must grow to reach it's destination. */ - -int -md_estimate_size_before_relax (fragP, segment_type) - register fragS *fragP; - register segT segment_type; -{ - switch (fragP->fr_subtype) - { - case C (UNCOND_JUMP, UNDEF_DISP): - /* used to be a branch to somewhere which was unknown */ - if (!fragP->fr_symbol) - { - fragP->fr_subtype = C (UNCOND_JUMP, UNCOND12); - fragP->fr_var = md_relax_table[C (UNCOND_JUMP, UNCOND12)].rlx_length; - } - else if (S_GET_SEGMENT (fragP->fr_symbol) == segment_type) - { - fragP->fr_subtype = C (UNCOND_JUMP, UNCOND12); - fragP->fr_var = md_relax_table[C (UNCOND_JUMP, UNCOND12)].rlx_length; - } - else - { - fragP->fr_subtype = C (UNCOND_JUMP, UNDEF_WORD_DISP); - fragP->fr_var = md_relax_table[C (UNCOND_JUMP, UNCOND32)].rlx_length; - return md_relax_table[C (UNCOND_JUMP, UNCOND32)].rlx_length; - } - break; - - default: - abort (); - case C (COND_JUMP, UNDEF_DISP): - /* used to be a branch to somewhere which was unknown */ - if (fragP->fr_symbol - && S_GET_SEGMENT (fragP->fr_symbol) == segment_type) - { - /* Got a symbol and it's defined in this segment, become byte - sized - maybe it will fix up */ - fragP->fr_subtype = C (COND_JUMP, COND8); - fragP->fr_var = md_relax_table[C (COND_JUMP, COND8)].rlx_length; - } - else if (fragP->fr_symbol) - { - /* Its got a segment, but its not ours, so it will always be long */ - fragP->fr_subtype = C (COND_JUMP, UNDEF_WORD_DISP); - fragP->fr_var = md_relax_table[C (COND_JUMP, COND32)].rlx_length; - return md_relax_table[C (COND_JUMP, COND32)].rlx_length; - } - else - { - /* We know the abs value */ - fragP->fr_subtype = C (COND_JUMP, COND8); - fragP->fr_var = md_relax_table[C (COND_JUMP, COND8)].rlx_length; - } - - break; - } - return fragP->fr_var; -} - -/* Put number into target byte order */ - -void -md_number_to_chars (ptr, use, nbytes) - char *ptr; - valueT use; - int nbytes; -{ - if (! target_big_endian) - number_to_chars_littleendian (ptr, use, nbytes); - else - number_to_chars_bigendian (ptr, use, nbytes); -} - -long -md_pcrel_from (fixP) - fixS *fixP; -{ - return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address + 2; -} - -#ifdef OBJ_COFF - -int -tc_coff_sizemachdep (frag) - fragS *frag; -{ - return md_relax_table[frag->fr_subtype].rlx_length; -} - -#endif /* OBJ_COFF */ - -/* When we align the .text section, insert the correct NOP pattern. */ - -int -sh_do_align (n, fill, len, max) - int n; - const char *fill; - int len; - int max; -{ - if (fill == NULL -#ifdef BFD_ASSEMBLER - && (now_seg->flags & SEC_CODE) != 0 -#else - && now_seg != data_section - && now_seg != bss_section -#endif - && n > 1) - { - static const unsigned char big_nop_pattern[] = { 0x00, 0x09 }; - static const unsigned char little_nop_pattern[] = { 0x09, 0x00 }; - - /* First align to a 2 byte boundary, in case there is an odd - .byte. */ - frag_align (1, 0, 0); - if (target_big_endian) - frag_align_pattern (n, big_nop_pattern, sizeof big_nop_pattern, max); - else - frag_align_pattern (n, little_nop_pattern, sizeof little_nop_pattern, - max); - return 1; - } - - return 0; -} - -#ifndef BFD_ASSEMBLER -#ifdef OBJ_COFF - -/* Map BFD relocs to SH COFF relocs. */ - -struct reloc_map -{ - bfd_reloc_code_real_type bfd_reloc; - int sh_reloc; -}; - -static const struct reloc_map coff_reloc_map[] = -{ - { BFD_RELOC_32, R_SH_IMM32 }, - { BFD_RELOC_16, R_SH_IMM16 }, - { BFD_RELOC_8, R_SH_IMM8 }, - { BFD_RELOC_SH_PCDISP8BY2, R_SH_PCDISP8BY2 }, - { BFD_RELOC_SH_PCDISP12BY2, R_SH_PCDISP }, - { BFD_RELOC_SH_IMM4, R_SH_IMM4 }, - { BFD_RELOC_SH_IMM4BY2, R_SH_IMM4BY2 }, - { BFD_RELOC_SH_IMM4BY4, R_SH_IMM4BY4 }, - { BFD_RELOC_SH_IMM8, R_SH_IMM8 }, - { BFD_RELOC_SH_IMM8BY2, R_SH_IMM8BY2 }, - { BFD_RELOC_SH_IMM8BY4, R_SH_IMM8BY4 }, - { BFD_RELOC_SH_PCRELIMM8BY2, R_SH_PCRELIMM8BY2 }, - { BFD_RELOC_SH_PCRELIMM8BY4, R_SH_PCRELIMM8BY4 }, - { BFD_RELOC_8_PCREL, R_SH_SWITCH8 }, - { BFD_RELOC_SH_SWITCH16, R_SH_SWITCH16 }, - { BFD_RELOC_SH_SWITCH32, R_SH_SWITCH32 }, - { BFD_RELOC_SH_USES, R_SH_USES }, - { BFD_RELOC_SH_COUNT, R_SH_COUNT }, - { BFD_RELOC_SH_ALIGN, R_SH_ALIGN }, - { BFD_RELOC_SH_CODE, R_SH_CODE }, - { BFD_RELOC_SH_DATA, R_SH_DATA }, - { BFD_RELOC_SH_LABEL, R_SH_LABEL }, - { BFD_RELOC_UNUSED, 0 } -}; - -/* Adjust a reloc for the SH. This is similar to the generic code, - but does some minor tweaking. */ - -void -sh_coff_reloc_mangle (seg, fix, intr, paddr) - segment_info_type *seg; - fixS *fix; - struct internal_reloc *intr; - unsigned int paddr; -{ - symbolS *symbol_ptr = fix->fx_addsy; - symbolS *dot; - - intr->r_vaddr = paddr + fix->fx_frag->fr_address + fix->fx_where; - - if (! SWITCH_TABLE (fix)) - { - const struct reloc_map *rm; - - for (rm = coff_reloc_map; rm->bfd_reloc != BFD_RELOC_UNUSED; rm++) - if (rm->bfd_reloc == (bfd_reloc_code_real_type) fix->fx_r_type) - break; - if (rm->bfd_reloc == BFD_RELOC_UNUSED) - as_bad_where (fix->fx_file, fix->fx_line, - "Can not represent %s relocation in this object file format", - bfd_get_reloc_code_name (fix->fx_r_type)); - intr->r_type = rm->sh_reloc; - intr->r_offset = 0; - } - else - { - know (sh_relax); - - if (fix->fx_r_type == BFD_RELOC_16) - intr->r_type = R_SH_SWITCH16; - else if (fix->fx_r_type == BFD_RELOC_8) - intr->r_type = R_SH_SWITCH8; - else if (fix->fx_r_type == BFD_RELOC_32) - intr->r_type = R_SH_SWITCH32; - else - abort (); - - /* For a switch reloc, we set r_offset to the difference between - the reloc address and the subtrahend. When the linker is - doing relaxing, it can use the determine the starting and - ending points of the switch difference expression. */ - intr->r_offset = intr->r_vaddr - S_GET_VALUE (fix->fx_subsy); - } - - /* PC relative relocs are always against the current section. */ - if (symbol_ptr == NULL) - { - switch (fix->fx_r_type) - { - case BFD_RELOC_SH_PCRELIMM8BY2: - case BFD_RELOC_SH_PCRELIMM8BY4: - case BFD_RELOC_SH_PCDISP8BY2: - case BFD_RELOC_SH_PCDISP12BY2: - case BFD_RELOC_SH_USES: - symbol_ptr = seg->dot; - break; - default: - break; - } - } - - if (fix->fx_r_type == BFD_RELOC_SH_USES) - { - /* We can't store the offset in the object file, since this - reloc does not take up any space, so we store it in r_offset. - The fx_addnumber field was set in md_apply_fix. */ - intr->r_offset = fix->fx_addnumber; - } - else if (fix->fx_r_type == BFD_RELOC_SH_COUNT) - { - /* We can't store the count in the object file, since this reloc - does not take up any space, so we store it in r_offset. The - fx_offset field was set when the fixup was created in - sh_coff_frob_file. */ - intr->r_offset = fix->fx_offset; - /* This reloc is always absolute. */ - symbol_ptr = NULL; - } - else if (fix->fx_r_type == BFD_RELOC_SH_ALIGN) - { - /* Store the alignment in the r_offset field. */ - intr->r_offset = fix->fx_offset; - /* This reloc is always absolute. */ - symbol_ptr = NULL; - } - else if (fix->fx_r_type == BFD_RELOC_SH_CODE - || fix->fx_r_type == BFD_RELOC_SH_DATA - || fix->fx_r_type == BFD_RELOC_SH_LABEL) - { - /* These relocs are always absolute. */ - symbol_ptr = NULL; - } - - /* Turn the segment of the symbol into an offset. */ - if (symbol_ptr != NULL) - { - dot = segment_info[S_GET_SEGMENT (symbol_ptr)].dot; - if (dot != NULL) - intr->r_symndx = dot->sy_number; - else - intr->r_symndx = symbol_ptr->sy_number; - } - else - intr->r_symndx = -1; -} - -#endif /* OBJ_COFF */ -#endif /* ! BFD_ASSEMBLER */ - -#ifdef BFD_ASSEMBLER - -/* Create a reloc. */ - -arelent * -tc_gen_reloc (section, fixp) - asection *section; - fixS *fixp; -{ - arelent *rel; - bfd_reloc_code_real_type r_type; - - rel = (arelent *) xmalloc (sizeof (arelent)); - rel->sym_ptr_ptr = &fixp->fx_addsy->bsym; - rel->address = fixp->fx_frag->fr_address + fixp->fx_where; - - r_type = fixp->fx_r_type; - - if (SWITCH_TABLE (fixp)) - { - rel->addend = rel->address - S_GET_VALUE (fixp->fx_subsy); - if (r_type == BFD_RELOC_16) - r_type = BFD_RELOC_SH_SWITCH16; - else if (r_type == BFD_RELOC_8) - r_type = BFD_RELOC_8_PCREL; - else if (r_type == BFD_RELOC_32) - r_type = BFD_RELOC_SH_SWITCH32; - else - abort (); - } - else if (r_type == BFD_RELOC_SH_USES) - rel->addend = fixp->fx_addnumber; - else if (r_type == BFD_RELOC_SH_COUNT) - rel->addend = fixp->fx_offset; - else if (r_type == BFD_RELOC_SH_ALIGN) - rel->addend = fixp->fx_offset; - else if (fixp->fx_pcrel) - rel->addend = fixp->fx_addnumber; - else - rel->addend = 0; - - rel->howto = bfd_reloc_type_lookup (stdoutput, r_type); - if (rel->howto == NULL) - { - as_bad_where (fixp->fx_file, fixp->fx_line, - "Cannot represent relocation type %s", - bfd_get_reloc_code_name (r_type)); - /* Set howto to a garbage value so that we can keep going. */ - rel->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32); - assert (rel->howto != NULL); - } - - return rel; -} - -#endif /* BFD_ASSEMBLER */ diff --git a/contrib/binutils/gas/config/tc-sh.h b/contrib/binutils/gas/config/tc-sh.h deleted file mode 100644 index a18029b020d68..0000000000000 --- a/contrib/binutils/gas/config/tc-sh.h +++ /dev/null @@ -1,141 +0,0 @@ -/* This file is tc-sh.h - Copyright (C) 1993, 94, 95, 96, 1997 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. */ - -#define TC_SH - -#define TARGET_BYTES_BIG_ENDIAN 0 - -#define TARGET_ARCH bfd_arch_sh - -/* Whether in little endian mode. */ -extern int shl; - -/* Whether -relax was used. */ -extern int sh_relax; - -/* Whether -small was used. */ -extern int sh_small; - -/* Don't try to break words. */ -#define WORKING_DOT_WORD - -/* We require .long, et. al., to be aligned correctly. */ -#define md_cons_align(nbytes) sh_cons_align (nbytes) -extern void sh_cons_align PARAMS ((int)); - -/* When relaxing, we need to generate relocations for alignment - directives. */ -#define HANDLE_ALIGN(frag) sh_handle_align (frag) -extern void sh_handle_align PARAMS ((fragS *)); - -/* We need to force out some relocations when relaxing. */ -#define TC_FORCE_RELOCATION(fix) sh_force_relocation (fix) -extern int sh_force_relocation (); - -#define IGNORE_NONSTANDARD_ESCAPES - -#define LISTING_HEADER (shl ? "Hitachi Super-H GAS Little Endian" : "Hitachi Super-H GAS Big Endian") - -#define md_operand(x) - -extern const struct relax_type md_relax_table[]; -#define TC_GENERIC_RELAX_TABLE md_relax_table - -/* We use a special alignment function to insert the correct nop - pattern. */ -extern int sh_do_align PARAMS ((int, const char *, int, int)); -#define md_do_align(n,fill,len,max,l) if (sh_do_align (n,fill,len,max)) goto l - -/* We record, for each section, whether we have most recently output a - CODE reloc or a DATA reloc. */ -struct sh_segment_info_type -{ - int in_code : 1; -}; -#define TC_SEGMENT_INFO_TYPE struct sh_segment_info_type - -/* We call a routine to emit a reloc for a label, so that the linker - can align loads and stores without crossing a label. */ -extern void sh_frob_label PARAMS ((void)); -#define tc_frob_label(sym) sh_frob_label () - -/* We call a routine to flush pending output in order to output a DATA - reloc when required. */ -extern void sh_flush_pending_output PARAMS ((void)); -#define md_flush_pending_output() sh_flush_pending_output () - -#ifdef BFD_ASSEMBLER -#define tc_frob_file_before_adjust sh_frob_file -#else -#define tc_frob_file sh_frob_file -#endif -extern void sh_frob_file PARAMS ((void)); - -#ifdef OBJ_COFF -/* COFF specific definitions. */ - -#define DO_NOT_STRIP 0 - -/* This macro translates between an internal fix and an coff reloc type */ -#define TC_COFF_FIX2RTYPE(fix) ((fix)->fx_r_type) - -#define BFD_ARCH TARGET_ARCH - -#define COFF_MAGIC (shl ? SH_ARCH_MAGIC_LITTLE : SH_ARCH_MAGIC_BIG) - -/* We need to write out relocs which have not been completed. */ -#define TC_COUNT_RELOC(fix) ((fix)->fx_addsy != NULL) - -#define TC_RELOC_MANGLE(seg, fix, int, paddr) \ - sh_coff_reloc_mangle ((seg), (fix), (int), (paddr)) -extern void sh_coff_reloc_mangle (); - -#define tc_coff_symbol_emit_hook(a) ; /* not used */ - -#define NEED_FX_R_TYPE 1 - -#define TC_KEEP_FX_OFFSET 1 - -#define TC_COFF_SIZEMACHDEP(frag) tc_coff_sizemachdep(frag) -extern int tc_coff_sizemachdep PARAMS ((fragS *)); - -/* We align most sections to a 16 byte boundary. */ -#define SUB_SEGMENT_ALIGN(SEG) \ - (strncmp (obj_segment_name (SEG), ".stabstr", 8) == 0 \ - ? 0 \ - : ((strncmp (obj_segment_name (SEG), ".stab", 5) == 0 \ - || strcmp (obj_segment_name (SEG), ".ctors") == 0 \ - || strcmp (obj_segment_name (SEG), ".dtors") == 0) \ - ? 2 \ - : (sh_small ? 2 : 4))) - -#endif /* OBJ_COFF */ - -#ifdef OBJ_ELF -/* ELF specific definitions. */ - -/* Whether or not the target is big endian */ -extern int target_big_endian; - -#define TARGET_FORMAT (shl ? "elf32-shl" : "elf32-sh") - -#endif /* OBJ_ELF */ - -/* end of tc-sh.h */ diff --git a/contrib/binutils/gas/config/tc-sparc.c b/contrib/binutils/gas/config/tc-sparc.c deleted file mode 100644 index 149610e4699f2..0000000000000 --- a/contrib/binutils/gas/config/tc-sparc.c +++ /dev/null @@ -1,4017 +0,0 @@ -/* tc-sparc.c -- Assemble for the SPARC - Copyright (C) 1989, 90-96, 97, 98, 99, 2000 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. */ - -#include <stdio.h> -#include <ctype.h> - -#include "as.h" -#include "subsegs.h" - -#include "opcode/sparc.h" - -#ifdef OBJ_ELF -#include "elf/sparc.h" -#endif - -static struct sparc_arch *lookup_arch PARAMS ((char *)); -static void init_default_arch PARAMS ((void)); -static int sparc_ip PARAMS ((char *, const struct sparc_opcode **)); -static int in_signed_range PARAMS ((bfd_signed_vma, bfd_signed_vma)); -static int in_unsigned_range PARAMS ((bfd_vma, bfd_vma)); -static int in_bitfield_range PARAMS ((bfd_signed_vma, bfd_signed_vma)); -static int sparc_ffs PARAMS ((unsigned int)); -static void synthetize_setuw PARAMS ((const struct sparc_opcode *)); -static void synthetize_setsw PARAMS ((const struct sparc_opcode *)); -static void synthetize_setx PARAMS ((const struct sparc_opcode *)); -static bfd_vma BSR PARAMS ((bfd_vma, int)); -static int cmp_reg_entry PARAMS ((const PTR, const PTR)); -static int parse_keyword_arg PARAMS ((int (*) (const char *), char **, int *)); -static int parse_const_expr_arg PARAMS ((char **, int *)); -static int get_expression PARAMS ((char *str)); - -/* Default architecture. */ -/* ??? The default value should be V8, but sparclite support was added - by making it the default. GCC now passes -Asparclite, so maybe sometime in - the future we can set this to V8. */ -#ifndef DEFAULT_ARCH -#define DEFAULT_ARCH "sparclite" -#endif -static char *default_arch = DEFAULT_ARCH; - -/* Non-zero if the initial values of `max_architecture' and `sparc_arch_size' - have been set. */ -static int default_init_p; - -/* Current architecture. We don't bump up unless necessary. */ -static enum sparc_opcode_arch_val current_architecture = SPARC_OPCODE_ARCH_V6; - -/* The maximum architecture level we can bump up to. - In a 32 bit environment, don't allow bumping up to v9 by default. - The native assembler works this way. The user is required to pass - an explicit argument before we'll create v9 object files. However, if - we don't see any v9 insns, a v8plus object file is not created. */ -static enum sparc_opcode_arch_val max_architecture; - -/* Either 32 or 64, selects file format. */ -static int sparc_arch_size; -/* Initial (default) value, recorded separately in case a user option - changes the value before md_show_usage is called. */ -static int default_arch_size; - -#ifdef OBJ_ELF -/* The currently selected v9 memory model. Currently only used for - ELF. */ -static enum { MM_TSO, MM_PSO, MM_RMO } sparc_memory_model = MM_RMO; -#endif - -static int architecture_requested; -static int warn_on_bump; - -/* If warn_on_bump and the needed architecture is higher than this - architecture, issue a warning. */ -static enum sparc_opcode_arch_val warn_after_architecture; - -/* Non-zero if as should generate error if an undeclared g[23] register - has been used in -64. */ -static int no_undeclared_regs; - -/* Non-zero if we are generating PIC code. */ -int sparc_pic_code; - -/* Non-zero if we should give an error when misaligned data is seen. */ -static int enforce_aligned_data; - -extern int target_big_endian; - -static int target_little_endian_data; - -/* Symbols for global registers on v9. */ -static symbolS *globals[8]; - -/* V9 and 86x have big and little endian data, but instructions are always big - endian. The sparclet has bi-endian support but both data and insns have - the same endianness. Global `target_big_endian' is used for data. - The following macro is used for instructions. */ -#ifndef INSN_BIG_ENDIAN -#define INSN_BIG_ENDIAN (target_big_endian \ - || default_arch_type == sparc86x \ - || SPARC_OPCODE_ARCH_V9_P (max_architecture)) -#endif - -/* handle of the OPCODE hash table */ -static struct hash_control *op_hash; - -static int log2 PARAMS ((int)); -static void s_data1 PARAMS ((void)); -static void s_seg PARAMS ((int)); -static void s_proc PARAMS ((int)); -static void s_reserve PARAMS ((int)); -static void s_common PARAMS ((int)); -static void s_empty PARAMS ((int)); -static void s_uacons PARAMS ((int)); -static void s_ncons PARAMS ((int)); -static void s_register PARAMS ((int)); - -const pseudo_typeS md_pseudo_table[] = -{ - {"align", s_align_bytes, 0}, /* Defaulting is invalid (0) */ - {"common", s_common, 0}, - {"empty", s_empty, 0}, - {"global", s_globl, 0}, - {"half", cons, 2}, - {"nword", s_ncons, 0}, - {"optim", s_ignore, 0}, - {"proc", s_proc, 0}, - {"reserve", s_reserve, 0}, - {"seg", s_seg, 0}, - {"skip", s_space, 0}, - {"word", cons, 4}, - {"xword", cons, 8}, - {"uahalf", s_uacons, 2}, - {"uaword", s_uacons, 4}, - {"uaxword", s_uacons, 8}, -#ifdef OBJ_ELF - /* these are specific to sparc/svr4 */ - {"2byte", s_uacons, 2}, - {"4byte", s_uacons, 4}, - {"8byte", s_uacons, 8}, - {"register", s_register, 0}, -#endif - {NULL, 0, 0}, -}; - -const int md_reloc_size = 12; /* Size of relocation record */ - -/* This array holds the chars that always start a comment. If the - pre-processor is disabled, these aren't very useful */ -const char comment_chars[] = "!"; /* JF removed '|' from comment_chars */ - -/* This array holds the chars that only start a comment at the beginning of - a line. If the line seems to have the form '# 123 filename' - .line and .file directives will appear in the pre-processed output */ -/* Note that input_file.c hand checks for '#' at the beginning of the - first line of the input file. This is because the compiler outputs - #NO_APP at the beginning of its output. */ -/* Also note that comments started like this one will always - work if '/' isn't otherwise defined. */ -const char line_comment_chars[] = "#"; - -const char line_separator_chars[] = ""; - -/* Chars that can be used to separate mant from exp in floating point nums */ -const char EXP_CHARS[] = "eE"; - -/* Chars that mean this number is a floating point constant */ -/* As in 0f12.456 */ -/* or 0d1.2345e12 */ -const char FLT_CHARS[] = "rRsSfFdDxXpP"; - -/* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be - changed in read.c. Ideally it shouldn't have to know about it at all, - but nothing is ideal around here. */ - -#define isoctal(c) ((unsigned)((c) - '0') < '8') - -struct sparc_it - { - char *error; - unsigned long opcode; - struct nlist *nlistp; - expressionS exp; - expressionS exp2; - int pcrel; - bfd_reloc_code_real_type reloc; - }; - -struct sparc_it the_insn, set_insn; - -static void output_insn - PARAMS ((const struct sparc_opcode *, struct sparc_it *)); - -/* Table of arguments to -A. - The sparc_opcode_arch table in sparc-opc.c is insufficient and incorrect - for this use. That table is for opcodes only. This table is for opcodes - and file formats. */ - -enum sparc_arch_types {v6, v7, v8, sparclet, sparclite, sparc86x, v8plus, - v8plusa, v9, v9a, v9_64}; - -static struct sparc_arch { - char *name; - char *opcode_arch; - enum sparc_arch_types arch_type; - /* Default word size, as specified during configuration. - A value of zero means can't be used to specify default architecture. */ - int default_arch_size; - /* Allowable arg to -A? */ - int user_option_p; -} sparc_arch_table[] = { - { "v6", "v6", v6, 0, 1 }, - { "v7", "v7", v7, 0, 1 }, - { "v8", "v8", v8, 32, 1 }, - { "sparclet", "sparclet", sparclet, 32, 1 }, - { "sparclite", "sparclite", sparclite, 32, 1 }, - { "sparc86x", "sparclite", sparc86x, 32, 1 }, - { "v8plus", "v9", v9, 0, 1 }, - { "v8plusa", "v9a", v9, 0, 1 }, - { "v9", "v9", v9, 0, 1 }, - { "v9a", "v9a", v9, 0, 1 }, - /* This exists to allow configure.in/Makefile.in to pass one - value to specify both the default machine and default word size. */ - { "v9-64", "v9", v9, 64, 0 }, - { NULL, NULL, v8, 0, 0 } -}; - -/* Variant of default_arch */ -static enum sparc_arch_types default_arch_type; - -static struct sparc_arch * -lookup_arch (name) - char *name; -{ - struct sparc_arch *sa; - - for (sa = &sparc_arch_table[0]; sa->name != NULL; sa++) - if (strcmp (sa->name, name) == 0) - break; - if (sa->name == NULL) - return NULL; - return sa; -} - -/* Initialize the default opcode arch and word size from the default - architecture name. */ - -static void -init_default_arch () -{ - struct sparc_arch *sa = lookup_arch (default_arch); - - if (sa == NULL - || sa->default_arch_size == 0) - as_fatal (_("Invalid default architecture, broken assembler.")); - - max_architecture = sparc_opcode_lookup_arch (sa->opcode_arch); - if (max_architecture == SPARC_OPCODE_ARCH_BAD) - as_fatal (_("Bad opcode table, broken assembler.")); - default_arch_size = sparc_arch_size = sa->default_arch_size; - default_init_p = 1; - default_arch_type = sa->arch_type; -} - -/* Called by TARGET_FORMAT. */ - -const char * -sparc_target_format () -{ - /* We don't get a chance to initialize anything before we're called, - so handle that now. */ - if (! default_init_p) - init_default_arch (); - -#ifdef OBJ_AOUT -#ifdef TE_NetBSD - return "a.out-sparc-netbsd"; -#else -#ifdef TE_SPARCAOUT - if (target_big_endian) - return "a.out-sunos-big"; - else if (default_arch_type == sparc86x && target_little_endian_data) - return "a.out-sunos-big"; - else return "a.out-sparc-little"; -#else - return "a.out-sunos-big"; -#endif -#endif -#endif - -#ifdef OBJ_BOUT - return "b.out.big"; -#endif - -#ifdef OBJ_COFF -#ifdef TE_LYNX - return "coff-sparc-lynx"; -#else - return "coff-sparc"; -#endif -#endif - -#ifdef OBJ_ELF - return sparc_arch_size == 64 ? "elf64-sparc" : "elf32-sparc"; -#endif - - abort (); -} - -/* - * md_parse_option - * Invocation line includes a switch not recognized by the base assembler. - * See if it's a processor-specific option. These are: - * - * -bump - * Warn on architecture bumps. See also -A. - * - * -Av6, -Av7, -Av8, -Asparclite, -Asparclet - * Standard 32 bit architectures. - * -Av8plus, -Av8plusa - * Sparc64 in a 32 bit world. - * -Av9, -Av9a - * Sparc64 in either a 32 or 64 bit world (-32/-64 says which). - * This used to only mean 64 bits, but properly specifying it - * complicated gcc's ASM_SPECs, so now opcode selection is - * specified orthogonally to word size (except when specifying - * the default, but that is an internal implementation detail). - * -xarch=v8plus, -xarch=v8plusa - * Same as -Av8plus{,a}, for compatibility with Sun's assembler. - * - * Select the architecture and possibly the file format. - * Instructions or features not supported by the selected - * architecture cause fatal errors. - * - * The default is to start at v6, and bump the architecture up - * whenever an instruction is seen at a higher level. In 32 bit - * environments, v9 is not bumped up to, the user must pass - * -Av8plus{,a}. - * - * If -bump is specified, a warning is printing when bumping to - * higher levels. - * - * If an architecture is specified, all instructions must match - * that architecture. Any higher level instructions are flagged - * as errors. Note that in the 32 bit environment specifying - * -Av8plus does not automatically create a v8plus object file, a - * v9 insn must be seen. - * - * If both an architecture and -bump are specified, the - * architecture starts at the specified level, but bumps are - * warnings. Note that we can't set `current_architecture' to - * the requested level in this case: in the 32 bit environment, - * we still must avoid creating v8plus object files unless v9 - * insns are seen. - * - * Note: - * Bumping between incompatible architectures is always an - * error. For example, from sparclite to v9. - */ - -#ifdef OBJ_ELF -CONST char *md_shortopts = "A:K:VQ:sq"; -#else -#ifdef OBJ_AOUT -CONST char *md_shortopts = "A:k"; -#else -CONST char *md_shortopts = "A:"; -#endif -#endif -struct option md_longopts[] = { -#define OPTION_BUMP (OPTION_MD_BASE) - {"bump", no_argument, NULL, OPTION_BUMP}, -#define OPTION_SPARC (OPTION_MD_BASE + 1) - {"sparc", no_argument, NULL, OPTION_SPARC}, -#define OPTION_XARCH (OPTION_MD_BASE + 2) - {"xarch", required_argument, NULL, OPTION_XARCH}, -#ifdef OBJ_ELF -#define OPTION_32 (OPTION_MD_BASE + 3) - {"32", no_argument, NULL, OPTION_32}, -#define OPTION_64 (OPTION_MD_BASE + 4) - {"64", no_argument, NULL, OPTION_64}, -#define OPTION_TSO (OPTION_MD_BASE + 5) - {"TSO", no_argument, NULL, OPTION_TSO}, -#define OPTION_PSO (OPTION_MD_BASE + 6) - {"PSO", no_argument, NULL, OPTION_PSO}, -#define OPTION_RMO (OPTION_MD_BASE + 7) - {"RMO", no_argument, NULL, OPTION_RMO}, -#endif -#ifdef SPARC_BIENDIAN -#define OPTION_LITTLE_ENDIAN (OPTION_MD_BASE + 8) - {"EL", no_argument, NULL, OPTION_LITTLE_ENDIAN}, -#define OPTION_BIG_ENDIAN (OPTION_MD_BASE + 9) - {"EB", no_argument, NULL, OPTION_BIG_ENDIAN}, -#endif -#define OPTION_ENFORCE_ALIGNED_DATA (OPTION_MD_BASE + 10) - {"enforce-aligned-data", no_argument, NULL, OPTION_ENFORCE_ALIGNED_DATA}, -#define OPTION_LITTLE_ENDIAN_DATA (OPTION_MD_BASE + 11) - {"little-endian-data", no_argument, NULL, OPTION_LITTLE_ENDIAN_DATA}, -#ifdef OBJ_ELF -#define OPTION_NO_UNDECLARED_REGS (OPTION_MD_BASE + 12) - {"no-undeclared-regs", no_argument, NULL, OPTION_NO_UNDECLARED_REGS}, -#define OPTION_UNDECLARED_REGS (OPTION_MD_BASE + 13) - {"undeclared-regs", no_argument, NULL, OPTION_UNDECLARED_REGS}, -#endif - {NULL, no_argument, NULL, 0} -}; -size_t md_longopts_size = sizeof(md_longopts); - -int -md_parse_option (c, arg) - int c; - char *arg; -{ - /* We don't get a chance to initialize anything before we're called, - so handle that now. */ - if (! default_init_p) - init_default_arch (); - - switch (c) - { - case OPTION_BUMP: - warn_on_bump = 1; - warn_after_architecture = SPARC_OPCODE_ARCH_V6; - break; - - case OPTION_XARCH: - /* This is for compatibility with Sun's assembler. */ - if (strcmp (arg, "v8plus") != 0 - && strcmp (arg, "v8plusa") != 0) - { - as_bad (_("invalid architecture -xarch=%s"), arg); - return 0; - } - - /* fall through */ - - case 'A': - { - struct sparc_arch *sa; - enum sparc_opcode_arch_val opcode_arch; - - sa = lookup_arch (arg); - if (sa == NULL - || ! sa->user_option_p) - { - as_bad (_("invalid architecture -A%s"), arg); - return 0; - } - - opcode_arch = sparc_opcode_lookup_arch (sa->opcode_arch); - if (opcode_arch == SPARC_OPCODE_ARCH_BAD) - as_fatal (_("Bad opcode table, broken assembler.")); - - max_architecture = opcode_arch; - architecture_requested = 1; - } - break; - - case OPTION_SPARC: - /* Ignore -sparc, used by SunOS make default .s.o rule. */ - break; - - case OPTION_ENFORCE_ALIGNED_DATA: - enforce_aligned_data = 1; - break; - -#ifdef SPARC_BIENDIAN - case OPTION_LITTLE_ENDIAN: - target_big_endian = 0; - if (default_arch_type != sparclet) - as_fatal ("This target does not support -EL"); - break; - case OPTION_LITTLE_ENDIAN_DATA: - target_little_endian_data = 1; - target_big_endian = 0; - if (default_arch_type != sparc86x - && default_arch_type != v9) - as_fatal ("This target does not support --little-endian-data"); - break; - case OPTION_BIG_ENDIAN: - target_big_endian = 1; - break; -#endif - -#ifdef OBJ_AOUT - case 'k': - sparc_pic_code = 1; - break; -#endif - -#ifdef OBJ_ELF - case OPTION_32: - case OPTION_64: - { - const char **list, **l; - - sparc_arch_size = c == OPTION_32 ? 32 : 64; - list = bfd_target_list (); - for (l = list; *l != NULL; l++) - { - if (sparc_arch_size == 32) - { - if (strcmp (*l, "elf32-sparc") == 0) - break; - } - else - { - if (strcmp (*l, "elf64-sparc") == 0) - break; - } - } - if (*l == NULL) - as_fatal (_("No compiled in support for %d bit object file format"), - sparc_arch_size); - free (list); - } - break; - - case OPTION_TSO: - sparc_memory_model = MM_TSO; - break; - - case OPTION_PSO: - sparc_memory_model = MM_PSO; - break; - - case OPTION_RMO: - sparc_memory_model = MM_RMO; - break; - - case 'V': - print_version_id (); - break; - - case 'Q': - /* Qy - do emit .comment - Qn - do not emit .comment */ - break; - - case 's': - /* use .stab instead of .stab.excl */ - break; - - case 'q': - /* quick -- native assembler does fewer checks */ - break; - - case 'K': - if (strcmp (arg, "PIC") != 0) - as_warn (_("Unrecognized option following -K")); - else - sparc_pic_code = 1; - break; - - case OPTION_NO_UNDECLARED_REGS: - no_undeclared_regs = 1; - break; - - case OPTION_UNDECLARED_REGS: - no_undeclared_regs = 0; - break; -#endif - - default: - return 0; - } - - return 1; -} - -void -md_show_usage (stream) - FILE *stream; -{ - const struct sparc_arch *arch; - - /* We don't get a chance to initialize anything before we're called, - so handle that now. */ - if (! default_init_p) - init_default_arch (); - - fprintf(stream, _("SPARC options:\n")); - for (arch = &sparc_arch_table[0]; arch->name; arch++) - { - if (arch != &sparc_arch_table[0]) - fprintf (stream, " | "); - if (arch->user_option_p) - fprintf (stream, "-A%s", arch->name); - } - fprintf (stream, _("\n-xarch=v8plus | -xarch=v8plusa\n")); - fprintf (stream, _("\ - specify variant of SPARC architecture\n\ --bump warn when assembler switches architectures\n\ --sparc ignored\n\ ---enforce-aligned-data force .long, etc., to be aligned correctly\n")); -#ifdef OBJ_AOUT - fprintf (stream, _("\ --k generate PIC\n")); -#endif -#ifdef OBJ_ELF - fprintf (stream, _("\ --32 create 32 bit object file\n\ --64 create 64 bit object file\n")); - fprintf (stream, _("\ - [default is %d]\n"), default_arch_size); - fprintf (stream, _("\ --TSO use Total Store Ordering\n\ --PSO use Partial Store Ordering\n\ --RMO use Relaxed Memory Ordering\n")); - fprintf (stream, _("\ - [default is %s]\n"), (default_arch_size == 64) ? "RMO" : "TSO"); - fprintf (stream, _("\ --KPIC generate PIC\n\ --V print assembler version number\n\ --undeclared-regs ignore application global register usage without\n\ - appropriate .register directive (default)\n\ --no-undeclared-regs force error on application global register usage\n\ - without appropriate .register directive\n\ --q ignored\n\ --Qy, -Qn ignored\n\ --s ignored\n")); -#endif -#ifdef SPARC_BIENDIAN - fprintf (stream, _("\ --EL generate code for a little endian machine\n\ --EB generate code for a big endian machine\n\ ---little-endian-data generate code for a machine having big endian\n\ - instructions and little endian data.\n")); -#endif -} - -/* native operand size opcode translation */ -struct - { - char *name; - char *name32; - char *name64; - } native_op_table[] = -{ - {"ldn", "ld", "ldx"}, - {"ldna", "lda", "ldxa"}, - {"stn", "st", "stx"}, - {"stna", "sta", "stxa"}, - {"slln", "sll", "sllx"}, - {"srln", "srl", "srlx"}, - {"sran", "sra", "srax"}, - {"casn", "cas", "casx"}, - {"casna", "casa", "casxa"}, - {"clrn", "clr", "clrx"}, - {NULL, NULL, NULL}, -}; - -/* sparc64 priviledged registers */ - -struct priv_reg_entry - { - char *name; - int regnum; - }; - -struct priv_reg_entry priv_reg_table[] = -{ - {"tpc", 0}, - {"tnpc", 1}, - {"tstate", 2}, - {"tt", 3}, - {"tick", 4}, - {"tba", 5}, - {"pstate", 6}, - {"tl", 7}, - {"pil", 8}, - {"cwp", 9}, - {"cansave", 10}, - {"canrestore", 11}, - {"cleanwin", 12}, - {"otherwin", 13}, - {"wstate", 14}, - {"fq", 15}, - {"ver", 31}, - {"", -1}, /* end marker */ -}; - -/* v9a specific asrs */ - -struct priv_reg_entry v9a_asr_table[] = -{ - {"tick_cmpr", 23}, - {"softint", 22}, - {"set_softint", 20}, - {"pic", 17}, - {"pcr", 16}, - {"gsr", 19}, - {"dcr", 18}, - {"clear_softint", 21}, - {"", -1}, /* end marker */ -}; - -static int -cmp_reg_entry (parg, qarg) - const PTR parg; - const PTR qarg; -{ - const struct priv_reg_entry *p = (const struct priv_reg_entry *) parg; - const struct priv_reg_entry *q = (const struct priv_reg_entry *) qarg; - - return strcmp (q->name, p->name); -} - -/* This function is called once, at assembler startup time. It should - set up all the tables, etc. that the MD part of the assembler will need. */ - -void -md_begin () -{ - register const char *retval = NULL; - int lose = 0; - register unsigned int i = 0; - - /* We don't get a chance to initialize anything before md_parse_option - is called, and it may not be called, so handle default initialization - now if not already done. */ - if (! default_init_p) - init_default_arch (); - - op_hash = hash_new (); - - while (i < (unsigned int) sparc_num_opcodes) - { - const char *name = sparc_opcodes[i].name; - retval = hash_insert (op_hash, name, (PTR) &sparc_opcodes[i]); - if (retval != NULL) - { - as_bad (_("Internal error: can't hash `%s': %s\n"), - sparc_opcodes[i].name, retval); - lose = 1; - } - do - { - if (sparc_opcodes[i].match & sparc_opcodes[i].lose) - { - as_bad (_("Internal error: losing opcode: `%s' \"%s\"\n"), - sparc_opcodes[i].name, sparc_opcodes[i].args); - lose = 1; - } - ++i; - } - while (i < (unsigned int) sparc_num_opcodes - && !strcmp (sparc_opcodes[i].name, name)); - } - - for (i = 0; native_op_table[i].name; i++) - { - const struct sparc_opcode *insn; - char *name = sparc_arch_size == 32 ? native_op_table[i].name32 : - native_op_table[i].name64; - insn = (struct sparc_opcode *)hash_find (op_hash, name); - if (insn == NULL) - { - as_bad (_("Internal error: can't find opcode `%s' for `%s'\n"), - name, native_op_table[i].name); - lose = 1; - } - else - { - retval = hash_insert (op_hash, native_op_table[i].name, (PTR) insn); - if (retval != NULL) - { - as_bad (_("Internal error: can't hash `%s': %s\n"), - sparc_opcodes[i].name, retval); - lose = 1; - } - } - } - - if (lose) - as_fatal (_("Broken assembler. No assembly attempted.")); - - qsort (priv_reg_table, sizeof (priv_reg_table) / sizeof (priv_reg_table[0]), - sizeof (priv_reg_table[0]), cmp_reg_entry); - - /* If -bump, record the architecture level at which we start issuing - warnings. The behaviour is different depending upon whether an - architecture was explicitly specified. If it wasn't, we issue warnings - for all upwards bumps. If it was, we don't start issuing warnings until - we need to bump beyond the requested architecture or when we bump between - conflicting architectures. */ - - if (warn_on_bump - && architecture_requested) - { - /* `max_architecture' records the requested architecture. - Issue warnings if we go above it. */ - warn_after_architecture = max_architecture; - - /* Find the highest architecture level that doesn't conflict with - the requested one. */ - for (max_architecture = SPARC_OPCODE_ARCH_MAX; - max_architecture > warn_after_architecture; - --max_architecture) - if (! SPARC_OPCODE_CONFLICT_P (max_architecture, - warn_after_architecture)) - break; - } -} - -/* Called after all assembly has been done. */ - -void -sparc_md_end () -{ - if (sparc_arch_size == 64) - { - if (current_architecture == SPARC_OPCODE_ARCH_V9A) - bfd_set_arch_mach (stdoutput, bfd_arch_sparc, bfd_mach_sparc_v9a); - else - bfd_set_arch_mach (stdoutput, bfd_arch_sparc, bfd_mach_sparc_v9); - } - else - { - if (current_architecture == SPARC_OPCODE_ARCH_V9) - bfd_set_arch_mach (stdoutput, bfd_arch_sparc, bfd_mach_sparc_v8plus); - else if (current_architecture == SPARC_OPCODE_ARCH_V9A) - bfd_set_arch_mach (stdoutput, bfd_arch_sparc, bfd_mach_sparc_v8plusa); - else if (current_architecture == SPARC_OPCODE_ARCH_SPARCLET) - bfd_set_arch_mach (stdoutput, bfd_arch_sparc, bfd_mach_sparc_sparclet); - else if (default_arch_type == sparc86x && target_little_endian_data) - bfd_set_arch_mach (stdoutput, bfd_arch_sparc, bfd_mach_sparc_sparclite_le); - else - { - /* The sparclite is treated like a normal sparc. Perhaps it shouldn't - be but for now it is (since that's the way it's always been - treated). */ - bfd_set_arch_mach (stdoutput, bfd_arch_sparc, bfd_mach_sparc); - } - } -} - -/* Return non-zero if VAL is in the range -(MAX+1) to MAX. */ - -static INLINE int -in_signed_range (val, max) - bfd_signed_vma val, max; -{ - if (max <= 0) - abort (); - /* Sign-extend the value from the architecture word size, so that - 0xffffffff is always considered -1 on sparc32. */ - if (sparc_arch_size == 32) - { - bfd_signed_vma sign = (bfd_signed_vma)1 << 31; - val = ((val & 0xffffffff) ^ sign) - sign; - } - if (val > max) - return 0; - if (val < ~max) - return 0; - return 1; -} - -/* Return non-zero if VAL is in the range 0 to MAX. */ - -static INLINE int -in_unsigned_range (val, max) - bfd_vma val, max; -{ - if (val > max) - return 0; - return 1; -} - -/* Return non-zero if VAL is in the range -(MAX/2+1) to MAX. - (e.g. -15 to +31). */ - -static INLINE int -in_bitfield_range (val, max) - bfd_signed_vma val, max; -{ - if (max <= 0) - abort (); - if (val > max) - return 0; - if (val < ~(max >> 1)) - return 0; - return 1; -} - -static int -sparc_ffs (mask) - unsigned int mask; -{ - int i; - - if (mask == 0) - return -1; - - for (i = 0; (mask & 1) == 0; ++i) - mask >>= 1; - return i; -} - -/* Implement big shift right. */ -static bfd_vma -BSR (val, amount) - bfd_vma val; - int amount; -{ - if (sizeof (bfd_vma) <= 4 && amount >= 32) - as_fatal (_("Support for 64-bit arithmetic not compiled in.")); - return val >> amount; -} - -/* For communication between sparc_ip and get_expression. */ -static char *expr_end; - -/* Values for `special_case'. - Instructions that require wierd handling because they're longer than - 4 bytes. */ -#define SPECIAL_CASE_NONE 0 -#define SPECIAL_CASE_SET 1 -#define SPECIAL_CASE_SETSW 2 -#define SPECIAL_CASE_SETX 3 -/* FIXME: sparc-opc.c doesn't have necessary "S" trigger to enable this. */ -#define SPECIAL_CASE_FDIV 4 - -/* Bit masks of various insns. */ -#define NOP_INSN 0x01000000 -#define OR_INSN 0x80100000 -#define XOR_INSN 0x80180000 -#define FMOVS_INSN 0x81A00020 -#define SETHI_INSN 0x01000000 -#define SLLX_INSN 0x81281000 -#define SRA_INSN 0x81380000 - -/* The last instruction to be assembled. */ -static const struct sparc_opcode *last_insn; -/* The assembled opcode of `last_insn'. */ -static unsigned long last_opcode; - -/* Handle the set and setuw synthetic instructions. */ -static void -synthetize_setuw (insn) - const struct sparc_opcode *insn; -{ - int need_hi22_p = 0; - int rd = (the_insn.opcode & RD (~0)) >> 25; - - if (the_insn.exp.X_op == O_constant) - { - if (SPARC_OPCODE_ARCH_V9_P (max_architecture)) - { - if (sizeof(offsetT) > 4 - && (the_insn.exp.X_add_number < 0 - || the_insn.exp.X_add_number > (offsetT) 0xffffffff)) - as_warn (_("set: number not in 0..4294967295 range")); - } - else - { - if (sizeof(offsetT) > 4 - && (the_insn.exp.X_add_number < -(offsetT) 0x80000000 - || the_insn.exp.X_add_number > (offsetT) 0xffffffff)) - as_warn (_("set: number not in -2147483648..4294967295 range")); - the_insn.exp.X_add_number = (int)the_insn.exp.X_add_number; - } - } - - /* See if operand is absolute and small; skip sethi if so. */ - if (the_insn.exp.X_op != O_constant - || the_insn.exp.X_add_number >= (1 << 12) - || the_insn.exp.X_add_number < -(1 << 12)) - { - the_insn.opcode = (SETHI_INSN | RD (rd) - | ((the_insn.exp.X_add_number >> 10) - & (the_insn.exp.X_op == O_constant ? 0x3fffff : 0))); - the_insn.reloc = (the_insn.exp.X_op != O_constant - ? BFD_RELOC_HI22 - : BFD_RELOC_NONE); - output_insn (insn, &the_insn); - need_hi22_p = 1; - } - - /* See if operand has no low-order bits; skip OR if so. */ - if (the_insn.exp.X_op != O_constant - || (need_hi22_p && (the_insn.exp.X_add_number & 0x3FF) != 0) - || ! need_hi22_p) - { - the_insn.opcode = (OR_INSN | (need_hi22_p ? RS1 (rd) : 0) - | RD (rd) | IMMED - | (the_insn.exp.X_add_number - & (the_insn.exp.X_op != O_constant ? 0 : - need_hi22_p ? 0x3ff : 0x1fff))); - the_insn.reloc = (the_insn.exp.X_op != O_constant - ? BFD_RELOC_LO10 - : BFD_RELOC_NONE); - output_insn (insn, &the_insn); - } -} - -/* Handle the setsw synthetic instruction. */ -static void -synthetize_setsw (insn) - const struct sparc_opcode *insn; -{ - int low32, rd, opc; - - rd = (the_insn.opcode & RD (~0)) >> 25; - - if (the_insn.exp.X_op != O_constant) - { - synthetize_setuw (insn); - - /* Need to sign extend it. */ - the_insn.opcode = (SRA_INSN | RS1 (rd) | RD (rd)); - the_insn.reloc = BFD_RELOC_NONE; - output_insn (insn, &the_insn); - return; - } - - if (sizeof(offsetT) > 4 - && (the_insn.exp.X_add_number < -(offsetT) 0x80000000 - || the_insn.exp.X_add_number > (offsetT) 0xffffffff)) - as_warn (_("setsw: number not in -2147483648..4294967295 range")); - - low32 = the_insn.exp.X_add_number; - - if (low32 >= 0) - { - synthetize_setuw (insn); - return; - } - - opc = OR_INSN; - - the_insn.reloc = BFD_RELOC_NONE; - /* See if operand is absolute and small; skip sethi if so. */ - if (low32 < -(1 << 12)) - { - the_insn.opcode = (SETHI_INSN | RD (rd) - | (((~the_insn.exp.X_add_number) >> 10) & 0x3fffff)); - output_insn (insn, &the_insn); - low32 = 0x1c00 | (low32 & 0x3ff); - opc = RS1 (rd) | XOR_INSN; - } - - the_insn.opcode = (opc | RD (rd) | IMMED - | (low32 & 0x1fff)); - output_insn (insn, &the_insn); -} - -/* Handle the setsw synthetic instruction. */ -static void -synthetize_setx (insn) - const struct sparc_opcode *insn; -{ - int upper32, lower32; - int tmpreg = (the_insn.opcode & RS1 (~0)) >> 14; - int dstreg = (the_insn.opcode & RD (~0)) >> 25; - int upper_dstreg; - int need_hh22_p = 0, need_hm10_p = 0, need_hi22_p = 0, need_lo10_p = 0; - int need_xor10_p = 0; - -#define SIGNEXT32(x) ((((x) & 0xffffffff) ^ 0x80000000) - 0x80000000) - lower32 = SIGNEXT32 (the_insn.exp.X_add_number); - upper32 = SIGNEXT32 (BSR (the_insn.exp.X_add_number, 32)); -#undef SIGNEXT32 - - upper_dstreg = tmpreg; - /* The tmp reg should not be the dst reg. */ - if (tmpreg == dstreg) - as_warn (_("setx: temporary register same as destination register")); - - /* ??? Obviously there are other optimizations we can do - (e.g. sethi+shift for 0x1f0000000) and perhaps we shouldn't be - doing some of these. Later. If you do change things, try to - change all of this to be table driven as well. */ - /* What to output depends on the number if it's constant. - Compute that first, then output what we've decided upon. */ - if (the_insn.exp.X_op != O_constant) - { - if (sparc_arch_size == 32) - { - /* When arch size is 32, we want setx to be equivalent - to setuw for anything but constants. */ - the_insn.exp.X_add_number &= 0xffffffff; - synthetize_setuw (insn); - return; - } - need_hh22_p = need_hm10_p = need_hi22_p = need_lo10_p = 1; - lower32 = 0; upper32 = 0; - } - else - { - /* Reset X_add_number, we've extracted it as upper32/lower32. - Otherwise fixup_segment will complain about not being able to - write an 8 byte number in a 4 byte field. */ - the_insn.exp.X_add_number = 0; - - /* Only need hh22 if `or' insn can't handle constant. */ - if (upper32 < -(1 << 12) || upper32 >= (1 << 12)) - need_hh22_p = 1; - - /* Does bottom part (after sethi) have bits? */ - if ((need_hh22_p && (upper32 & 0x3ff) != 0) - /* No hh22, but does upper32 still have bits we can't set - from lower32? */ - || (! need_hh22_p && upper32 != 0 && upper32 != -1)) - need_hm10_p = 1; - - /* If the lower half is all zero, we build the upper half directly - into the dst reg. */ - if (lower32 != 0 - /* Need lower half if number is zero or 0xffffffff00000000. */ - || (! need_hh22_p && ! need_hm10_p)) - { - /* No need for sethi if `or' insn can handle constant. */ - if (lower32 < -(1 << 12) || lower32 >= (1 << 12) - /* Note that we can't use a negative constant in the `or' - insn unless the upper 32 bits are all ones. */ - || (lower32 < 0 && upper32 != -1) - || (lower32 >= 0 && upper32 == -1)) - need_hi22_p = 1; - - if (need_hi22_p && upper32 == -1) - need_xor10_p = 1; - - /* Does bottom part (after sethi) have bits? */ - else if ((need_hi22_p && (lower32 & 0x3ff) != 0) - /* No sethi. */ - || (! need_hi22_p && (lower32 & 0x1fff) != 0) - /* Need `or' if we didn't set anything else. */ - || (! need_hi22_p && ! need_hh22_p && ! need_hm10_p)) - need_lo10_p = 1; - } - else - /* Output directly to dst reg if lower 32 bits are all zero. */ - upper_dstreg = dstreg; - } - - if (!upper_dstreg && dstreg) - as_warn (_("setx: illegal temporary register g0")); - - if (need_hh22_p) - { - the_insn.opcode = (SETHI_INSN | RD (upper_dstreg) - | ((upper32 >> 10) & 0x3fffff)); - the_insn.reloc = (the_insn.exp.X_op != O_constant - ? BFD_RELOC_SPARC_HH22 : BFD_RELOC_NONE); - output_insn (insn, &the_insn); - } - - if (need_hi22_p) - { - the_insn.opcode = (SETHI_INSN | RD (dstreg) - | (((need_xor10_p ? ~lower32 : lower32) - >> 10) & 0x3fffff)); - the_insn.reloc = (the_insn.exp.X_op != O_constant - ? BFD_RELOC_SPARC_LM22 : BFD_RELOC_NONE); - output_insn (insn, &the_insn); - } - - if (need_hm10_p) - { - the_insn.opcode = (OR_INSN - | (need_hh22_p ? RS1 (upper_dstreg) : 0) - | RD (upper_dstreg) - | IMMED - | (upper32 & (need_hh22_p ? 0x3ff : 0x1fff))); - the_insn.reloc = (the_insn.exp.X_op != O_constant - ? BFD_RELOC_SPARC_HM10 : BFD_RELOC_NONE); - output_insn (insn, &the_insn); - } - - if (need_lo10_p) - { - /* FIXME: One nice optimization to do here is to OR the low part - with the highpart if hi22 isn't needed and the low part is - positive. */ - the_insn.opcode = (OR_INSN | (need_hi22_p ? RS1 (dstreg) : 0) - | RD (dstreg) - | IMMED - | (lower32 & (need_hi22_p ? 0x3ff : 0x1fff))); - the_insn.reloc = (the_insn.exp.X_op != O_constant - ? BFD_RELOC_LO10 : BFD_RELOC_NONE); - output_insn (insn, &the_insn); - } - - /* If we needed to build the upper part, shift it into place. */ - if (need_hh22_p || need_hm10_p) - { - the_insn.opcode = (SLLX_INSN | RS1 (upper_dstreg) | RD (upper_dstreg) - | IMMED | 32); - the_insn.reloc = BFD_RELOC_NONE; - output_insn (insn, &the_insn); - } - - /* To get -1 in upper32, we do sethi %hi(~x), r; xor r, -0x400 | x, r. */ - if (need_xor10_p) - { - the_insn.opcode = (XOR_INSN | RS1 (dstreg) | RD (dstreg) | IMMED - | 0x1c00 | (lower32 & 0x3ff)); - the_insn.reloc = BFD_RELOC_NONE; - output_insn (insn, &the_insn); - } - - /* If we needed to build both upper and lower parts, OR them together. */ - else if ((need_hh22_p || need_hm10_p) && (need_hi22_p || need_lo10_p)) - { - the_insn.opcode = (OR_INSN | RS1 (dstreg) | RS2 (upper_dstreg) - | RD (dstreg)); - the_insn.reloc = BFD_RELOC_NONE; - output_insn (insn, &the_insn); - } -} - -/* Main entry point to assemble one instruction. */ - -void -md_assemble (str) - char *str; -{ - const struct sparc_opcode *insn; - int special_case; - - know (str); - special_case = sparc_ip (str, &insn); - - /* We warn about attempts to put a floating point branch in a delay slot, - unless the delay slot has been annulled. */ - if (insn != NULL - && last_insn != NULL - && (insn->flags & F_FBR) != 0 - && (last_insn->flags & F_DELAYED) != 0 - /* ??? This test isn't completely accurate. We assume anything with - F_{UNBR,CONDBR,FBR} set is annullable. */ - && ((last_insn->flags & (F_UNBR | F_CONDBR | F_FBR)) == 0 - || (last_opcode & ANNUL) == 0)) - as_warn (_("FP branch in delay slot")); - - /* SPARC before v9 requires a nop instruction between a floating - point instruction and a floating point branch. We insert one - automatically, with a warning. */ - if (max_architecture < SPARC_OPCODE_ARCH_V9 - && insn != NULL - && last_insn != NULL - && (insn->flags & F_FBR) != 0 - && (last_insn->flags & F_FLOAT) != 0) - { - struct sparc_it nop_insn; - - nop_insn.opcode = NOP_INSN; - nop_insn.reloc = BFD_RELOC_NONE; - output_insn (insn, &nop_insn); - as_warn (_("FP branch preceded by FP instruction; NOP inserted")); - } - - switch (special_case) - { - case SPECIAL_CASE_NONE: - /* normal insn */ - output_insn (insn, &the_insn); - break; - - case SPECIAL_CASE_SETSW: - synthetize_setsw (insn); - break; - - case SPECIAL_CASE_SET: - synthetize_setuw (insn); - break; - - case SPECIAL_CASE_SETX: - synthetize_setx (insn); - break; - - case SPECIAL_CASE_FDIV: - { - int rd = (the_insn.opcode >> 25) & 0x1f; - - output_insn (insn, &the_insn); - - /* According to information leaked from Sun, the "fdiv" instructions - on early SPARC machines would produce incorrect results sometimes. - The workaround is to add an fmovs of the destination register to - itself just after the instruction. This was true on machines - with Weitek 1165 float chips, such as the Sun-4/260 and /280. */ - assert (the_insn.reloc == BFD_RELOC_NONE); - the_insn.opcode = FMOVS_INSN | rd | RD (rd); - output_insn (insn, &the_insn); - return; - } - - default: - as_fatal (_("failed special case insn sanity check")); - } -} - -/* Subroutine of md_assemble to do the actual parsing. */ - -static int -sparc_ip (str, pinsn) - char *str; - const struct sparc_opcode **pinsn; -{ - char *error_message = ""; - char *s; - const char *args; - char c; - const struct sparc_opcode *insn; - char *argsStart; - unsigned long opcode; - unsigned int mask = 0; - int match = 0; - int comma = 0; - int v9_arg_p; - int special_case = SPECIAL_CASE_NONE; - - s = str; - if (islower ((unsigned char) *s)) - { - do - ++s; - while (islower ((unsigned char) *s) || isdigit ((unsigned char) *s)); - } - - switch (*s) - { - case '\0': - break; - - case ',': - comma = 1; - - /*FALLTHROUGH */ - - case ' ': - *s++ = '\0'; - break; - - default: - as_fatal (_("Unknown opcode: `%s'"), str); - } - insn = (struct sparc_opcode *) hash_find (op_hash, str); - *pinsn = insn; - if (insn == NULL) - { - as_bad (_("Unknown opcode: `%s'"), str); - return special_case; - } - if (comma) - { - *--s = ','; - } - - argsStart = s; - for (;;) - { - opcode = insn->match; - memset (&the_insn, '\0', sizeof (the_insn)); - the_insn.reloc = BFD_RELOC_NONE; - v9_arg_p = 0; - - /* - * Build the opcode, checking as we go to make - * sure that the operands match - */ - for (args = insn->args;; ++args) - { - switch (*args) - { - case 'K': - { - int kmask = 0; - - /* Parse a series of masks. */ - if (*s == '#') - { - while (*s == '#') - { - int mask; - - if (! parse_keyword_arg (sparc_encode_membar, &s, - &mask)) - { - error_message = _(": invalid membar mask name"); - goto error; - } - kmask |= mask; - while (*s == ' ') { ++s; continue; } - if (*s == '|' || *s == '+') - ++s; - while (*s == ' ') { ++s; continue; } - } - } - else - { - if (! parse_const_expr_arg (&s, &kmask)) - { - error_message = _(": invalid membar mask expression"); - goto error; - } - if (kmask < 0 || kmask > 127) - { - error_message = _(": invalid membar mask number"); - goto error; - } - } - - opcode |= MEMBAR (kmask); - continue; - } - - case '*': - { - int fcn = 0; - - /* Parse a prefetch function. */ - if (*s == '#') - { - if (! parse_keyword_arg (sparc_encode_prefetch, &s, &fcn)) - { - error_message = _(": invalid prefetch function name"); - goto error; - } - } - else - { - if (! parse_const_expr_arg (&s, &fcn)) - { - error_message = _(": invalid prefetch function expression"); - goto error; - } - if (fcn < 0 || fcn > 31) - { - error_message = _(": invalid prefetch function number"); - goto error; - } - } - opcode |= RD (fcn); - continue; - } - - case '!': - case '?': - /* Parse a sparc64 privileged register. */ - if (*s == '%') - { - struct priv_reg_entry *p = priv_reg_table; - unsigned int len = 9999999; /* init to make gcc happy */ - - s += 1; - while (p->name[0] > s[0]) - p++; - while (p->name[0] == s[0]) - { - len = strlen (p->name); - if (strncmp (p->name, s, len) == 0) - break; - p++; - } - if (p->name[0] != s[0]) - { - error_message = _(": unrecognizable privileged register"); - goto error; - } - if (*args == '?') - opcode |= (p->regnum << 14); - else - opcode |= (p->regnum << 25); - s += len; - continue; - } - else - { - error_message = _(": unrecognizable privileged register"); - goto error; - } - - case '_': - case '/': - /* Parse a v9a ancillary state register. */ - if (*s == '%') - { - struct priv_reg_entry *p = v9a_asr_table; - unsigned int len = 9999999; /* init to make gcc happy */ - - s += 1; - while (p->name[0] > s[0]) - p++; - while (p->name[0] == s[0]) - { - len = strlen (p->name); - if (strncmp (p->name, s, len) == 0) - break; - p++; - } - if (p->name[0] != s[0]) - { - error_message = _(": unrecognizable v9a ancillary state register"); - goto error; - } - if (*args == '/' && (p->regnum == 20 || p->regnum == 21)) - { - error_message = _(": rd on write only ancillary state register"); - goto error; - } - if (*args == '/') - opcode |= (p->regnum << 14); - else - opcode |= (p->regnum << 25); - s += len; - continue; - } - else - { - error_message = _(": unrecognizable v9a ancillary state register"); - goto error; - } - - case 'M': - case 'm': - if (strncmp (s, "%asr", 4) == 0) - { - s += 4; - - if (isdigit ((unsigned char) *s)) - { - long num = 0; - - while (isdigit ((unsigned char) *s)) - { - num = num * 10 + *s - '0'; - ++s; - } - - if (current_architecture >= SPARC_OPCODE_ARCH_V9) - { - if (num < 16 || 31 < num) - { - error_message = _(": asr number must be between 16 and 31"); - goto error; - } - } - else - { - if (num < 0 || 31 < num) - { - error_message = _(": asr number must be between 0 and 31"); - goto error; - } - } - - opcode |= (*args == 'M' ? RS1 (num) : RD (num)); - continue; - } - else - { - error_message = _(": expecting %asrN"); - goto error; - } - } /* if %asr */ - break; - - case 'I': - the_insn.reloc = BFD_RELOC_SPARC_11; - goto immediate; - - case 'j': - the_insn.reloc = BFD_RELOC_SPARC_10; - goto immediate; - - case 'X': - /* V8 systems don't understand BFD_RELOC_SPARC_5. */ - if (SPARC_OPCODE_ARCH_V9_P (max_architecture)) - the_insn.reloc = BFD_RELOC_SPARC_5; - else - the_insn.reloc = BFD_RELOC_SPARC13; - /* These fields are unsigned, but for upward compatibility, - allow negative values as well. */ - goto immediate; - - case 'Y': - /* V8 systems don't understand BFD_RELOC_SPARC_6. */ - if (SPARC_OPCODE_ARCH_V9_P (max_architecture)) - the_insn.reloc = BFD_RELOC_SPARC_6; - else - the_insn.reloc = BFD_RELOC_SPARC13; - /* These fields are unsigned, but for upward compatibility, - allow negative values as well. */ - goto immediate; - - case 'k': - the_insn.reloc = /* RELOC_WDISP2_14 */ BFD_RELOC_SPARC_WDISP16; - the_insn.pcrel = 1; - goto immediate; - - case 'G': - the_insn.reloc = BFD_RELOC_SPARC_WDISP19; - the_insn.pcrel = 1; - goto immediate; - - case 'N': - if (*s == 'p' && s[1] == 'n') - { - s += 2; - continue; - } - break; - - case 'T': - if (*s == 'p' && s[1] == 't') - { - s += 2; - continue; - } - break; - - case 'z': - if (*s == ' ') - { - ++s; - } - if (strncmp (s, "%icc", 4) == 0) - { - s += 4; - continue; - } - break; - - case 'Z': - if (*s == ' ') - { - ++s; - } - if (strncmp (s, "%xcc", 4) == 0) - { - s += 4; - continue; - } - break; - - case '6': - if (*s == ' ') - { - ++s; - } - if (strncmp (s, "%fcc0", 5) == 0) - { - s += 5; - continue; - } - break; - - case '7': - if (*s == ' ') - { - ++s; - } - if (strncmp (s, "%fcc1", 5) == 0) - { - s += 5; - continue; - } - break; - - case '8': - if (*s == ' ') - { - ++s; - } - if (strncmp (s, "%fcc2", 5) == 0) - { - s += 5; - continue; - } - break; - - case '9': - if (*s == ' ') - { - ++s; - } - if (strncmp (s, "%fcc3", 5) == 0) - { - s += 5; - continue; - } - break; - - case 'P': - if (strncmp (s, "%pc", 3) == 0) - { - s += 3; - continue; - } - break; - - case 'W': - if (strncmp (s, "%tick", 5) == 0) - { - s += 5; - continue; - } - break; - - case '\0': /* end of args */ - if (*s == '\0') - { - match = 1; - } - break; - - case '+': - if (*s == '+') - { - ++s; - continue; - } - if (*s == '-') - { - continue; - } - break; - - case '[': /* these must match exactly */ - case ']': - case ',': - case ' ': - if (*s++ == *args) - continue; - break; - - case '#': /* must be at least one digit */ - if (isdigit ((unsigned char) *s++)) - { - while (isdigit ((unsigned char) *s)) - { - ++s; - } - continue; - } - break; - - case 'C': /* coprocessor state register */ - if (strncmp (s, "%csr", 4) == 0) - { - s += 4; - continue; - } - break; - - case 'b': /* next operand is a coprocessor register */ - case 'c': - case 'D': - if (*s++ == '%' && *s++ == 'c' && isdigit ((unsigned char) *s)) - { - mask = *s++; - if (isdigit ((unsigned char) *s)) - { - mask = 10 * (mask - '0') + (*s++ - '0'); - if (mask >= 32) - { - break; - } - } - else - { - mask -= '0'; - } - switch (*args) - { - - case 'b': - opcode |= mask << 14; - continue; - - case 'c': - opcode |= mask; - continue; - - case 'D': - opcode |= mask << 25; - continue; - } - } - break; - - case 'r': /* next operand must be a register */ - case 'O': - case '1': - case '2': - case 'd': - if (*s++ == '%') - { - switch (c = *s++) - { - - case 'f': /* frame pointer */ - if (*s++ == 'p') - { - mask = 0x1e; - break; - } - goto error; - - case 'g': /* global register */ - c = *s++; - if (isoctal (c)) - { - mask = c - '0'; - break; - } - goto error; - - case 'i': /* in register */ - c = *s++; - if (isoctal (c)) - { - mask = c - '0' + 24; - break; - } - goto error; - - case 'l': /* local register */ - c = *s++; - if (isoctal (c)) - { - mask = (c - '0' + 16); - break; - } - goto error; - - case 'o': /* out register */ - c = *s++; - if (isoctal (c)) - { - mask = (c - '0' + 8); - break; - } - goto error; - - case 's': /* stack pointer */ - if (*s++ == 'p') - { - mask = 0xe; - break; - } - goto error; - - case 'r': /* any register */ - if (!isdigit ((unsigned char) (c = *s++))) - { - goto error; - } - /* FALLTHROUGH */ - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (isdigit ((unsigned char) *s)) - { - if ((c = 10 * (c - '0') + (*s++ - '0')) >= 32) - { - goto error; - } - } - else - { - c -= '0'; - } - mask = c; - break; - - default: - goto error; - } - - if ((mask & ~1) == 2 && sparc_arch_size == 64 - && no_undeclared_regs && ! globals [mask]) - as_bad (_("detected global register use not covered by .register pseudo-op")); - - /* Got the register, now figure out where - it goes in the opcode. */ - switch (*args) - { - case '1': - opcode |= mask << 14; - continue; - - case '2': - opcode |= mask; - continue; - - case 'd': - opcode |= mask << 25; - continue; - - case 'r': - opcode |= (mask << 25) | (mask << 14); - continue; - - case 'O': - opcode |= (mask << 25) | (mask << 0); - continue; - } - } - break; - - case 'e': /* next operand is a floating point register */ - case 'v': - case 'V': - - case 'f': - case 'B': - case 'R': - - case 'g': - case 'H': - case 'J': - { - char format; - - if (*s++ == '%' - && ((format = *s) == 'f') - && isdigit ((unsigned char) *++s)) - { - for (mask = 0; isdigit ((unsigned char) *s); ++s) - { - mask = 10 * mask + (*s - '0'); - } /* read the number */ - - if ((*args == 'v' - || *args == 'B' - || *args == 'H') - && (mask & 1)) - { - break; - } /* register must be even numbered */ - - if ((*args == 'V' - || *args == 'R' - || *args == 'J') - && (mask & 3)) - { - break; - } /* register must be multiple of 4 */ - - if (mask >= 64) - { - if (SPARC_OPCODE_ARCH_V9_P (max_architecture)) - error_message = _(": There are only 64 f registers; [0-63]"); - else - error_message = _(": There are only 32 f registers; [0-31]"); - goto error; - } /* on error */ - else if (mask >= 32) - { - if (SPARC_OPCODE_ARCH_V9_P (max_architecture)) - { - v9_arg_p = 1; - mask -= 31; /* wrap high bit */ - } - else - { - error_message = _(": There are only 32 f registers; [0-31]"); - goto error; - } - } - } - else - { - break; - } /* if not an 'f' register. */ - - switch (*args) - { - case 'v': - case 'V': - case 'e': - opcode |= RS1 (mask); - continue; - - - case 'f': - case 'B': - case 'R': - opcode |= RS2 (mask); - continue; - - case 'g': - case 'H': - case 'J': - opcode |= RD (mask); - continue; - } /* pack it in. */ - - know (0); - break; - } /* float arg */ - - case 'F': - if (strncmp (s, "%fsr", 4) == 0) - { - s += 4; - continue; - } - break; - - case '0': /* 64 bit immediate (set, setsw, setx insn) */ - the_insn.reloc = BFD_RELOC_NONE; /* reloc handled elsewhere */ - goto immediate; - - case 'l': /* 22 bit PC relative immediate */ - the_insn.reloc = BFD_RELOC_SPARC_WDISP22; - the_insn.pcrel = 1; - goto immediate; - - case 'L': /* 30 bit immediate */ - the_insn.reloc = BFD_RELOC_32_PCREL_S2; - the_insn.pcrel = 1; - goto immediate; - - case 'h': - case 'n': /* 22 bit immediate */ - the_insn.reloc = BFD_RELOC_SPARC22; - goto immediate; - - case 'i': /* 13 bit immediate */ - the_insn.reloc = BFD_RELOC_SPARC13; - - /* fallthrough */ - - immediate: - if (*s == ' ') - s++; - - { - char *s1; - char *op_arg = NULL; - expressionS op_exp; - bfd_reloc_code_real_type old_reloc = the_insn.reloc; - - /* Check for %hi, etc. */ - if (*s == '%') - { - static const struct ops { - /* The name as it appears in assembler. */ - char *name; - /* strlen (name), precomputed for speed */ - int len; - /* The reloc this pseudo-op translates to. */ - int reloc; - /* Non-zero if for v9 only. */ - int v9_p; - /* Non-zero if can be used in pc-relative contexts. */ - int pcrel_p;/*FIXME:wip*/ - } ops[] = { - /* hix/lox must appear before hi/lo so %hix won't be - mistaken for %hi. */ - { "hix", 3, BFD_RELOC_SPARC_HIX22, 1, 0 }, - { "lox", 3, BFD_RELOC_SPARC_LOX10, 1, 0 }, - { "hi", 2, BFD_RELOC_HI22, 0, 1 }, - { "lo", 2, BFD_RELOC_LO10, 0, 1 }, - { "hh", 2, BFD_RELOC_SPARC_HH22, 1, 1 }, - { "hm", 2, BFD_RELOC_SPARC_HM10, 1, 1 }, - { "lm", 2, BFD_RELOC_SPARC_LM22, 1, 1 }, - { "h44", 3, BFD_RELOC_SPARC_H44, 1, 0 }, - { "m44", 3, BFD_RELOC_SPARC_M44, 1, 0 }, - { "l44", 3, BFD_RELOC_SPARC_L44, 1, 0 }, - { "uhi", 3, BFD_RELOC_SPARC_HH22, 1, 0 }, - { "ulo", 3, BFD_RELOC_SPARC_HM10, 1, 0 }, - { NULL } - }; - const struct ops *o; - - for (o = ops; o->name; o++) - if (strncmp (s + 1, o->name, o->len) == 0) - break; - if (o->name == NULL) - break; - - if (s[o->len + 1] != '(') - { - as_bad (_("Illegal operands: %%%s requires arguments in ()"), o->name); - return special_case; - } - - op_arg = o->name; - the_insn.reloc = o->reloc; - s += o->len + 2; - v9_arg_p = o->v9_p; - } - - /* Note that if the get_expression() fails, we will still - have created U entries in the symbol table for the - 'symbols' in the input string. Try not to create U - symbols for registers, etc. */ - - /* This stuff checks to see if the expression ends in - +%reg. If it does, it removes the register from - the expression, and re-sets 's' to point to the - right place. */ - - if (op_arg) - { - int npar = 0; - - for (s1 = s; *s1 && *s1 != ',' && *s1 != ']'; s1++) - if (*s1 == '(') - npar++; - else if (*s1 == ')') - { - if (!npar) - break; - npar--; - } - - if (*s1 != ')') - { - as_bad (_("Illegal operands: %%%s requires arguments in ()"), op_arg); - return special_case; - } - - *s1 = '\0'; - (void) get_expression (s); - *s1 = ')'; - s = s1 + 1; - if (*s == ',' || *s == ']' || !*s) - continue; - if (*s != '+' && *s != '-') - { - as_bad (_("Illegal operands: Can't do arithmetics other than + and - involving %%%s()"), op_arg); - return special_case; - } - *s1 = '0'; - s = s1; - op_exp = the_insn.exp; - memset (&the_insn.exp, 0, sizeof(the_insn.exp)); - } - - for (s1 = s; *s1 && *s1 != ',' && *s1 != ']'; s1++) ; - - if (s1 != s && isdigit ((unsigned char) s1[-1])) - { - if (s1[-2] == '%' && s1[-3] == '+') - s1 -= 3; - else if (strchr ("goli0123456789", s1[-2]) && s1[-3] == '%' && s1[-4] == '+') - s1 -= 4; - else - s1 = NULL; - if (s1) - { - *s1 = '\0'; - if (op_arg && s1 == s + 1) - the_insn.exp.X_op = O_absent; - else - (void) get_expression (s); - *s1 = '+'; - if (op_arg) - *s = ')'; - s = s1; - } - } - else - s1 = NULL; - - if (!s1) - { - (void) get_expression (s); - if (op_arg) - *s = ')'; - s = expr_end; - } - - if (op_arg) - { - the_insn.exp2 = the_insn.exp; - the_insn.exp = op_exp; - if (the_insn.exp2.X_op == O_absent) - the_insn.exp2.X_op = O_illegal; - else if (the_insn.exp.X_op == O_absent) - { - the_insn.exp = the_insn.exp2; - the_insn.exp2.X_op = O_illegal; - } - else if (the_insn.exp.X_op == O_constant) - { - valueT val = the_insn.exp.X_add_number; - switch (the_insn.reloc) - { - default: - break; - - case BFD_RELOC_SPARC_HH22: - val = BSR (val, 32); - /* intentional fallthrough */ - - case BFD_RELOC_SPARC_LM22: - case BFD_RELOC_HI22: - val = (val >> 10) & 0x3fffff; - break; - - case BFD_RELOC_SPARC_HM10: - val = BSR (val, 32); - /* intentional fallthrough */ - - case BFD_RELOC_LO10: - val &= 0x3ff; - break; - - case BFD_RELOC_SPARC_H44: - val >>= 22; - val &= 0x3fffff; - break; - - case BFD_RELOC_SPARC_M44: - val >>= 12; - val &= 0x3ff; - break; - - case BFD_RELOC_SPARC_L44: - val &= 0xfff; - break; - - case BFD_RELOC_SPARC_HIX22: - val = ~ val; - val = (val >> 10) & 0x3fffff; - break; - - case BFD_RELOC_SPARC_LOX10: - val = (val & 0x3ff) | 0x1c00; - break; - } - the_insn.exp = the_insn.exp2; - the_insn.exp.X_add_number += val; - the_insn.exp2.X_op = O_illegal; - the_insn.reloc = old_reloc; - } - else if (the_insn.exp2.X_op != O_constant) - { - as_bad (_("Illegal operands: Can't add non-constant expression to %%%s()"), op_arg); - return special_case; - } - else - { - if (old_reloc != BFD_RELOC_SPARC13 - || the_insn.reloc != BFD_RELOC_LO10 - || sparc_arch_size != 64 - || sparc_pic_code) - { - as_bad (_("Illegal operands: Can't do arithmetics involving %%%s() of a relocatable symbol"), op_arg); - return special_case; - } - the_insn.reloc = BFD_RELOC_SPARC_OLO10; - } - } - } - /* Check for constants that don't require emitting a reloc. */ - if (the_insn.exp.X_op == O_constant - && the_insn.exp.X_add_symbol == 0 - && the_insn.exp.X_op_symbol == 0) - { - /* For pc-relative call instructions, we reject - constants to get better code. */ - if (the_insn.pcrel - && the_insn.reloc == BFD_RELOC_32_PCREL_S2 - && in_signed_range (the_insn.exp.X_add_number, 0x3fff)) - { - error_message = _(": PC-relative operand can't be a constant"); - goto error; - } - - /* Constants that won't fit are checked in md_apply_fix3 - and bfd_install_relocation. - ??? It would be preferable to install the constants - into the insn here and save having to create a fixS - for each one. There already exists code to handle - all the various cases (e.g. in md_apply_fix3 and - bfd_install_relocation) so duplicating all that code - here isn't right. */ - } - - continue; - - case 'a': - if (*s++ == 'a') - { - opcode |= ANNUL; - continue; - } - break; - - case 'A': - { - int asi = 0; - - /* Parse an asi. */ - if (*s == '#') - { - if (! parse_keyword_arg (sparc_encode_asi, &s, &asi)) - { - error_message = _(": invalid ASI name"); - goto error; - } - } - else - { - if (! parse_const_expr_arg (&s, &asi)) - { - error_message = _(": invalid ASI expression"); - goto error; - } - if (asi < 0 || asi > 255) - { - error_message = _(": invalid ASI number"); - goto error; - } - } - opcode |= ASI (asi); - continue; - } /* alternate space */ - - case 'p': - if (strncmp (s, "%psr", 4) == 0) - { - s += 4; - continue; - } - break; - - case 'q': /* floating point queue */ - if (strncmp (s, "%fq", 3) == 0) - { - s += 3; - continue; - } - break; - - case 'Q': /* coprocessor queue */ - if (strncmp (s, "%cq", 3) == 0) - { - s += 3; - continue; - } - break; - - case 'S': - if (strcmp (str, "set") == 0 - || strcmp (str, "setuw") == 0) - { - special_case = SPECIAL_CASE_SET; - continue; - } - else if (strcmp (str, "setsw") == 0) - { - special_case = SPECIAL_CASE_SETSW; - continue; - } - else if (strcmp (str, "setx") == 0) - { - special_case = SPECIAL_CASE_SETX; - continue; - } - else if (strncmp (str, "fdiv", 4) == 0) - { - special_case = SPECIAL_CASE_FDIV; - continue; - } - break; - - case 'o': - if (strncmp (s, "%asi", 4) != 0) - break; - s += 4; - continue; - - case 's': - if (strncmp (s, "%fprs", 5) != 0) - break; - s += 5; - continue; - - case 'E': - if (strncmp (s, "%ccr", 4) != 0) - break; - s += 4; - continue; - - case 't': - if (strncmp (s, "%tbr", 4) != 0) - break; - s += 4; - continue; - - case 'w': - if (strncmp (s, "%wim", 4) != 0) - break; - s += 4; - continue; - - case 'x': - { - char *push = input_line_pointer; - expressionS e; - - input_line_pointer = s; - expression (&e); - if (e.X_op == O_constant) - { - int n = e.X_add_number; - if (n != e.X_add_number || (n & ~0x1ff) != 0) - as_bad (_("OPF immediate operand out of range (0-0x1ff)")); - else - opcode |= e.X_add_number << 5; - } - else - as_bad (_("non-immediate OPF operand, ignored")); - s = input_line_pointer; - input_line_pointer = push; - continue; - } - - case 'y': - if (strncmp (s, "%y", 2) != 0) - break; - s += 2; - continue; - - case 'u': - case 'U': - { - /* Parse a sparclet cpreg. */ - int cpreg; - if (! parse_keyword_arg (sparc_encode_sparclet_cpreg, &s, &cpreg)) - { - error_message = _(": invalid cpreg name"); - goto error; - } - opcode |= (*args == 'U' ? RS1 (cpreg) : RD (cpreg)); - continue; - } - - default: - as_fatal (_("failed sanity check.")); - } /* switch on arg code */ - - /* Break out of for() loop. */ - break; - } /* for each arg that we expect */ - - error: - if (match == 0) - { - /* Args don't match. */ - if (&insn[1] - sparc_opcodes < sparc_num_opcodes - && (insn->name == insn[1].name - || !strcmp (insn->name, insn[1].name))) - { - ++insn; - s = argsStart; - continue; - } - else - { - as_bad (_("Illegal operands%s"), error_message); - return special_case; - } - } - else - { - /* We have a match. Now see if the architecture is ok. */ - int needed_arch_mask = insn->architecture; - - if (v9_arg_p) - { - needed_arch_mask &= ~ ((1 << SPARC_OPCODE_ARCH_V9) - | (1 << SPARC_OPCODE_ARCH_V9A)); - needed_arch_mask |= (1 << SPARC_OPCODE_ARCH_V9); - } - - if (needed_arch_mask & SPARC_OPCODE_SUPPORTED (current_architecture)) - ; /* ok */ - /* Can we bump up the architecture? */ - else if (needed_arch_mask & SPARC_OPCODE_SUPPORTED (max_architecture)) - { - enum sparc_opcode_arch_val needed_architecture = - sparc_ffs (SPARC_OPCODE_SUPPORTED (max_architecture) - & needed_arch_mask); - - assert (needed_architecture <= SPARC_OPCODE_ARCH_MAX); - if (warn_on_bump - && needed_architecture > warn_after_architecture) - { - as_warn (_("architecture bumped from \"%s\" to \"%s\" on \"%s\""), - sparc_opcode_archs[current_architecture].name, - sparc_opcode_archs[needed_architecture].name, - str); - warn_after_architecture = needed_architecture; - } - current_architecture = needed_architecture; - } - /* Conflict. */ - /* ??? This seems to be a bit fragile. What if the next entry in - the opcode table is the one we want and it is supported? - It is possible to arrange the table today so that this can't - happen but what about tomorrow? */ - else - { - int arch,printed_one_p = 0; - char *p; - char required_archs[SPARC_OPCODE_ARCH_MAX * 16]; - - /* Create a list of the architectures that support the insn. */ - needed_arch_mask &= ~ SPARC_OPCODE_SUPPORTED (max_architecture); - p = required_archs; - arch = sparc_ffs (needed_arch_mask); - while ((1 << arch) <= needed_arch_mask) - { - if ((1 << arch) & needed_arch_mask) - { - if (printed_one_p) - *p++ = '|'; - strcpy (p, sparc_opcode_archs[arch].name); - p += strlen (p); - printed_one_p = 1; - } - ++arch; - } - - as_bad (_("Architecture mismatch on \"%s\"."), str); - as_tsktsk (_(" (Requires %s; requested architecture is %s.)"), - required_archs, - sparc_opcode_archs[max_architecture].name); - return special_case; - } - } /* if no match */ - - break; - } /* forever looking for a match */ - - the_insn.opcode = opcode; - return special_case; -} - -/* Parse an argument that can be expressed as a keyword. - (eg: #StoreStore or %ccfr). - The result is a boolean indicating success. - If successful, INPUT_POINTER is updated. */ - -static int -parse_keyword_arg (lookup_fn, input_pointerP, valueP) - int (*lookup_fn) PARAMS ((const char *)); - char **input_pointerP; - int *valueP; -{ - int value; - char c, *p, *q; - - p = *input_pointerP; - for (q = p + (*p == '#' || *p == '%'); - isalnum ((unsigned char) *q) || *q == '_'; - ++q) - continue; - c = *q; - *q = 0; - value = (*lookup_fn) (p); - *q = c; - if (value == -1) - return 0; - *valueP = value; - *input_pointerP = q; - return 1; -} - -/* Parse an argument that is a constant expression. - The result is a boolean indicating success. */ - -static int -parse_const_expr_arg (input_pointerP, valueP) - char **input_pointerP; - int *valueP; -{ - char *save = input_line_pointer; - expressionS exp; - - input_line_pointer = *input_pointerP; - /* The next expression may be something other than a constant - (say if we're not processing the right variant of the insn). - Don't call expression unless we're sure it will succeed as it will - signal an error (which we want to defer until later). */ - /* FIXME: It might be better to define md_operand and have it recognize - things like %asi, etc. but continuing that route through to the end - is a lot of work. */ - if (*input_line_pointer == '%') - { - input_line_pointer = save; - return 0; - } - expression (&exp); - *input_pointerP = input_line_pointer; - input_line_pointer = save; - if (exp.X_op != O_constant) - return 0; - *valueP = exp.X_add_number; - return 1; -} - -/* Subroutine of sparc_ip to parse an expression. */ - -static int -get_expression (str) - char *str; -{ - char *save_in; - segT seg; - - save_in = input_line_pointer; - input_line_pointer = str; - seg = expression (&the_insn.exp); - if (seg != absolute_section - && seg != text_section - && seg != data_section - && seg != bss_section - && seg != undefined_section) - { - the_insn.error = _("bad segment"); - expr_end = input_line_pointer; - input_line_pointer = save_in; - return 1; - } - expr_end = input_line_pointer; - input_line_pointer = save_in; - return 0; -} - -/* Subroutine of md_assemble to output one insn. */ - -static void -output_insn (insn, the_insn) - const struct sparc_opcode *insn; - struct sparc_it *the_insn; -{ - char *toP = frag_more (4); - - /* put out the opcode */ - if (INSN_BIG_ENDIAN) - number_to_chars_bigendian (toP, (valueT) the_insn->opcode, 4); - else - number_to_chars_littleendian (toP, (valueT) the_insn->opcode, 4); - - /* put out the symbol-dependent stuff */ - if (the_insn->reloc != BFD_RELOC_NONE) - { - fixS *fixP = fix_new_exp (frag_now, /* which frag */ - (toP - frag_now->fr_literal), /* where */ - 4, /* size */ - &the_insn->exp, - the_insn->pcrel, - the_insn->reloc); - /* Turn off overflow checking in fixup_segment. We'll do our - own overflow checking in md_apply_fix3. This is necessary because - the insn size is 4 and fixup_segment will signal an overflow for - large 8 byte quantities. */ - fixP->fx_no_overflow = 1; - if (the_insn->reloc == BFD_RELOC_SPARC_OLO10) - fixP->tc_fix_data = the_insn->exp2.X_add_number; - } - - last_insn = insn; - last_opcode = the_insn->opcode; -} - -/* - This is identical to the md_atof in m68k.c. I think this is right, - but I'm not sure. - - Turn a string in input_line_pointer into a floating point constant of type - type, and store the appropriate bytes in *litP. The number of LITTLENUMS - emitted is stored in *sizeP . An error message is returned, or NULL on OK. - */ - -/* Equal to MAX_PRECISION in atof-ieee.c */ -#define MAX_LITTLENUMS 6 - -char * -md_atof (type, litP, sizeP) - char type; - char *litP; - int *sizeP; -{ - int i,prec; - LITTLENUM_TYPE words[MAX_LITTLENUMS]; - char *t; - - switch (type) - { - case 'f': - case 'F': - case 's': - case 'S': - prec = 2; - break; - - case 'd': - case 'D': - case 'r': - case 'R': - prec = 4; - break; - - case 'x': - case 'X': - prec = 6; - break; - - case 'p': - case 'P': - prec = 6; - break; - - default: - *sizeP = 0; - return _("Bad call to MD_ATOF()"); - } - - t = atof_ieee (input_line_pointer, type, words); - if (t) - input_line_pointer = t; - *sizeP = prec * sizeof (LITTLENUM_TYPE); - - if (target_big_endian) - { - for (i = 0; i < prec; i++) - { - md_number_to_chars (litP, (valueT) words[i], sizeof (LITTLENUM_TYPE)); - litP += sizeof (LITTLENUM_TYPE); - } - } - else - { - for (i = prec - 1; i >= 0; i--) - { - md_number_to_chars (litP, (valueT) words[i], sizeof (LITTLENUM_TYPE)); - litP += sizeof (LITTLENUM_TYPE); - } - } - - return 0; -} - -/* Write a value out to the object file, using the appropriate - endianness. */ - -void -md_number_to_chars (buf, val, n) - char *buf; - valueT val; - int n; -{ - if (target_big_endian) - number_to_chars_bigendian (buf, val, n); - else if (target_little_endian_data - && ((n == 4 || n == 2) && ~now_seg->flags & SEC_ALLOC)) - /* Output debug words, which are not in allocated sections, as big endian */ - number_to_chars_bigendian (buf, val, n); - else if (target_little_endian_data || ! target_big_endian) - number_to_chars_littleendian (buf, val, n); -} - -/* Apply a fixS to the frags, now that we know the value it ought to - hold. */ - -int -md_apply_fix3 (fixP, value, segment) - fixS *fixP; - valueT *value; - segT segment; -{ - char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; - offsetT val; - long insn; - - val = *value; - - assert (fixP->fx_r_type < BFD_RELOC_UNUSED); - - fixP->fx_addnumber = val; /* Remember value for emit_reloc */ - -#ifdef OBJ_ELF - /* FIXME: SPARC ELF relocations don't use an addend in the data - field itself. This whole approach should be somehow combined - with the calls to bfd_install_relocation. Also, the value passed - in by fixup_segment includes the value of a defined symbol. We - don't want to include the value of an externally visible symbol. */ - if (fixP->fx_addsy != NULL) - { - if (symbol_used_in_reloc_p (fixP->fx_addsy) - && (S_IS_EXTERNAL (fixP->fx_addsy) - || S_IS_WEAK (fixP->fx_addsy) - || (sparc_pic_code && ! fixP->fx_pcrel) - || (S_GET_SEGMENT (fixP->fx_addsy) != segment - && ((bfd_get_section_flags (stdoutput, - S_GET_SEGMENT (fixP->fx_addsy)) - & SEC_LINK_ONCE) != 0 - || strncmp (segment_name (S_GET_SEGMENT (fixP->fx_addsy)), - ".gnu.linkonce", - sizeof ".gnu.linkonce" - 1) == 0))) - && S_GET_SEGMENT (fixP->fx_addsy) != absolute_section - && S_GET_SEGMENT (fixP->fx_addsy) != undefined_section - && ! bfd_is_com_section (S_GET_SEGMENT (fixP->fx_addsy))) - fixP->fx_addnumber -= S_GET_VALUE (fixP->fx_addsy); - return 1; - } -#endif - - /* This is a hack. There should be a better way to - handle this. Probably in terms of howto fields, once - we can look at these fixups in terms of howtos. */ - if (fixP->fx_r_type == BFD_RELOC_32_PCREL_S2 && fixP->fx_addsy) - val += fixP->fx_where + fixP->fx_frag->fr_address; - -#ifdef OBJ_AOUT - /* FIXME: More ridiculous gas reloc hacking. If we are going to - generate a reloc, then we just want to let the reloc addend set - the value. We do not want to also stuff the addend into the - object file. Including the addend in the object file works when - doing a static link, because the linker will ignore the object - file contents. However, the dynamic linker does not ignore the - object file contents. */ - if (fixP->fx_addsy != NULL - && fixP->fx_r_type != BFD_RELOC_32_PCREL_S2) - val = 0; - - /* When generating PIC code, we do not want an addend for a reloc - against a local symbol. We adjust fx_addnumber to cancel out the - value already included in val, and to also cancel out the - adjustment which bfd_install_relocation will create. */ - if (sparc_pic_code - && fixP->fx_r_type != BFD_RELOC_32_PCREL_S2 - && fixP->fx_addsy != NULL - && ! S_IS_COMMON (fixP->fx_addsy) - && symbol_section_p (fixP->fx_addsy)) - fixP->fx_addnumber -= 2 * S_GET_VALUE (fixP->fx_addsy); - - /* When generating PIC code, we need to fiddle to get - bfd_install_relocation to do the right thing for a PC relative - reloc against a local symbol which we are going to keep. */ - if (sparc_pic_code - && fixP->fx_r_type == BFD_RELOC_32_PCREL_S2 - && fixP->fx_addsy != NULL - && (S_IS_EXTERNAL (fixP->fx_addsy) - || S_IS_WEAK (fixP->fx_addsy)) - && S_IS_DEFINED (fixP->fx_addsy) - && ! S_IS_COMMON (fixP->fx_addsy)) - { - val = 0; - fixP->fx_addnumber -= 2 * S_GET_VALUE (fixP->fx_addsy); - } -#endif - - /* If this is a data relocation, just output VAL. */ - - if (fixP->fx_r_type == BFD_RELOC_16) - { - md_number_to_chars (buf, val, 2); - } - else if (fixP->fx_r_type == BFD_RELOC_32 - || fixP->fx_r_type == BFD_RELOC_SPARC_REV32) - { - md_number_to_chars (buf, val, 4); - } - else if (fixP->fx_r_type == BFD_RELOC_64) - { - md_number_to_chars (buf, val, 8); - } - else if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT - || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY) - { - fixP->fx_done = 0; - return 1; - } - else - { - /* It's a relocation against an instruction. */ - - if (INSN_BIG_ENDIAN) - insn = bfd_getb32 ((unsigned char *) buf); - else - insn = bfd_getl32 ((unsigned char *) buf); - - switch (fixP->fx_r_type) - { - case BFD_RELOC_32_PCREL_S2: - val = val >> 2; - /* FIXME: This increment-by-one deserves a comment of why it's - being done! */ - if (! sparc_pic_code - || fixP->fx_addsy == NULL - || symbol_section_p (fixP->fx_addsy)) - ++val; - insn |= val & 0x3fffffff; - break; - - case BFD_RELOC_SPARC_11: - if (! in_signed_range (val, 0x7ff)) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("relocation overflow")); - insn |= val & 0x7ff; - break; - - case BFD_RELOC_SPARC_10: - if (! in_signed_range (val, 0x3ff)) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("relocation overflow")); - insn |= val & 0x3ff; - break; - - case BFD_RELOC_SPARC_7: - if (! in_bitfield_range (val, 0x7f)) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("relocation overflow")); - insn |= val & 0x7f; - break; - - case BFD_RELOC_SPARC_6: - if (! in_bitfield_range (val, 0x3f)) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("relocation overflow")); - insn |= val & 0x3f; - break; - - case BFD_RELOC_SPARC_5: - if (! in_bitfield_range (val, 0x1f)) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("relocation overflow")); - insn |= val & 0x1f; - break; - - case BFD_RELOC_SPARC_WDISP16: - /* FIXME: simplify */ - if (((val > 0) && (val & ~0x3fffc)) - || ((val < 0) && (~(val - 1) & ~0x3fffc))) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("relocation overflow")); - /* FIXME: The +1 deserves a comment. */ - val = (val >> 2) + 1; - insn |= ((val & 0xc000) << 6) | (val & 0x3fff); - break; - - case BFD_RELOC_SPARC_WDISP19: - /* FIXME: simplify */ - if (((val > 0) && (val & ~0x1ffffc)) - || ((val < 0) && (~(val - 1) & ~0x1ffffc))) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("relocation overflow")); - /* FIXME: The +1 deserves a comment. */ - val = (val >> 2) + 1; - insn |= val & 0x7ffff; - break; - - case BFD_RELOC_SPARC_HH22: - val = BSR (val, 32); - /* intentional fallthrough */ - - case BFD_RELOC_SPARC_LM22: - case BFD_RELOC_HI22: - if (!fixP->fx_addsy) - { - insn |= (val >> 10) & 0x3fffff; - } - else - { - /* FIXME: Need comment explaining why we do this. */ - insn &= ~0xffff; - } - break; - - case BFD_RELOC_SPARC22: - if (val & ~0x003fffff) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("relocation overflow")); - insn |= (val & 0x3fffff); - break; - - case BFD_RELOC_SPARC_HM10: - val = BSR (val, 32); - /* intentional fallthrough */ - - case BFD_RELOC_LO10: - if (!fixP->fx_addsy) - { - insn |= val & 0x3ff; - } - else - { - /* FIXME: Need comment explaining why we do this. */ - insn &= ~0xff; - } - break; - - case BFD_RELOC_SPARC_OLO10: - val &= 0x3ff; - val += fixP->tc_fix_data; - /* intentional fallthrough */ - - case BFD_RELOC_SPARC13: - if (! in_signed_range (val, 0x1fff)) - as_bad_where (fixP->fx_file, fixP->fx_line, - _("relocation overflow")); - insn |= val & 0x1fff; - break; - - case BFD_RELOC_SPARC_WDISP22: - val = (val >> 2) + 1; - /* FALLTHROUGH */ - case BFD_RELOC_SPARC_BASE22: - insn |= val & 0x3fffff; - break; - - case BFD_RELOC_SPARC_H44: - if (!fixP->fx_addsy) - { - bfd_vma tval = val; - tval >>= 22; - insn |= tval & 0x3fffff; - } - break; - - case BFD_RELOC_SPARC_M44: - if (!fixP->fx_addsy) - insn |= (val >> 12) & 0x3ff; - break; - - case BFD_RELOC_SPARC_L44: - if (!fixP->fx_addsy) - insn |= val & 0xfff; - break; - - case BFD_RELOC_SPARC_HIX22: - if (!fixP->fx_addsy) - { - val ^= ~ (offsetT) 0; - insn |= (val >> 10) & 0x3fffff; - } - break; - - case BFD_RELOC_SPARC_LOX10: - if (!fixP->fx_addsy) - insn |= 0x1c00 | (val & 0x3ff); - break; - - case BFD_RELOC_NONE: - default: - as_bad_where (fixP->fx_file, fixP->fx_line, - _("bad or unhandled relocation type: 0x%02x"), - fixP->fx_r_type); - break; - } - - if (INSN_BIG_ENDIAN) - bfd_putb32 (insn, (unsigned char *) buf); - else - bfd_putl32 (insn, (unsigned char *) buf); - } - - /* Are we finished with this relocation now? */ - if (fixP->fx_addsy == 0 && !fixP->fx_pcrel) - fixP->fx_done = 1; - - return 1; -} - -/* Translate internal representation of relocation info to BFD target - format. */ -arelent ** -tc_gen_reloc (section, fixp) - asection *section; - fixS *fixp; -{ - static arelent *relocs[3]; - arelent *reloc; - bfd_reloc_code_real_type code; - - relocs[0] = reloc = (arelent *) xmalloc (sizeof (arelent)); - relocs[1] = NULL; - - reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); - *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); - reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; - - switch (fixp->fx_r_type) - { - case BFD_RELOC_16: - case BFD_RELOC_32: - case BFD_RELOC_HI22: - case BFD_RELOC_LO10: - case BFD_RELOC_32_PCREL_S2: - case BFD_RELOC_SPARC13: - case BFD_RELOC_SPARC22: - case BFD_RELOC_SPARC_BASE13: - case BFD_RELOC_SPARC_WDISP16: - case BFD_RELOC_SPARC_WDISP19: - case BFD_RELOC_SPARC_WDISP22: - case BFD_RELOC_64: - case BFD_RELOC_SPARC_5: - case BFD_RELOC_SPARC_6: - case BFD_RELOC_SPARC_7: - case BFD_RELOC_SPARC_10: - case BFD_RELOC_SPARC_11: - case BFD_RELOC_SPARC_HH22: - case BFD_RELOC_SPARC_HM10: - case BFD_RELOC_SPARC_LM22: - case BFD_RELOC_SPARC_PC_HH22: - case BFD_RELOC_SPARC_PC_HM10: - case BFD_RELOC_SPARC_PC_LM22: - case BFD_RELOC_SPARC_H44: - case BFD_RELOC_SPARC_M44: - case BFD_RELOC_SPARC_L44: - case BFD_RELOC_SPARC_HIX22: - case BFD_RELOC_SPARC_LOX10: - case BFD_RELOC_SPARC_REV32: - case BFD_RELOC_SPARC_OLO10: - case BFD_RELOC_VTABLE_ENTRY: - case BFD_RELOC_VTABLE_INHERIT: - code = fixp->fx_r_type; - break; - default: - abort (); - return NULL; - } - -#if defined (OBJ_ELF) || defined (OBJ_AOUT) - /* If we are generating PIC code, we need to generate a different - set of relocs. */ - -#ifdef OBJ_ELF -#define GOT_NAME "_GLOBAL_OFFSET_TABLE_" -#else -#define GOT_NAME "__GLOBAL_OFFSET_TABLE_" -#endif - - /* This code must be parallel to the OBJ_ELF tc_fix_adjustable. */ - - if (sparc_pic_code) - { - switch (code) - { - case BFD_RELOC_32_PCREL_S2: - if (! S_IS_DEFINED (fixp->fx_addsy) - || S_IS_COMMON (fixp->fx_addsy) - || S_IS_EXTERNAL (fixp->fx_addsy) - || S_IS_WEAK (fixp->fx_addsy)) - code = BFD_RELOC_SPARC_WPLT30; - break; - case BFD_RELOC_HI22: - if (fixp->fx_addsy != NULL - && strcmp (S_GET_NAME (fixp->fx_addsy), GOT_NAME) == 0) - code = BFD_RELOC_SPARC_PC22; - else - code = BFD_RELOC_SPARC_GOT22; - break; - case BFD_RELOC_LO10: - if (fixp->fx_addsy != NULL - && strcmp (S_GET_NAME (fixp->fx_addsy), GOT_NAME) == 0) - code = BFD_RELOC_SPARC_PC10; - else - code = BFD_RELOC_SPARC_GOT10; - break; - case BFD_RELOC_SPARC13: - code = BFD_RELOC_SPARC_GOT13; - break; - default: - break; - } - } -#endif /* defined (OBJ_ELF) || defined (OBJ_AOUT) */ - - if (code == BFD_RELOC_SPARC_OLO10) - reloc->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_LO10); - else - reloc->howto = bfd_reloc_type_lookup (stdoutput, code); - if (reloc->howto == 0) - { - as_bad_where (fixp->fx_file, fixp->fx_line, - _("internal error: can't export reloc type %d (`%s')"), - fixp->fx_r_type, bfd_get_reloc_code_name (code)); - xfree (reloc); - relocs[0] = NULL; - return relocs; - } - - /* @@ Why fx_addnumber sometimes and fx_offset other times? */ -#ifdef OBJ_AOUT - - if (reloc->howto->pc_relative == 0 - || code == BFD_RELOC_SPARC_PC10 - || code == BFD_RELOC_SPARC_PC22) - reloc->addend = fixp->fx_addnumber; - else if (sparc_pic_code - && fixp->fx_r_type == BFD_RELOC_32_PCREL_S2 - && fixp->fx_addsy != NULL - && (S_IS_EXTERNAL (fixp->fx_addsy) - || S_IS_WEAK (fixp->fx_addsy)) - && S_IS_DEFINED (fixp->fx_addsy) - && ! S_IS_COMMON (fixp->fx_addsy)) - reloc->addend = fixp->fx_addnumber; - else - reloc->addend = fixp->fx_offset - reloc->address; - -#else /* elf or coff */ - - if (reloc->howto->pc_relative == 0 - || code == BFD_RELOC_SPARC_PC10 - || code == BFD_RELOC_SPARC_PC22) - reloc->addend = fixp->fx_addnumber; - else if (symbol_section_p (fixp->fx_addsy)) - reloc->addend = (section->vma - + fixp->fx_addnumber - + md_pcrel_from (fixp)); - else - reloc->addend = fixp->fx_offset; -#endif - - /* We expand R_SPARC_OLO10 to R_SPARC_LO10 and R_SPARC_13 - on the same location. */ - if (code == BFD_RELOC_SPARC_OLO10) - { - relocs[1] = reloc = (arelent *) xmalloc (sizeof (arelent)); - relocs[2] = NULL; - - reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); - *reloc->sym_ptr_ptr = symbol_get_bfdsym (section_symbol (absolute_section)); - reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; - reloc->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_SPARC13); - reloc->addend = fixp->tc_fix_data; - } - - return relocs; -} - -/* We have no need to default values of symbols. */ - -/* ARGSUSED */ -symbolS * -md_undefined_symbol (name) - char *name; -{ - return 0; -} /* md_undefined_symbol() */ - -/* Round up a section size to the appropriate boundary. */ -valueT -md_section_align (segment, size) - segT segment; - valueT size; -{ -#ifndef OBJ_ELF - /* This is not right for ELF; a.out wants it, and COFF will force - the alignment anyways. */ - valueT align = ((valueT) 1 - << (valueT) bfd_get_section_alignment (stdoutput, segment)); - valueT newsize; - /* turn alignment value into a mask */ - align--; - newsize = (size + align) & ~align; - return newsize; -#else - return size; -#endif -} - -/* Exactly what point is a PC-relative offset relative TO? - On the sparc, they're relative to the address of the offset, plus - its size. This gets us to the following instruction. - (??? Is this right? FIXME-SOON) */ -long -md_pcrel_from (fixP) - fixS *fixP; -{ - long ret; - - ret = fixP->fx_where + fixP->fx_frag->fr_address; - if (! sparc_pic_code - || fixP->fx_addsy == NULL - || symbol_section_p (fixP->fx_addsy)) - ret += fixP->fx_size; - return ret; -} - -/* Return log2 (VALUE), or -1 if VALUE is not an exact positive power - of two. */ - -static int -log2 (value) - int value; -{ - int shift; - - if (value <= 0) - return -1; - - for (shift = 0; (value & 1) == 0; value >>= 1) - ++shift; - - return (value == 1) ? shift : -1; -} - -/* - * sort of like s_lcomm - */ - -#ifndef OBJ_ELF -static int max_alignment = 15; -#endif - -static void -s_reserve (ignore) - int ignore; -{ - char *name; - char *p; - char c; - int align; - int size; - int temp; - symbolS *symbolP; - - name = input_line_pointer; - c = get_symbol_end (); - p = input_line_pointer; - *p = c; - SKIP_WHITESPACE (); - - if (*input_line_pointer != ',') - { - as_bad (_("Expected comma after name")); - ignore_rest_of_line (); - return; - } - - ++input_line_pointer; - - if ((size = get_absolute_expression ()) < 0) - { - as_bad (_("BSS length (%d.) <0! Ignored."), size); - ignore_rest_of_line (); - return; - } /* bad length */ - - *p = 0; - symbolP = symbol_find_or_make (name); - *p = c; - - if (strncmp (input_line_pointer, ",\"bss\"", 6) != 0 - && strncmp (input_line_pointer, ",\".bss\"", 7) != 0) - { - as_bad (_("bad .reserve segment -- expected BSS segment")); - return; - } - - if (input_line_pointer[2] == '.') - input_line_pointer += 7; - else - input_line_pointer += 6; - SKIP_WHITESPACE (); - - if (*input_line_pointer == ',') - { - ++input_line_pointer; - - SKIP_WHITESPACE (); - if (*input_line_pointer == '\n') - { - as_bad (_("missing alignment")); - ignore_rest_of_line (); - return; - } - - align = (int) get_absolute_expression (); - -#ifndef OBJ_ELF - if (align > max_alignment) - { - align = max_alignment; - as_warn (_("alignment too large; assuming %d"), align); - } -#endif - - if (align < 0) - { - as_bad (_("negative alignment")); - ignore_rest_of_line (); - return; - } - - if (align != 0) - { - temp = log2 (align); - if (temp < 0) - { - as_bad (_("alignment not a power of 2")); - ignore_rest_of_line (); - return; - } - - align = temp; - } - - record_alignment (bss_section, align); - } - else - align = 0; - - if (!S_IS_DEFINED (symbolP) -#ifdef OBJ_AOUT - && S_GET_OTHER (symbolP) == 0 - && S_GET_DESC (symbolP) == 0 -#endif - ) - { - if (! need_pass_2) - { - char *pfrag; - segT current_seg = now_seg; - subsegT current_subseg = now_subseg; - - subseg_set (bss_section, 1); /* switch to bss */ - - if (align) - frag_align (align, 0, 0); /* do alignment */ - - /* detach from old frag */ - if (S_GET_SEGMENT(symbolP) == bss_section) - symbol_get_frag (symbolP)->fr_symbol = NULL; - - symbol_set_frag (symbolP, frag_now); - pfrag = frag_var (rs_org, 1, 1, (relax_substateT)0, symbolP, - (offsetT) size, (char *)0); - *pfrag = 0; - - S_SET_SEGMENT (symbolP, bss_section); - - subseg_set (current_seg, current_subseg); - -#ifdef OBJ_ELF - S_SET_SIZE (symbolP, size); -#endif - } - } - else - { - as_warn("Ignoring attempt to re-define symbol %s", - S_GET_NAME (symbolP)); - } /* if not redefining */ - - demand_empty_rest_of_line (); -} - -static void -s_common (ignore) - int ignore; -{ - char *name; - char c; - char *p; - int temp, size; - symbolS *symbolP; - - name = input_line_pointer; - c = get_symbol_end (); - /* just after name is now '\0' */ - p = input_line_pointer; - *p = c; - SKIP_WHITESPACE (); - if (*input_line_pointer != ',') - { - as_bad (_("Expected comma after symbol-name")); - ignore_rest_of_line (); - return; - } - input_line_pointer++; /* skip ',' */ - if ((temp = get_absolute_expression ()) < 0) - { - as_bad (_(".COMMon length (%d.) <0! Ignored."), temp); - ignore_rest_of_line (); - return; - } - size = temp; - *p = 0; - symbolP = symbol_find_or_make (name); - *p = c; - if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP)) - { - as_bad (_("Ignoring attempt to re-define symbol")); - ignore_rest_of_line (); - return; - } - if (S_GET_VALUE (symbolP) != 0) - { - if (S_GET_VALUE (symbolP) != (valueT) size) - { - as_warn (_("Length of .comm \"%s\" is already %ld. Not changed to %d."), - S_GET_NAME (symbolP), (long) S_GET_VALUE (symbolP), size); - } - } - else - { -#ifndef OBJ_ELF - S_SET_VALUE (symbolP, (valueT) size); - S_SET_EXTERNAL (symbolP); -#endif - } - know (symbol_get_frag (symbolP) == &zero_address_frag); - if (*input_line_pointer != ',') - { - as_bad (_("Expected comma after common length")); - ignore_rest_of_line (); - return; - } - input_line_pointer++; - SKIP_WHITESPACE (); - if (*input_line_pointer != '"') - { - temp = get_absolute_expression (); - -#ifndef OBJ_ELF - if (temp > max_alignment) - { - temp = max_alignment; - as_warn (_("alignment too large; assuming %d"), temp); - } -#endif - - if (temp < 0) - { - as_bad (_("negative alignment")); - ignore_rest_of_line (); - return; - } - -#ifdef OBJ_ELF - if (symbol_get_obj (symbolP)->local) - { - segT old_sec; - int old_subsec; - char *p; - int align; - - old_sec = now_seg; - old_subsec = now_subseg; - - if (temp == 0) - align = 0; - else - align = log2 (temp); - - if (align < 0) - { - as_bad (_("alignment not a power of 2")); - ignore_rest_of_line (); - return; - } - - record_alignment (bss_section, align); - subseg_set (bss_section, 0); - if (align) - frag_align (align, 0, 0); - if (S_GET_SEGMENT (symbolP) == bss_section) - symbol_get_frag (symbolP)->fr_symbol = 0; - symbol_set_frag (symbolP, frag_now); - p = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP, - (offsetT) size, (char *) 0); - *p = 0; - S_SET_SEGMENT (symbolP, bss_section); - S_CLEAR_EXTERNAL (symbolP); - S_SET_SIZE (symbolP, size); - subseg_set (old_sec, old_subsec); - } - else -#endif /* OBJ_ELF */ - { - allocate_common: - S_SET_VALUE (symbolP, (valueT) size); -#ifdef OBJ_ELF - S_SET_ALIGN (symbolP, temp); - S_SET_SIZE (symbolP, size); -#endif - S_SET_EXTERNAL (symbolP); - S_SET_SEGMENT (symbolP, bfd_com_section_ptr); - } - } - else - { - input_line_pointer++; - /* @@ Some use the dot, some don't. Can we get some consistency?? */ - if (*input_line_pointer == '.') - input_line_pointer++; - /* @@ Some say data, some say bss. */ - if (strncmp (input_line_pointer, "bss\"", 4) - && strncmp (input_line_pointer, "data\"", 5)) - { - while (*--input_line_pointer != '"') - ; - input_line_pointer--; - goto bad_common_segment; - } - while (*input_line_pointer++ != '"') - ; - goto allocate_common; - } - -#ifdef BFD_ASSEMBLER - symbol_get_bfdsym (symbolP)->flags |= BSF_OBJECT; -#endif - - demand_empty_rest_of_line (); - return; - - { - bad_common_segment: - p = input_line_pointer; - while (*p && *p != '\n') - p++; - c = *p; - *p = '\0'; - as_bad (_("bad .common segment %s"), input_line_pointer + 1); - *p = c; - input_line_pointer = p; - ignore_rest_of_line (); - return; - } -} - -/* Handle the .empty pseudo-op. This supresses the warnings about - invalid delay slot usage. */ - -static void -s_empty (ignore) - int ignore; -{ - /* The easy way to implement is to just forget about the last - instruction. */ - last_insn = NULL; -} - -static void -s_seg (ignore) - int ignore; -{ - - if (strncmp (input_line_pointer, "\"text\"", 6) == 0) - { - input_line_pointer += 6; - s_text (0); - return; - } - if (strncmp (input_line_pointer, "\"data\"", 6) == 0) - { - input_line_pointer += 6; - s_data (0); - return; - } - if (strncmp (input_line_pointer, "\"data1\"", 7) == 0) - { - input_line_pointer += 7; - s_data1 (); - return; - } - if (strncmp (input_line_pointer, "\"bss\"", 5) == 0) - { - input_line_pointer += 5; - /* We only support 2 segments -- text and data -- for now, so - things in the "bss segment" will have to go into data for now. - You can still allocate SEG_BSS stuff with .lcomm or .reserve. */ - subseg_set (data_section, 255); /* FIXME-SOMEDAY */ - return; - } - as_bad (_("Unknown segment type")); - demand_empty_rest_of_line (); -} - -static void -s_data1 () -{ - subseg_set (data_section, 1); - demand_empty_rest_of_line (); -} - -static void -s_proc (ignore) - int ignore; -{ - while (!is_end_of_line[(unsigned char) *input_line_pointer]) - { - ++input_line_pointer; - } - ++input_line_pointer; -} - -/* This static variable is set by s_uacons to tell sparc_cons_align - that the expession does not need to be aligned. */ - -static int sparc_no_align_cons = 0; - -/* This handles the unaligned space allocation pseudo-ops, such as - .uaword. .uaword is just like .word, but the value does not need - to be aligned. */ - -static void -s_uacons (bytes) - int bytes; -{ - /* Tell sparc_cons_align not to align this value. */ - sparc_no_align_cons = 1; - cons (bytes); -} - -/* This handles the native word allocation pseudo-op .nword. - For sparc_arch_size 32 it is equivalent to .word, for - sparc_arch_size 64 it is equivalent to .xword. */ - -static void -s_ncons (bytes) - int bytes; -{ - cons (sparc_arch_size == 32 ? 4 : 8); -} - -#ifdef OBJ_ELF -/* Handle the SPARC ELF .register pseudo-op. This sets the binding of a - global register. - The syntax is: - - .register %g[2367],{#scratch|symbolname|#ignore} - */ - -static void -s_register (ignore) - int ignore; -{ - char c; - int reg; - int flags; - const char *regname; - - if (input_line_pointer[0] != '%' - || input_line_pointer[1] != 'g' - || ((input_line_pointer[2] & ~1) != '2' - && (input_line_pointer[2] & ~1) != '6') - || input_line_pointer[3] != ',') - as_bad (_("register syntax is .register %%g[2367],{#scratch|symbolname|#ignore}")); - reg = input_line_pointer[2] - '0'; - input_line_pointer += 4; - - if (*input_line_pointer == '#') - { - ++input_line_pointer; - regname = input_line_pointer; - c = get_symbol_end (); - if (strcmp (regname, "scratch") && strcmp (regname, "ignore")) - as_bad (_("register syntax is .register %%g[2367],{#scratch|symbolname|#ignore}")); - if (regname [0] == 'i') - regname = NULL; - else - regname = ""; - } - else - { - regname = input_line_pointer; - c = get_symbol_end (); - } - if (sparc_arch_size == 64) - { - if (globals [reg]) - { - if ((regname && globals [reg] != (symbolS *)1 - && strcmp (S_GET_NAME (globals [reg]), regname)) - || ((regname != NULL) ^ (globals [reg] != (symbolS *)1))) - as_bad (_("redefinition of global register")); - } - else - { - if (regname == NULL) - globals [reg] = (symbolS *)1; - else - { - if (*regname) - { - if (symbol_find (regname)) - as_bad (_("Register symbol %s already defined."), - regname); - } - globals [reg] = symbol_make (regname); - flags = symbol_get_bfdsym (globals [reg])->flags; - if (! *regname) - flags = flags & ~(BSF_GLOBAL|BSF_LOCAL|BSF_WEAK); - if (! (flags & (BSF_GLOBAL|BSF_LOCAL|BSF_WEAK))) - flags |= BSF_GLOBAL; - symbol_get_bfdsym (globals [reg])->flags = flags; - S_SET_VALUE (globals [reg], (valueT)reg); - S_SET_ALIGN (globals [reg], reg); - S_SET_SIZE (globals [reg], 0); - /* Although we actually want undefined_section here, - we have to use absolute_section, because otherwise - generic as code will make it a COM section. - We fix this up in sparc_adjust_symtab. */ - S_SET_SEGMENT (globals [reg], absolute_section); - S_SET_OTHER (globals [reg], 0); - elf_symbol (symbol_get_bfdsym (globals [reg])) - ->internal_elf_sym.st_info = - ELF_ST_INFO(STB_GLOBAL, STT_REGISTER); - elf_symbol (symbol_get_bfdsym (globals [reg])) - ->internal_elf_sym.st_shndx = SHN_UNDEF; - } - } - } - - *input_line_pointer = c; - - demand_empty_rest_of_line (); -} - -/* Adjust the symbol table. We set undefined sections for STT_REGISTER - symbols which need it. */ - -void -sparc_adjust_symtab () -{ - symbolS *sym; - - for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym)) - { - if (ELF_ST_TYPE (elf_symbol (symbol_get_bfdsym (sym)) - ->internal_elf_sym.st_info) != STT_REGISTER) - continue; - - if (ELF_ST_TYPE (elf_symbol (symbol_get_bfdsym (sym)) - ->internal_elf_sym.st_shndx != SHN_UNDEF)) - continue; - - S_SET_SEGMENT (sym, undefined_section); - } -} -#endif - -/* If the --enforce-aligned-data option is used, we require .word, - et. al., to be aligned correctly. We do it by setting up an - rs_align_code frag, and checking in HANDLE_ALIGN to make sure that - no unexpected alignment was introduced. - - The SunOS and Solaris native assemblers enforce aligned data by - default. We don't want to do that, because gcc can deliberately - generate misaligned data if the packed attribute is used. Instead, - we permit misaligned data by default, and permit the user to set an - option to check for it. */ - -void -sparc_cons_align (nbytes) - int nbytes; -{ - int nalign; - char *p; - - /* Only do this if we are enforcing aligned data. */ - if (! enforce_aligned_data) - return; - - if (sparc_no_align_cons) - { - /* This is an unaligned pseudo-op. */ - sparc_no_align_cons = 0; - return; - } - - nalign = log2 (nbytes); - if (nalign == 0) - return; - - assert (nalign > 0); - - if (now_seg == absolute_section) - { - if ((abs_section_offset & ((1 << nalign) - 1)) != 0) - as_bad (_("misaligned data")); - return; - } - - p = frag_var (rs_align_code, 1, 1, (relax_substateT) 0, - (symbolS *) NULL, (offsetT) nalign, (char *) NULL); - - record_alignment (now_seg, nalign); -} - -/* This is where we do the unexpected alignment check. - This is called from HANDLE_ALIGN in tc-sparc.h. */ - -void -sparc_handle_align (fragp) - fragS *fragp; -{ - if (fragp->fr_type == rs_align_code && !fragp->fr_subtype - && fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix != 0) - as_bad_where (fragp->fr_file, fragp->fr_line, _("misaligned data")); - if (fragp->fr_type == rs_align_code && fragp->fr_subtype == 1024) - { - int count = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix; - - if (count >= 4 - && !(count & 3) - && count <= 1024 - && !((long)(fragp->fr_literal + fragp->fr_fix) & 3)) - { - unsigned *p = (unsigned *)(fragp->fr_literal + fragp->fr_fix); - int i; - - for (i = 0; i < count; i += 4, p++) - if (INSN_BIG_ENDIAN) - number_to_chars_bigendian ((char *)p, 0x01000000, 4); /* emit nops */ - else - number_to_chars_littleendian ((char *)p, 0x10000000, 4); - - if (SPARC_OPCODE_ARCH_V9_P (max_architecture) && count > 8) - { - char *waddr = &fragp->fr_literal[fragp->fr_fix]; - unsigned wval = (0x30680000 | count >> 2); /* ba,a,pt %xcc, 1f */ - if (INSN_BIG_ENDIAN) - number_to_chars_bigendian (waddr, wval, 4); - else - number_to_chars_littleendian (waddr, wval, 4); - } - fragp->fr_var = count; - } - } -} - -#ifdef OBJ_ELF -/* Some special processing for a Sparc ELF file. */ - -void -sparc_elf_final_processing () -{ - /* Set the Sparc ELF flag bits. FIXME: There should probably be some - sort of BFD interface for this. */ - if (sparc_arch_size == 64) - { - switch (sparc_memory_model) - { - case MM_RMO: - elf_elfheader (stdoutput)->e_flags |= EF_SPARCV9_RMO; - break; - case MM_PSO: - elf_elfheader (stdoutput)->e_flags |= EF_SPARCV9_PSO; - break; - default: - break; - } - } - else if (current_architecture >= SPARC_OPCODE_ARCH_V9) - elf_elfheader (stdoutput)->e_flags |= EF_SPARC_32PLUS; - if (current_architecture == SPARC_OPCODE_ARCH_V9A) - elf_elfheader (stdoutput)->e_flags |= EF_SPARC_SUN_US1; -} -#endif - -/* This is called by emit_expr via TC_CONS_FIX_NEW when creating a - reloc for a cons. We could use the definition there, except that - we want to handle little endian relocs specially. */ - -void -cons_fix_new_sparc (frag, where, nbytes, exp) - fragS *frag; - int where; - unsigned int nbytes; - expressionS *exp; -{ - bfd_reloc_code_real_type r; - - r = (nbytes == 1 ? BFD_RELOC_8 : - (nbytes == 2 ? BFD_RELOC_16 : - (nbytes == 4 ? BFD_RELOC_32 : BFD_RELOC_64))); - - if (target_little_endian_data && nbytes == 4 - && now_seg->flags & SEC_ALLOC) - r = BFD_RELOC_SPARC_REV32; - fix_new_exp (frag, where, (int) nbytes, exp, 0, r); -} - -#ifdef OBJ_ELF -int -elf32_sparc_force_relocation (fixp) - struct fix *fixp; -{ - if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT - || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY) - return 1; - - return 0; -} -#endif - diff --git a/contrib/binutils/gas/config/tc-sparc.h b/contrib/binutils/gas/config/tc-sparc.h deleted file mode 100644 index 91fda224b4075..0000000000000 --- a/contrib/binutils/gas/config/tc-sparc.h +++ /dev/null @@ -1,199 +0,0 @@ -/* tc-sparc.h - Macros and type defines for the sparc. - Copyright (C) 1989, 90-96, 97, 98, 1999 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 () - -#define RELOC_EXPANSION_POSSIBLE -#define MAX_RELOC_EXPANSION 2 - -#if 0 -#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 -#endif -/* Make it unconditional and check if -EL is valid after option parsing */ -#define SPARC_BIENDIAN - -#define WORKING_DOT_WORD - -#define md_convert_frag(b,s,f) {as_fatal (_("sparc convert_frag\n"));} -#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) \ - && subseg_text_p (now_seg)) \ - { \ - char *p; \ - p = frag_var (rs_align_code, 1 << n, 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 - -#ifdef OBJ_ELF -#define TC_FORCE_RELOCATION(fixp) elf32_sparc_force_relocation(fixp) -extern int elf32_sparc_force_relocation PARAMS ((struct fix *)); -#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. The PIC part of this test must be - parallel to the code in tc_gen_reloc which converts relocations to - GOT relocations. */ -#define tc_fix_adjustable(FIX) \ - (! S_IS_EXTERNAL ((FIX)->fx_addsy) \ - && ! S_IS_WEAK ((FIX)->fx_addsy) \ - && (FIX)->fx_r_type != BFD_RELOC_VTABLE_INHERIT \ - && (FIX)->fx_r_type != BFD_RELOC_VTABLE_ENTRY \ - && (! sparc_pic_code \ - || ((FIX)->fx_r_type != BFD_RELOC_HI22 \ - && (FIX)->fx_r_type != BFD_RELOC_LO10 \ - && (FIX)->fx_r_type != BFD_RELOC_SPARC13 \ - && ((FIX)->fx_r_type != BFD_RELOC_32_PCREL_S2 \ - || (S_IS_DEFINED ((FIX)->fx_addsy) \ - && ! S_IS_COMMON ((FIX)->fx_addsy) \ - && ! S_IS_EXTERNAL ((FIX)->fx_addsy) \ - && ! S_IS_WEAK ((FIX)->fx_addsy))) \ - && ((FIX)->fx_pcrel \ - || ((FIX)->fx_subsy != NULL \ - && (S_GET_SEGMENT ((FIX)->fx_subsy) \ - == S_GET_SEGMENT ((FIX)->fx_addsy))) \ - || S_IS_LOCAL ((FIX)->fx_addsy))))) - -/* Finish up the entire symtab. */ -#define tc_adjust_symtab() sparc_adjust_symtab () -extern void sparc_adjust_symtab PARAMS ((void)); -#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, nor any reloc - which we will need if a symbol is overridden. */ -#define tc_fix_adjustable(FIX) \ - (! sparc_pic_code \ - || ((FIX)->fx_pcrel \ - && ((FIX)->fx_addsy == NULL \ - || (! S_IS_EXTERNAL ((FIX)->fx_addsy) \ - && ! S_IS_WEAK ((FIX)->fx_addsy)))) \ - || (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 - -#define TC_CONS_FIX_NEW cons_fix_new_sparc -extern void cons_fix_new_sparc - PARAMS ((struct frag *, int, unsigned int, struct expressionS *)); - -#define TC_FIX_TYPE valueT - -#define TC_INIT_FIX_DATA(X) \ - do \ - { \ - (X)->tc_fix_data = 0; \ - } \ - while(0) - -#define TC_FIX_DATA_PRINT(FILE, FIXP) \ - do \ - { \ - fprintf((FILE), "addend2=%ld\n", \ - (unsigned long) (FIXP)->tc_fix_data); \ - } \ - while(0) - -/* end of tc-sparc.h */ diff --git a/contrib/binutils/gas/config/tc-tic30.c b/contrib/binutils/gas/config/tc-tic30.c deleted file mode 100644 index 255c06a381df8..0000000000000 --- a/contrib/binutils/gas/config/tc-tic30.c +++ /dev/null @@ -1,1888 +0,0 @@ -/* tc-c30.c -- Assembly code for the Texas Instruments TMS320C30 - Copyright (C) 1998, 1999 Free Software Foundation. - Contributed by Steven Haworth (steve@pm.cse.rmit.edu.au) - - 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. */ - -/* - Texas Instruments TMS320C30 machine specific gas. - Written by Steven Haworth (steve@pm.cse.rmit.edu.au). - Bugs & suggestions are completely welcome. This is free software. - Please help us make it better. - */ - -#include "as.h" -#include "opcode/tic30.h" - -/* put here all non-digit non-letter charcters that may occur in an operand */ -static char operand_special_chars[] = "%$-+(,)*._~/<>&^!:[@]"; -static char *ordinal_names[] = -{"first", "second", "third", "fourth", "fifth"}; - -const int md_reloc_size = 0; - -const char comment_chars[] = ";"; -const char line_comment_chars[] = "*"; -const char line_separator_chars[] = ""; - -const char *md_shortopts = ""; -struct option md_longopts[] = -{ - {NULL, no_argument, NULL, 0} -}; - -size_t md_longopts_size = sizeof (md_longopts); - -/* Chars that mean this number is a floating point constant */ -/* As in 0f12.456 */ -/* or 0d1.2345e12 */ -const char FLT_CHARS[] = "fFdDxX"; - -/* Chars that can be used to separate mant from exp in floating point nums */ -const char EXP_CHARS[] = "eE"; - -/* tables for lexical analysis */ -static char opcode_chars[256]; -static char register_chars[256]; -static char operand_chars[256]; -static char space_chars[256]; -static char identifier_chars[256]; -static char digit_chars[256]; - -/* lexical macros */ -#define is_opcode_char(x) (opcode_chars[(unsigned char) x]) -#define is_operand_char(x) (operand_chars[(unsigned char) x]) -#define is_register_char(x) (register_chars[(unsigned char) x]) -#define is_space_char(x) (space_chars[(unsigned char) x]) -#define is_identifier_char(x) (identifier_chars[(unsigned char) x]) -#define is_digit_char(x) (digit_chars[(unsigned char) x]) - -const pseudo_typeS md_pseudo_table[] = -{ - {0, 0, 0} -}; - -#undef USE_STDOUT -#define USE_STDOUT 1 - -#ifdef USE_STDARG - -#include <stdarg.h> - -int -debug (const char *string,...) -{ - if (flag_debug) - { - va_list argptr; - char str[100]; - - va_start (argptr, string); - vsprintf (str, string, argptr); - if (str[0] == '\0') - return (0); - va_end (argptr); - fputs (str, USE_STDOUT ? stdout : stderr); - return strlen (str); - } - else - return 0; -} -#else -int -debug (string, va_alist) - const char *string; - va_dcl -{ - if (flag_debug) - { - va_list argptr; - char str[100]; - int cnt; - - va_start (argptr, string); - cnt = vsprintf (str, string, argptr); - if (str[0] == NULL) - return (0); - va_end (argptr); - fputs (str, USE_STDOUT ? stdout : stderr); - return (cnt); - } - else - return 0; -} -#endif - -/* hash table for opcode lookup */ -static struct hash_control *op_hash; -/* hash table for parallel opcode lookup */ -static struct hash_control *parop_hash; -/* hash table for register lookup */ -static struct hash_control *reg_hash; -/* hash table for indirect addressing lookup */ -static struct hash_control *ind_hash; - -void -md_begin () -{ - const char *hash_err; - debug ("In md_begin()\n"); - op_hash = hash_new (); - { - const template *current_optab = tic30_optab; - for (; current_optab < tic30_optab_end; current_optab++) - { - hash_err = hash_insert (op_hash, current_optab->name, (char *) current_optab); - if (hash_err) - as_fatal ("Internal Error: Can't Hash %s: %s", current_optab->name, hash_err); - } - } - parop_hash = hash_new (); - { - const partemplate *current_parop = tic30_paroptab; - for (; current_parop < tic30_paroptab_end; current_parop++) - { - hash_err = hash_insert (parop_hash, current_parop->name, (char *) current_parop); - if (hash_err) - as_fatal ("Internal Error: Can't Hash %s: %s", current_parop->name, hash_err); - } - } - reg_hash = hash_new (); - { - const reg *current_reg = tic30_regtab; - for (; current_reg < tic30_regtab_end; current_reg++) - { - hash_err = hash_insert (reg_hash, current_reg->name, (char *) current_reg); - if (hash_err) - as_fatal ("Internal Error: Can't Hash %s: %s", current_reg->name, hash_err); - } - } - ind_hash = hash_new (); - { - const ind_addr_type *current_ind = tic30_indaddr_tab; - for (; current_ind < tic30_indaddrtab_end; current_ind++) - { - hash_err = hash_insert (ind_hash, current_ind->syntax, (char *) current_ind); - if (hash_err) - as_fatal ("Internal Error: Can't Hash %s: %s", current_ind->syntax, hash_err); - } - } - /* fill in lexical tables: opcode_chars, operand_chars, space_chars */ - { - register int c; - register char *p; - - for (c = 0; c < 256; c++) - { - if (islower (c) || isdigit (c)) - { - opcode_chars[c] = c; - register_chars[c] = c; - } - else if (isupper (c)) - { - opcode_chars[c] = tolower (c); - register_chars[c] = opcode_chars[c]; - } - else if (c == ')' || c == '(') - { - register_chars[c] = c; - } - if (isupper (c) || islower (c) || isdigit (c)) - operand_chars[c] = c; - if (isdigit (c) || c == '-') - digit_chars[c] = c; - if (isalpha (c) || c == '_' || c == '.' || isdigit (c)) - identifier_chars[c] = c; - if (c == ' ' || c == '\t') - space_chars[c] = c; - if (c == '_') - opcode_chars[c] = c; - } - for (p = operand_special_chars; *p != '\0'; p++) - operand_chars[(unsigned char) *p] = *p; - } -} - -/* Address Mode OR values */ -#define AM_Register 0x00000000 -#define AM_Direct 0x00200000 -#define AM_Indirect 0x00400000 -#define AM_Immediate 0x00600000 -#define AM_NotReq 0xFFFFFFFF - -/* PC Relative OR values */ -#define PC_Register 0x00000000 -#define PC_Relative 0x02000000 - -typedef struct -{ - unsigned op_type; - struct - { - int resolved; - unsigned address; - char *label; - expressionS direct_expr; - } - direct; - struct - { - unsigned mod; - int ARnum; - unsigned char disp; - } - indirect; - struct - { - unsigned opcode; - } - reg; - struct - { - int resolved; - int decimal_found; - float f_number; - int s_number; - unsigned int u_number; - char *label; - expressionS imm_expr; - } - immediate; -} -operand; - -int tic30_parallel_insn PARAMS ((char *)); -operand *tic30_operand PARAMS ((char *)); -char *tic30_find_parallel_insn PARAMS ((char *, char *)); - -template *opcode; - -struct tic30_insn - { - template *tm; /* Template of current instruction */ - unsigned opcode; /* Final opcode */ - int operands; /* Number of given operands */ - /* Type of operand given in instruction */ - operand *operand_type[MAX_OPERANDS]; - unsigned addressing_mode; /* Final addressing mode of instruction */ - }; - -struct tic30_insn insn; -static int found_parallel_insn; - -void -md_assemble (line) - char *line; -{ - template *opcode; - char *current_posn; - char *token_start; - char save_char; - int count; - - debug ("In md_assemble() with argument %s\n", line); - memset (&insn, '\0', sizeof (insn)); - if (found_parallel_insn) - { - debug ("Line is second part of parallel instruction\n\n"); - found_parallel_insn = 0; - return; - } - if ((current_posn = tic30_find_parallel_insn (line, input_line_pointer + 1)) == NULL) - current_posn = line; - else - found_parallel_insn = 1; - while (is_space_char (*current_posn)) - current_posn++; - token_start = current_posn; - if (!is_opcode_char (*current_posn)) - { - as_bad ("Invalid character %s in opcode", output_invalid (*current_posn)); - return; - } - /* Check if instruction is a parallel instruction by seeing if the first - character is a q. */ - if (*token_start == 'q') - { - if (tic30_parallel_insn (token_start)) - { - if (found_parallel_insn) - free (token_start); - return; - } - } - while (is_opcode_char (*current_posn)) - current_posn++; - { /* Find instruction */ - save_char = *current_posn; - *current_posn = '\0'; - opcode = (template *) hash_find (op_hash, token_start); - if (opcode) - { - debug ("Found instruction %s\n", opcode->name); - insn.tm = opcode; - } - else - { - debug ("Didn't find insn\n"); - as_bad ("Unknown TMS320C30 instruction: %s", token_start); - return; - } - *current_posn = save_char; - } - if (*current_posn != END_OF_INSN) - { /* Find operands */ - int paren_not_balanced; - int expecting_operand = 0; - int this_operand; - do - { - /* skip optional white space before operand */ - while (!is_operand_char (*current_posn) && *current_posn != END_OF_INSN) - { - if (!is_space_char (*current_posn)) - { - as_bad ("Invalid character %s before %s operand", - output_invalid (*current_posn), - ordinal_names[insn.operands]); - return; - } - current_posn++; - } - token_start = current_posn; /* after white space */ - paren_not_balanced = 0; - while (paren_not_balanced || *current_posn != ',') - { - if (*current_posn == END_OF_INSN) - { - if (paren_not_balanced) - { - as_bad ("Unbalanced parenthesis in %s operand.", - ordinal_names[insn.operands]); - return; - } - else - break; /* we are done */ - } - else if (!is_operand_char (*current_posn) && !is_space_char (*current_posn)) - { - as_bad ("Invalid character %s in %s operand", - output_invalid (*current_posn), - ordinal_names[insn.operands]); - return; - } - if (*current_posn == '(') - ++paren_not_balanced; - if (*current_posn == ')') - --paren_not_balanced; - current_posn++; - } - if (current_posn != token_start) - { /* yes, we've read in another operand */ - this_operand = insn.operands++; - if (insn.operands > MAX_OPERANDS) - { - as_bad ("Spurious operands; (%d operands/instruction max)", - MAX_OPERANDS); - return; - } - /* now parse operand adding info to 'insn' as we go along */ - save_char = *current_posn; - *current_posn = '\0'; - insn.operand_type[this_operand] = tic30_operand (token_start); - *current_posn = save_char; - if (insn.operand_type[this_operand] == NULL) - return; - } - else - { - if (expecting_operand) - { - as_bad ("Expecting operand after ','; got nothing"); - return; - } - if (*current_posn == ',') - { - as_bad ("Expecting operand before ','; got nothing"); - return; - } - } - /* now *current_posn must be either ',' or END_OF_INSN */ - if (*current_posn == ',') - { - if (*++current_posn == END_OF_INSN) - { /* just skip it, if it's \n complain */ - as_bad ("Expecting operand after ','; got nothing"); - return; - } - expecting_operand = 1; - } - } - while (*current_posn != END_OF_INSN); /* until we get end of insn */ - } - debug ("Number of operands found: %d\n", insn.operands); - /* Check that number of operands is correct */ - if (insn.operands != insn.tm->operands) - { - int i; - int numops = insn.tm->operands; - /* If operands are not the same, then see if any of the operands are not - required. Then recheck with number of given operands. If they are still not - the same, then give an error, otherwise carry on. */ - for (i = 0; i < insn.tm->operands; i++) - if (insn.tm->operand_types[i] & NotReq) - numops--; - if (insn.operands != numops) - { - as_bad ("Incorrect number of operands given"); - return; - } - } - insn.addressing_mode = AM_NotReq; - for (count = 0; count < insn.operands; count++) - { - if (insn.operand_type[count]->op_type & insn.tm->operand_types[count]) - { - debug ("Operand %d matches\n", count + 1); - /* If instruction has two operands and has an AddressMode modifier then set - addressing mode type for instruction */ - if (insn.tm->opcode_modifier == AddressMode) - { - int addr_insn = 0; - /* Store instruction uses the second operand for the address mode. */ - if ((insn.tm->operand_types[1] & (Indirect | Direct)) == (Indirect | Direct)) - addr_insn = 1; - if (insn.operand_type[addr_insn]->op_type & (AllReg)) - insn.addressing_mode = AM_Register; - else if (insn.operand_type[addr_insn]->op_type & Direct) - insn.addressing_mode = AM_Direct; - else if (insn.operand_type[addr_insn]->op_type & Indirect) - insn.addressing_mode = AM_Indirect; - else - insn.addressing_mode = AM_Immediate; - } - } - else - { - as_bad ("The %s operand doesn't match", ordinal_names[count]); - return; - } - } - /* Now set the addressing mode for 3 operand instructions. */ - if ((insn.tm->operand_types[0] & op3T1) && (insn.tm->operand_types[1] & op3T2)) - { - /* Set the addressing mode to the values used for 2 operand instructions in the - G addressing field of the opcode. */ - char *p; - switch (insn.operand_type[0]->op_type) - { - case Rn: - case ARn: - case DPReg: - case OtherReg: - if (insn.operand_type[1]->op_type & (AllReg)) - insn.addressing_mode = AM_Register; - else if (insn.operand_type[1]->op_type & Indirect) - insn.addressing_mode = AM_Direct; - else - { - /* Shouldn't make it to this stage */ - as_bad ("Incompatible first and second operands in instruction"); - return; - } - break; - case Indirect: - if (insn.operand_type[1]->op_type & (AllReg)) - insn.addressing_mode = AM_Indirect; - else if (insn.operand_type[1]->op_type & Indirect) - insn.addressing_mode = AM_Immediate; - else - { - /* Shouldn't make it to this stage */ - as_bad ("Incompatible first and second operands in instruction"); - return; - } - break; - } - /* Now make up the opcode for the 3 operand instructions. As in parallel - instructions, there will be no unresolved values, so they can be fully formed - and added to the frag table. */ - insn.opcode = insn.tm->base_opcode; - if (insn.operand_type[0]->op_type & Indirect) - { - insn.opcode |= (insn.operand_type[0]->indirect.ARnum); - insn.opcode |= (insn.operand_type[0]->indirect.mod << 3); - } - else - insn.opcode |= (insn.operand_type[0]->reg.opcode); - if (insn.operand_type[1]->op_type & Indirect) - { - insn.opcode |= (insn.operand_type[1]->indirect.ARnum << 8); - insn.opcode |= (insn.operand_type[1]->indirect.mod << 11); - } - else - insn.opcode |= (insn.operand_type[1]->reg.opcode << 8); - if (insn.operands == 3) - insn.opcode |= (insn.operand_type[2]->reg.opcode << 16); - insn.opcode |= insn.addressing_mode; - p = frag_more (INSN_SIZE); - md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE); - } - else - { /* Not a three operand instruction */ - char *p; - int am_insn = -1; - insn.opcode = insn.tm->base_opcode; - /* Create frag for instruction - all instructions are 4 bytes long. */ - p = frag_more (INSN_SIZE); - if ((insn.operands > 0) && (insn.tm->opcode_modifier == AddressMode)) - { - insn.opcode |= insn.addressing_mode; - if (insn.addressing_mode == AM_Indirect) - { - /* Determine which operand gives the addressing mode */ - if (insn.operand_type[0]->op_type & Indirect) - am_insn = 0; - if ((insn.operands > 1) && (insn.operand_type[1]->op_type & Indirect)) - am_insn = 1; - insn.opcode |= (insn.operand_type[am_insn]->indirect.disp); - insn.opcode |= (insn.operand_type[am_insn]->indirect.ARnum << 8); - insn.opcode |= (insn.operand_type[am_insn]->indirect.mod << 11); - if (insn.operands > 1) - insn.opcode |= (insn.operand_type[!am_insn]->reg.opcode << 16); - md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE); - } - else if (insn.addressing_mode == AM_Register) - { - insn.opcode |= (insn.operand_type[0]->reg.opcode); - if (insn.operands > 1) - insn.opcode |= (insn.operand_type[1]->reg.opcode << 16); - md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE); - } - else if (insn.addressing_mode == AM_Direct) - { - if (insn.operand_type[0]->op_type & Direct) - am_insn = 0; - if ((insn.operands > 1) && (insn.operand_type[1]->op_type & Direct)) - am_insn = 1; - if (insn.operands > 1) - insn.opcode |= (insn.operand_type[!am_insn]->reg.opcode << 16); - if (insn.operand_type[am_insn]->direct.resolved == 1) - { - /* Resolved values can be placed straight into instruction word, and output */ - insn.opcode |= (insn.operand_type[am_insn]->direct.address & 0x0000FFFF); - md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE); - } - else - { /* Unresolved direct addressing mode instruction */ - md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE); - fix_new_exp (frag_now, p + 2 - (frag_now->fr_literal), 2, &insn.operand_type[am_insn]->direct.direct_expr, 0, 0); - } - } - else if (insn.addressing_mode == AM_Immediate) - { - if (insn.operand_type[0]->immediate.resolved == 1) - { - char *keeploc; - int size; - if (insn.operands > 1) - insn.opcode |= (insn.operand_type[1]->reg.opcode << 16); - switch (insn.tm->imm_arg_type) - { - case Imm_Float: - debug ("Floating point first operand\n"); - md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE); - keeploc = input_line_pointer; - input_line_pointer = insn.operand_type[0]->immediate.label; - if (md_atof ('f', p + 2, &size) != 0) - { - as_bad ("invalid short form floating point immediate operand"); - return; - } - input_line_pointer = keeploc; - break; - case Imm_UInt: - debug ("Unsigned int first operand\n"); - if (insn.operand_type[0]->immediate.decimal_found) - as_warn ("rounding down first operand float to unsigned int"); - if (insn.operand_type[0]->immediate.u_number > 0xFFFF) - as_warn ("only lower 16-bits of first operand are used"); - insn.opcode |= (insn.operand_type[0]->immediate.u_number & 0x0000FFFFL); - md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE); - break; - case Imm_SInt: - debug ("Int first operand\n"); - if (insn.operand_type[0]->immediate.decimal_found) - as_warn ("rounding down first operand float to signed int"); - if (insn.operand_type[0]->immediate.s_number < -32768 || - insn.operand_type[0]->immediate.s_number > 32767) - { - as_bad ("first operand is too large for 16-bit signed int"); - return; - } - insn.opcode |= (insn.operand_type[0]->immediate.s_number & 0x0000FFFFL); - md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE); - break; - } - } - else - { /* Unresolved immediate label */ - if (insn.operands > 1) - insn.opcode |= (insn.operand_type[1]->reg.opcode << 16); - md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE); - fix_new_exp (frag_now, p + 2 - (frag_now->fr_literal), 2, &insn.operand_type[0]->immediate.imm_expr, 0, 0); - } - } - } - else if (insn.tm->opcode_modifier == PCRel) - { - /* Conditional Branch and Call instructions */ - if ((insn.tm->operand_types[0] & (AllReg | Disp)) == (AllReg | Disp)) - { - if (insn.operand_type[0]->op_type & (AllReg)) - { - insn.opcode |= (insn.operand_type[0]->reg.opcode); - insn.opcode |= PC_Register; - md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE); - } - else - { - insn.opcode |= PC_Relative; - if (insn.operand_type[0]->immediate.resolved == 1) - { - insn.opcode |= (insn.operand_type[0]->immediate.s_number & 0x0000FFFF); - md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE); - } - else - { - md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE); - fix_new_exp (frag_now, p + 2 - (frag_now->fr_literal), 2, &insn.operand_type[0]->immediate.imm_expr, 1, 0); - } - } - } - else if ((insn.tm->operand_types[0] & ARn) == ARn) - { - /* Decrement and Branch instructions */ - insn.opcode |= ((insn.operand_type[0]->reg.opcode - 0x08) << 22); - if (insn.operand_type[1]->op_type & (AllReg)) - { - insn.opcode |= (insn.operand_type[1]->reg.opcode); - insn.opcode |= PC_Register; - md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE); - } - else if (insn.operand_type[1]->immediate.resolved == 1) - { - if (insn.operand_type[0]->immediate.decimal_found) - { - as_bad ("first operand is floating point"); - return; - } - if (insn.operand_type[0]->immediate.s_number < -32768 || - insn.operand_type[0]->immediate.s_number > 32767) - { - as_bad ("first operand is too large for 16-bit signed int"); - return; - } - insn.opcode |= (insn.operand_type[1]->immediate.s_number); - insn.opcode |= PC_Relative; - md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE); - } - else - { - insn.opcode |= PC_Relative; - md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE); - fix_new_exp (frag_now, p + 2 - frag_now->fr_literal, 2, &insn.operand_type[1]->immediate.imm_expr, 1, 0); - } - } - } - else if (insn.tm->operand_types[0] == IVector) - { - /* Trap instructions */ - if (insn.operand_type[0]->op_type & IVector) - insn.opcode |= (insn.operand_type[0]->immediate.u_number); - else - { /* Shouldn't get here */ - as_bad ("interrupt vector for trap instruction out of range"); - return; - } - md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE); - } - else if (insn.tm->opcode_modifier == StackOp || insn.tm->opcode_modifier == Rotate) - { - /* Push, Pop and Rotate instructions */ - insn.opcode |= (insn.operand_type[0]->reg.opcode << 16); - md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE); - } - else if ((insn.tm->operand_types[0] & (Abs24 | Direct)) == (Abs24 | Direct)) - { - /* LDP Instruction needs to be tested for before the next section */ - if (insn.operand_type[0]->op_type & Direct) - { - if (insn.operand_type[0]->direct.resolved == 1) - { - /* Direct addressing uses lower 8 bits of direct address */ - insn.opcode |= (insn.operand_type[0]->direct.address & 0x00FF0000) >> 16; - md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE); - } - else - { - fixS *fix; - md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE); - fix = fix_new_exp (frag_now, p + 3 - (frag_now->fr_literal), 1, &insn.operand_type[0]->direct.direct_expr, 0, 0); - /* Ensure that the assembler doesn't complain about fitting a 24-bit - address into 8 bits. */ - fix->fx_no_overflow = 1; - } - } - else - { - if (insn.operand_type[0]->immediate.resolved == 1) - { - /* Immediate addressing uses upper 8 bits of address */ - if (insn.operand_type[0]->immediate.u_number > 0x00FFFFFF) - { - as_bad ("LDP instruction needs a 24-bit operand"); - return; - } - insn.opcode |= ((insn.operand_type[0]->immediate.u_number & 0x00FF0000) >> 16); - md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE); - } - else - { - fixS *fix; - md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE); - fix = fix_new_exp (frag_now, p + 3 - (frag_now->fr_literal), 1, &insn.operand_type[0]->immediate.imm_expr, 0, 0); - fix->fx_no_overflow = 1; - } - } - } - else if (insn.tm->operand_types[0] & (Imm24)) - { - /* Unconditional Branch and Call instructions */ - if (insn.operand_type[0]->immediate.resolved == 1) - { - if (insn.operand_type[0]->immediate.u_number > 0x00FFFFFF) - as_warn ("first operand is too large for a 24-bit displacement"); - insn.opcode |= (insn.operand_type[0]->immediate.u_number & 0x00FFFFFF); - md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE); - } - else - { - md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE); - fix_new_exp (frag_now, p + 1 - (frag_now->fr_literal), 3, &insn.operand_type[0]->immediate.imm_expr, 0, 0); - } - } - else if (insn.tm->operand_types[0] & NotReq) - { - /* Check for NOP instruction without arguments. */ - md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE); - } - else if (insn.tm->operands == 0) - { - /* Check for instructions without operands. */ - md_number_to_chars (p, (valueT) insn.opcode, INSN_SIZE); - } - } - debug ("Addressing mode: %08X\n", insn.addressing_mode); - { - int i; - for (i = 0; i < insn.operands; i++) - { - if (insn.operand_type[i]->immediate.label) - free (insn.operand_type[i]->immediate.label); - free (insn.operand_type[i]); - } - } - debug ("Final opcode: %08X\n", insn.opcode); - debug ("\n"); -} - -struct tic30_par_insn -{ - partemplate *tm; /* Template of current parallel instruction */ - int operands[2]; /* Number of given operands for each insn */ - /* Type of operand given in instruction */ - operand *operand_type[2][MAX_OPERANDS]; - int swap_operands; /* Whether to swap operands around. */ - unsigned p_field; /* Value of p field in multiply add/sub instructions */ - unsigned opcode; /* Final opcode */ -}; - -struct tic30_par_insn p_insn; - -int -tic30_parallel_insn (char *token) -{ - static partemplate *p_opcode; - char *current_posn = token; - char *token_start; - char save_char; - - debug ("In tic30_parallel_insn with %s\n", token); - memset (&p_insn, '\0', sizeof (p_insn)); - while (is_opcode_char (*current_posn)) - current_posn++; - { /* Find instruction */ - save_char = *current_posn; - *current_posn = '\0'; - p_opcode = (partemplate *) hash_find (parop_hash, token); - if (p_opcode) - { - debug ("Found instruction %s\n", p_opcode->name); - p_insn.tm = p_opcode; - } - else - { - char first_opcode[6] = - {0}; - char second_opcode[6] = - {0}; - int i; - int current_opcode = -1; - int char_ptr = 0; - - for (i = 0; i < strlen (token); i++) - { - char ch = *(token + i); - if (ch == '_' && current_opcode == -1) - { - current_opcode = 0; - continue; - } - if (ch == '_' && current_opcode == 0) - { - current_opcode = 1; - char_ptr = 0; - continue; - } - switch (current_opcode) - { - case 0: - first_opcode[char_ptr++] = ch; - break; - case 1: - second_opcode[char_ptr++] = ch; - break; - } - } - debug ("first_opcode = %s\n", first_opcode); - debug ("second_opcode = %s\n", second_opcode); - sprintf (token, "q_%s_%s", second_opcode, first_opcode); - p_opcode = (partemplate *) hash_find (parop_hash, token); - if (p_opcode) - { - debug ("Found instruction %s\n", p_opcode->name); - p_insn.tm = p_opcode; - p_insn.swap_operands = 1; - } - else - return 0; - } - *current_posn = save_char; - } - { /* Find operands */ - int paren_not_balanced; - int expecting_operand = 0; - int found_separator = 0; - do - { - /* skip optional white space before operand */ - while (!is_operand_char (*current_posn) && *current_posn != END_OF_INSN) - { - if (!is_space_char (*current_posn) && *current_posn != PARALLEL_SEPARATOR) - { - as_bad ("Invalid character %s before %s operand", - output_invalid (*current_posn), - ordinal_names[insn.operands]); - return 1; - } - if (*current_posn == PARALLEL_SEPARATOR) - found_separator = 1; - current_posn++; - } - token_start = current_posn; /* after white space */ - paren_not_balanced = 0; - while (paren_not_balanced || *current_posn != ',') - { - if (*current_posn == END_OF_INSN) - { - if (paren_not_balanced) - { - as_bad ("Unbalanced parenthesis in %s operand.", - ordinal_names[insn.operands]); - return 1; - } - else - break; /* we are done */ - } - else if (*current_posn == PARALLEL_SEPARATOR) - { - while (is_space_char (*(current_posn - 1))) - current_posn--; - break; - } - else if (!is_operand_char (*current_posn) && !is_space_char (*current_posn)) - { - as_bad ("Invalid character %s in %s operand", - output_invalid (*current_posn), - ordinal_names[insn.operands]); - return 1; - } - if (*current_posn == '(') - ++paren_not_balanced; - if (*current_posn == ')') - --paren_not_balanced; - current_posn++; - } - if (current_posn != token_start) - { /* yes, we've read in another operand */ - p_insn.operands[found_separator]++; - if (p_insn.operands[found_separator] > MAX_OPERANDS) - { - as_bad ("Spurious operands; (%d operands/instruction max)", - MAX_OPERANDS); - return 1; - } - /* now parse operand adding info to 'insn' as we go along */ - save_char = *current_posn; - *current_posn = '\0'; - p_insn.operand_type[found_separator][p_insn.operands[found_separator] - 1] = - tic30_operand (token_start); - *current_posn = save_char; - if (!p_insn.operand_type[found_separator][p_insn.operands[found_separator] - 1]) - return 1; - } - else - { - if (expecting_operand) - { - as_bad ("Expecting operand after ','; got nothing"); - return 1; - } - if (*current_posn == ',') - { - as_bad ("Expecting operand before ','; got nothing"); - return 1; - } - } - /* now *current_posn must be either ',' or END_OF_INSN */ - if (*current_posn == ',') - { - if (*++current_posn == END_OF_INSN) - { /* just skip it, if it's \n complain */ - as_bad ("Expecting operand after ','; got nothing"); - return 1; - } - expecting_operand = 1; - } - } - while (*current_posn != END_OF_INSN); /* until we get end of insn */ - } - if (p_insn.swap_operands) - { - int temp_num, i; - operand *temp_op; - - temp_num = p_insn.operands[0]; - p_insn.operands[0] = p_insn.operands[1]; - p_insn.operands[1] = temp_num; - for (i = 0; i < MAX_OPERANDS; i++) - { - temp_op = p_insn.operand_type[0][i]; - p_insn.operand_type[0][i] = p_insn.operand_type[1][i]; - p_insn.operand_type[1][i] = temp_op; - } - } - if (p_insn.operands[0] != p_insn.tm->operands_1) - { - as_bad ("incorrect number of operands given in the first instruction"); - return 1; - } - if (p_insn.operands[1] != p_insn.tm->operands_2) - { - as_bad ("incorrect number of operands given in the second instruction"); - return 1; - } - debug ("Number of operands in first insn: %d\n", p_insn.operands[0]); - debug ("Number of operands in second insn: %d\n", p_insn.operands[1]); - { /* Now check if operands are correct */ - int count; - int num_rn = 0; - int num_ind = 0; - for (count = 0; count < 2; count++) - { - int i; - for (i = 0; i < p_insn.operands[count]; i++) - { - if ((p_insn.operand_type[count][i]->op_type & - p_insn.tm->operand_types[count][i]) == 0) - { - as_bad ("%s instruction, operand %d doesn't match", ordinal_names[count], i + 1); - return 1; - } - /* Get number of R register and indirect reference contained within the first - two operands of each instruction. This is required for the multiply - parallel instructions which require two R registers and two indirect - references, but not in any particular place. */ - if ((p_insn.operand_type[count][i]->op_type & Rn) && i < 2) - num_rn++; - else if ((p_insn.operand_type[count][i]->op_type & Indirect) && i < 2) - num_ind++; - } - } - if ((p_insn.tm->operand_types[0][0] & (Indirect | Rn)) == (Indirect | Rn)) - { - /* Check for the multiply instructions */ - if (num_rn != 2) - { - as_bad ("incorrect format for multiply parallel instruction"); - return 1; - } - if (num_ind != 2) - { /* Shouldn't get here */ - as_bad ("incorrect format for multiply parallel instruction"); - return 1; - } - if ((p_insn.operand_type[0][2]->reg.opcode != 0x00) && - (p_insn.operand_type[0][2]->reg.opcode != 0x01)) - { - as_bad ("destination for multiply can only be R0 or R1"); - return 1; - } - if ((p_insn.operand_type[1][2]->reg.opcode != 0x02) && - (p_insn.operand_type[1][2]->reg.opcode != 0x03)) - { - as_bad ("destination for add/subtract can only be R2 or R3"); - return 1; - } - /* Now determine the P field for the instruction */ - if (p_insn.operand_type[0][0]->op_type & Indirect) - { - if (p_insn.operand_type[0][1]->op_type & Indirect) - p_insn.p_field = 0x00000000; /* Ind * Ind, Rn +/- Rn */ - else if (p_insn.operand_type[1][0]->op_type & Indirect) - p_insn.p_field = 0x01000000; /* Ind * Rn, Ind +/- Rn */ - else - p_insn.p_field = 0x03000000; /* Ind * Rn, Rn +/- Ind */ - } - else - { - if (p_insn.operand_type[0][1]->op_type & Rn) - p_insn.p_field = 0x02000000; /* Rn * Rn, Ind +/- Ind */ - else if (p_insn.operand_type[1][0]->op_type & Indirect) - { - operand *temp; - p_insn.p_field = 0x01000000; /* Rn * Ind, Ind +/- Rn */ - /* Need to swap the two multiply operands around so that everything is in - its place for the opcode makeup ie so Ind * Rn, Ind +/- Rn */ - temp = p_insn.operand_type[0][0]; - p_insn.operand_type[0][0] = p_insn.operand_type[0][1]; - p_insn.operand_type[0][1] = temp; - } - else - { - operand *temp; - p_insn.p_field = 0x03000000; /* Rn * Ind, Rn +/- Ind */ - temp = p_insn.operand_type[0][0]; - p_insn.operand_type[0][0] = p_insn.operand_type[0][1]; - p_insn.operand_type[0][1] = temp; - } - } - } - } - debug ("P field: %08X\n", p_insn.p_field); - /* Finalise opcode. This is easier for parallel instructions as they have to be - fully resolved, there are no memory addresses allowed, except through indirect - addressing, so there are no labels to resolve. */ - { - p_insn.opcode = p_insn.tm->base_opcode; - switch (p_insn.tm->oporder) - { - case OO_4op1: - p_insn.opcode |= (p_insn.operand_type[0][0]->indirect.ARnum); - p_insn.opcode |= (p_insn.operand_type[0][0]->indirect.mod << 3); - p_insn.opcode |= (p_insn.operand_type[1][1]->indirect.ARnum << 8); - p_insn.opcode |= (p_insn.operand_type[1][1]->indirect.mod << 11); - p_insn.opcode |= (p_insn.operand_type[1][0]->reg.opcode << 16); - p_insn.opcode |= (p_insn.operand_type[0][1]->reg.opcode << 22); - break; - case OO_4op2: - p_insn.opcode |= (p_insn.operand_type[0][0]->indirect.ARnum); - p_insn.opcode |= (p_insn.operand_type[0][0]->indirect.mod << 3); - p_insn.opcode |= (p_insn.operand_type[1][0]->indirect.ARnum << 8); - p_insn.opcode |= (p_insn.operand_type[1][0]->indirect.mod << 11); - p_insn.opcode |= (p_insn.operand_type[1][1]->reg.opcode << 19); - p_insn.opcode |= (p_insn.operand_type[0][1]->reg.opcode << 22); - if (p_insn.operand_type[1][1]->reg.opcode == p_insn.operand_type[0][1]->reg.opcode) - as_warn ("loading the same register in parallel operation"); - break; - case OO_4op3: - p_insn.opcode |= (p_insn.operand_type[0][1]->indirect.ARnum); - p_insn.opcode |= (p_insn.operand_type[0][1]->indirect.mod << 3); - p_insn.opcode |= (p_insn.operand_type[1][1]->indirect.ARnum << 8); - p_insn.opcode |= (p_insn.operand_type[1][1]->indirect.mod << 11); - p_insn.opcode |= (p_insn.operand_type[1][0]->reg.opcode << 16); - p_insn.opcode |= (p_insn.operand_type[0][0]->reg.opcode << 22); - break; - case OO_5op1: - p_insn.opcode |= (p_insn.operand_type[0][0]->indirect.ARnum); - p_insn.opcode |= (p_insn.operand_type[0][0]->indirect.mod << 3); - p_insn.opcode |= (p_insn.operand_type[1][1]->indirect.ARnum << 8); - p_insn.opcode |= (p_insn.operand_type[1][1]->indirect.mod << 11); - p_insn.opcode |= (p_insn.operand_type[1][0]->reg.opcode << 16); - p_insn.opcode |= (p_insn.operand_type[0][1]->reg.opcode << 19); - p_insn.opcode |= (p_insn.operand_type[0][2]->reg.opcode << 22); - break; - case OO_5op2: - p_insn.opcode |= (p_insn.operand_type[0][1]->indirect.ARnum); - p_insn.opcode |= (p_insn.operand_type[0][1]->indirect.mod << 3); - p_insn.opcode |= (p_insn.operand_type[1][1]->indirect.ARnum << 8); - p_insn.opcode |= (p_insn.operand_type[1][1]->indirect.mod << 11); - p_insn.opcode |= (p_insn.operand_type[1][0]->reg.opcode << 16); - p_insn.opcode |= (p_insn.operand_type[0][0]->reg.opcode << 19); - p_insn.opcode |= (p_insn.operand_type[0][2]->reg.opcode << 22); - break; - case OO_PField: - p_insn.opcode |= p_insn.p_field; - if (p_insn.operand_type[0][2]->reg.opcode == 0x01) - p_insn.opcode |= 0x00800000; - if (p_insn.operand_type[1][2]->reg.opcode == 0x03) - p_insn.opcode |= 0x00400000; - switch (p_insn.p_field) - { - case 0x00000000: - p_insn.opcode |= (p_insn.operand_type[0][1]->indirect.ARnum); - p_insn.opcode |= (p_insn.operand_type[0][1]->indirect.mod << 3); - p_insn.opcode |= (p_insn.operand_type[0][0]->indirect.ARnum << 8); - p_insn.opcode |= (p_insn.operand_type[0][0]->indirect.mod << 11); - p_insn.opcode |= (p_insn.operand_type[1][1]->reg.opcode << 16); - p_insn.opcode |= (p_insn.operand_type[1][0]->reg.opcode << 19); - break; - case 0x01000000: - p_insn.opcode |= (p_insn.operand_type[1][0]->indirect.ARnum); - p_insn.opcode |= (p_insn.operand_type[1][0]->indirect.mod << 3); - p_insn.opcode |= (p_insn.operand_type[0][0]->indirect.ARnum << 8); - p_insn.opcode |= (p_insn.operand_type[0][0]->indirect.mod << 11); - p_insn.opcode |= (p_insn.operand_type[1][1]->reg.opcode << 16); - p_insn.opcode |= (p_insn.operand_type[0][1]->reg.opcode << 19); - break; - case 0x02000000: - p_insn.opcode |= (p_insn.operand_type[1][1]->indirect.ARnum); - p_insn.opcode |= (p_insn.operand_type[1][1]->indirect.mod << 3); - p_insn.opcode |= (p_insn.operand_type[1][0]->indirect.ARnum << 8); - p_insn.opcode |= (p_insn.operand_type[1][0]->indirect.mod << 11); - p_insn.opcode |= (p_insn.operand_type[0][1]->reg.opcode << 16); - p_insn.opcode |= (p_insn.operand_type[0][0]->reg.opcode << 19); - break; - case 0x03000000: - p_insn.opcode |= (p_insn.operand_type[1][1]->indirect.ARnum); - p_insn.opcode |= (p_insn.operand_type[1][1]->indirect.mod << 3); - p_insn.opcode |= (p_insn.operand_type[0][0]->indirect.ARnum << 8); - p_insn.opcode |= (p_insn.operand_type[0][0]->indirect.mod << 11); - p_insn.opcode |= (p_insn.operand_type[1][0]->reg.opcode << 16); - p_insn.opcode |= (p_insn.operand_type[0][1]->reg.opcode << 19); - break; - } - break; - } - } /* Opcode is finalised at this point for all parallel instructions. */ - { /* Output opcode */ - char *p; - p = frag_more (INSN_SIZE); - md_number_to_chars (p, (valueT) p_insn.opcode, INSN_SIZE); - } - { - int i, j; - for (i = 0; i < 2; i++) - for (j = 0; j < p_insn.operands[i]; j++) - free (p_insn.operand_type[i][j]); - } - debug ("Final opcode: %08X\n", p_insn.opcode); - debug ("\n"); - return 1; -} - -operand * -tic30_operand (token) - char *token; -{ - int count; - char ind_buffer[strlen (token)]; - operand *current_op; - - debug ("In tic30_operand with %s\n", token); - current_op = (operand *) malloc (sizeof (operand)); - memset (current_op, '\0', sizeof (operand)); - if (*token == DIRECT_REFERENCE) - { - char *token_posn = token + 1; - int direct_label = 0; - debug ("Found direct reference\n"); - while (*token_posn) - { - if (!is_digit_char (*token_posn)) - direct_label = 1; - token_posn++; - } - if (direct_label) - { - char *save_input_line_pointer; - segT retval; - debug ("Direct reference is a label\n"); - current_op->direct.label = token + 1; - save_input_line_pointer = input_line_pointer; - input_line_pointer = token + 1; - debug ("Current input_line_pointer: %s\n", input_line_pointer); - retval = expression (¤t_op->direct.direct_expr); - debug ("Expression type: %d\n", current_op->direct.direct_expr.X_op); - debug ("Expression addnum: %d\n", current_op->direct.direct_expr.X_add_number); - debug ("Segment: %d\n", retval); - input_line_pointer = save_input_line_pointer; - if (current_op->direct.direct_expr.X_op == O_constant) - { - current_op->direct.address = current_op->direct.direct_expr.X_add_number; - current_op->direct.resolved = 1; - } - } - else - { - debug ("Direct reference is a number\n"); - current_op->direct.address = atoi (token + 1); - current_op->direct.resolved = 1; - } - current_op->op_type = Direct; - } - else if (*token == INDIRECT_REFERENCE) - { /* Indirect reference operand */ - int found_ar = 0; - int found_disp = 0; - int ar_number = -1; - int disp_number = 0; - int buffer_posn = 1; - ind_addr_type *ind_addr_op; - debug ("Found indirect reference\n"); - ind_buffer[0] = *token; - for (count = 1; count < strlen (token); count++) - { /* Strip operand */ - ind_buffer[buffer_posn] = tolower (*(token + count)); - if ((*(token + count - 1) == 'a' || *(token + count - 1) == 'A') && - (*(token + count) == 'r' || *(token + count) == 'R')) - { - /* AR reference is found, so get its number and remove it from the buffer - so it can pass through hash_find() */ - if (found_ar) - { - as_bad ("More than one AR register found in indirect reference"); - return NULL; - } - if (*(token + count + 1) < '0' || *(token + count + 1) > '7') - { - as_bad ("Illegal AR register in indirect reference"); - return NULL; - } - ar_number = *(token + count + 1) - '0'; - found_ar = 1; - count++; - } - if (*(token + count) == '(') - { - /* Parenthesis found, so check if a displacement value is inside. If so, get - the value and remove it from the buffer. */ - if (is_digit_char (*(token + count + 1))) - { - char disp[10]; - int disp_posn = 0; - - if (found_disp) - { - as_bad ("More than one displacement found in indirect reference"); - return NULL; - } - count++; - while (*(token + count) != ')') - { - if (!is_digit_char (*(token + count))) - { - as_bad ("Invalid displacement in indirect reference"); - return NULL; - } - disp[disp_posn++] = *(token + (count++)); - } - disp[disp_posn] = '\0'; - disp_number = atoi (disp); - count--; - found_disp = 1; - } - } - buffer_posn++; - } - ind_buffer[buffer_posn] = '\0'; - if (!found_ar) - { - as_bad ("AR register not found in indirect reference"); - return NULL; - } - ind_addr_op = (ind_addr_type *) hash_find (ind_hash, ind_buffer); - if (ind_addr_op) - { - debug ("Found indirect reference: %s\n", ind_addr_op->syntax); - if (ind_addr_op->displacement == IMPLIED_DISP) - { - found_disp = 1; - disp_number = 1; - } - else if ((ind_addr_op->displacement == DISP_REQUIRED) && !found_disp) - { - /* Maybe an implied displacement of 1 again */ - as_bad ("required displacement wasn't given in indirect reference"); - return 0; - } - } - else - { - as_bad ("illegal indirect reference"); - return NULL; - } - if (found_disp && (disp_number < 0 || disp_number > 255)) - { - as_bad ("displacement must be an unsigned 8-bit number"); - return NULL; - } - current_op->indirect.mod = ind_addr_op->modfield; - current_op->indirect.disp = disp_number; - current_op->indirect.ARnum = ar_number; - current_op->op_type = Indirect; - } - else - { - reg *regop = (reg *) hash_find (reg_hash, token); - if (regop) - { - debug ("Found register operand: %s\n", regop->name); - if (regop->regtype == REG_ARn) - current_op->op_type = ARn; - else if (regop->regtype == REG_Rn) - current_op->op_type = Rn; - else if (regop->regtype == REG_DP) - current_op->op_type = DPReg; - else - current_op->op_type = OtherReg; - current_op->reg.opcode = regop->opcode; - } - else - { - if (!is_digit_char (*token) || *(token + 1) == 'x' || strchr (token, 'h')) - { - char *save_input_line_pointer; - segT retval; - debug ("Probably a label: %s\n", token); - current_op->immediate.label = (char *) malloc (strlen (token) + 1); - strcpy (current_op->immediate.label, token); - current_op->immediate.label[strlen (token)] = '\0'; - save_input_line_pointer = input_line_pointer; - input_line_pointer = token; - debug ("Current input_line_pointer: %s\n", input_line_pointer); - retval = expression (¤t_op->immediate.imm_expr); - debug ("Expression type: %d\n", current_op->immediate.imm_expr.X_op); - debug ("Expression addnum: %d\n", current_op->immediate.imm_expr.X_add_number); - debug ("Segment: %d\n", retval); - input_line_pointer = save_input_line_pointer; - if (current_op->immediate.imm_expr.X_op == O_constant) - { - current_op->immediate.s_number = current_op->immediate.imm_expr.X_add_number; - current_op->immediate.u_number = (unsigned int) current_op->immediate.imm_expr.X_add_number; - current_op->immediate.resolved = 1; - } - } - else - { - unsigned count; - debug ("Found a number or displacement\n"); - for (count = 0; count < strlen (token); count++) - if (*(token + count) == '.') - current_op->immediate.decimal_found = 1; - current_op->immediate.label = (char *) malloc (strlen (token) + 1); - strcpy (current_op->immediate.label, token); - current_op->immediate.label[strlen (token)] = '\0'; - current_op->immediate.f_number = (float) atof (token); - current_op->immediate.s_number = (int) atoi (token); - current_op->immediate.u_number = (unsigned int) atoi (token); - current_op->immediate.resolved = 1; - } - current_op->op_type = Disp | Abs24 | Imm16 | Imm24; - if (current_op->immediate.u_number >= 0 && current_op->immediate.u_number <= 31) - current_op->op_type |= IVector; - } - } - return current_op; -} - -/* next_line points to the next line after the current instruction (current_line). - Search for the parallel bars, and if found, merge two lines into internal syntax - for a parallel instruction: - q_[INSN1]_[INSN2] [OPERANDS1] | [OPERANDS2] - By this stage, all comments are scrubbed, and only the bare lines are given. - */ - -#define NONE 0 -#define START_OPCODE 1 -#define END_OPCODE 2 -#define START_OPERANDS 3 -#define END_OPERANDS 4 - -char * -tic30_find_parallel_insn (current_line, next_line) - char *current_line; - char *next_line; -{ - int found_parallel = 0; - char first_opcode[256]; - char second_opcode[256]; - char first_operands[256]; - char second_operands[256]; - char *parallel_insn; - - debug ("In tic30_find_parallel_insn()\n"); - while (!is_end_of_line[(int) *next_line]) - { - if (*next_line == PARALLEL_SEPARATOR && *(next_line + 1) == PARALLEL_SEPARATOR) - { - found_parallel = 1; - next_line++; - break; - } - next_line++; - } - if (!found_parallel) - return NULL; - debug ("Found a parallel instruction\n"); - { - int i; - char *opcode, *operands, *line; - - for (i = 0; i < 2; i++) - { - if (i == 0) - { - opcode = &first_opcode[0]; - operands = &first_operands[0]; - line = current_line; - } - else - { - opcode = &second_opcode[0]; - operands = &second_operands[0]; - line = next_line; - } - { - int search_status = NONE; - int char_ptr = 0; - char c; - - while (!is_end_of_line[(int) (c = *line)] && *line) - { - if (is_opcode_char (c) && search_status == NONE) - { - opcode[char_ptr++] = tolower (c); - search_status = START_OPCODE; - } - else if (is_opcode_char (c) && search_status == START_OPCODE) - { - opcode[char_ptr++] = tolower (c); - } - else if (!is_opcode_char (c) && search_status == START_OPCODE) - { - opcode[char_ptr] = '\0'; - char_ptr = 0; - search_status = END_OPCODE; - } - else if (is_operand_char (c) && search_status == START_OPERANDS) - { - operands[char_ptr++] = c; - } - if (is_operand_char (c) && search_status == END_OPCODE) - { - operands[char_ptr++] = c; - search_status = START_OPERANDS; - } - line++; - } - if (search_status != START_OPERANDS) - return NULL; - operands[char_ptr] = '\0'; - } - } - } - parallel_insn = (char *) malloc (strlen (first_opcode) + strlen (first_operands) + - strlen (second_opcode) + strlen (second_operands) + 8); - sprintf (parallel_insn, "q_%s_%s %s | %s", first_opcode, second_opcode, first_operands, second_operands); - debug ("parallel insn = %s\n", parallel_insn); - return parallel_insn; -} - -#undef NONE -#undef START_OPCODE -#undef END_OPCODE -#undef START_OPERANDS -#undef END_OPERANDS - -/* In order to get gas to ignore any | chars at the start of a line, - this function returns true if a | is found in a line. */ - -int -tic30_unrecognized_line (c) - int c; -{ - debug ("In tc_unrecognized_line\n"); - return (c == PARALLEL_SEPARATOR); -} - -int -md_estimate_size_before_relax (fragP, segment) - fragS *fragP; - segT segment; -{ - debug ("In md_estimate_size_before_relax()\n"); - return 0; -} - -void -md_convert_frag (abfd, sec, fragP) - bfd *abfd; - segT sec; - register fragS *fragP; -{ - debug ("In md_convert_frag()\n"); -} - -int -md_apply_fix (fixP, valP) - fixS *fixP; - valueT *valP; -{ - valueT value = *valP; - - debug ("In md_apply_fix() with value = %ld\n", (long) value); - debug ("Values in fixP\n"); - debug ("fx_size = %d\n", fixP->fx_size); - debug ("fx_pcrel = %d\n", fixP->fx_pcrel); - debug ("fx_where = %d\n", fixP->fx_where); - debug ("fx_offset = %d\n", (int) fixP->fx_offset); - { - char *buf = fixP->fx_frag->fr_literal + fixP->fx_where; - value /= INSN_SIZE; - if (fixP->fx_size == 1) - { /* Special fix for LDP instruction. */ - value = (value & 0x00FF0000) >> 16; - } - debug ("new value = %ld\n", (long) value); - md_number_to_chars (buf, value, fixP->fx_size); - } - return 1; -} - -int -md_parse_option (c, arg) - int c; - char *arg; -{ - int i; - - debug ("In md_parse_option()\n"); - for (i = 0; i < c; i++) - { - printf ("%c\n", arg[c]); - } - return 0; -} - -void -md_show_usage (stream) - FILE *stream; -{ - debug ("In md_show_usage()\n"); -} - -symbolS * -md_undefined_symbol (name) - char *name; -{ - debug ("In md_undefined_symbol()\n"); - return (symbolS *) 0; -} - -valueT -md_section_align (segment, size) - segT segment; - valueT size; -{ - debug ("In md_section_align() segment = %d and size = %d\n", segment, size); - size = (size + 3) / 4; - size *= 4; - debug ("New size value = %d\n", size); - return size; -} - -long -md_pcrel_from (fixP) - fixS *fixP; -{ - int offset; - - debug ("In md_pcrel_from()\n"); - debug ("fx_where = %d\n", fixP->fx_where); - debug ("fx_size = %d\n", fixP->fx_size); - /* Find the opcode that represents the current instruction in the fr_literal - storage area, and check bit 21. Bit 21 contains whether the current instruction - is a delayed one or not, and then set the offset value appropriately. */ - if (fixP->fx_frag->fr_literal[fixP->fx_where - fixP->fx_size + 1] & 0x20) - offset = 3; - else - offset = 1; - debug ("offset = %d\n", offset); - /* PC Relative instructions have a format: - displacement = Label - (PC + offset) - This function returns PC + offset where: - fx_where - fx_size = PC - INSN_SIZE * offset = offset number of instructions - */ - return fixP->fx_where - fixP->fx_size + (INSN_SIZE * offset); -} - -char * -md_atof (what_statement_type, literalP, sizeP) - int what_statement_type; - char *literalP; - int *sizeP; -{ - int prec; - char *token; - char keepval; - unsigned long value; - /* char *atof_ieee (); */ - float float_value; - debug ("In md_atof()\n"); - debug ("precision = %c\n", what_statement_type); - debug ("literal = %s\n", literalP); - debug ("line = "); - token = input_line_pointer; - while (!is_end_of_line[(unsigned) *input_line_pointer] && (*input_line_pointer) && (*input_line_pointer != ',')) - { - debug ("%c", *input_line_pointer); - input_line_pointer++; - } - keepval = *input_line_pointer; - *input_line_pointer = '\0'; - debug ("\n"); - float_value = (float) atof (token); - *input_line_pointer = keepval; - debug ("float_value = %f\n", float_value); - switch (what_statement_type) - { - case 'f': - case 'F': - case 's': - case 'S': - prec = 2; - break; - - case 'd': - case 'D': - case 'r': - case 'R': - prec = 4; - break; - - default: - *sizeP = 0; - return "Bad call to MD_ATOF()"; - } - if (float_value == 0.0) - { - value = (prec == 2) ? 0x00008000L : 0x80000000L; - } - else - { - unsigned long exp, sign, mant, tmsfloat; - tmsfloat = *((long *) &float_value); - sign = tmsfloat & 0x80000000; - mant = tmsfloat & 0x007FFFFF; - exp = tmsfloat & 0x7F800000; - exp <<= 1; - if (exp == 0xFF000000) - { - if (mant == 0) - value = 0x7F7FFFFF; - else if (sign == 0) - value = 0x7F7FFFFF; - else - value = 0x7F800000; - } - else - { - exp -= 0x7F000000; - if (sign) - { - mant = mant & 0x007FFFFF; - mant = -mant; - mant = mant & 0x00FFFFFF; - if (mant == 0) - { - mant |= 0x00800000; - exp = (long) exp - 0x01000000; - } - } - tmsfloat = exp | mant; - value = tmsfloat; - } - if (prec == 2) - { - long exp, mant; - - if (tmsfloat == 0x80000000) - { - value = 0x8000; - } - else - { - value = 0; - exp = (tmsfloat & 0xFF000000); - exp >>= 24; - mant = tmsfloat & 0x007FFFFF; - if (tmsfloat & 0x00800000) - { - mant |= 0xFF000000; - mant += 0x00000800; - mant >>= 12; - mant |= 0x00000800; - mant &= 0x0FFF; - if (exp > 7) - value = 0x7800; - } - else - { - mant |= 0x00800000; - mant += 0x00000800; - exp += (mant >> 24); - mant >>= 12; - mant &= 0x07FF; - if (exp > 7) - value = 0x77FF; - } - if (exp < -8) - value = 0x8000; - if (value == 0) - { - mant = (exp << 12) | mant; - value = mant & 0xFFFF; - } - } - } - } - md_number_to_chars (literalP, value, prec); - *sizeP = prec; - return 0; -} - -void -md_number_to_chars (buf, val, n) - char *buf; - valueT val; - int n; -{ - debug ("In md_number_to_chars()\n"); - number_to_chars_bigendian (buf, val, n); - /* number_to_chars_littleendian(buf,val,n); */ -} - -#define F(SZ,PCREL) (((SZ) << 1) + (PCREL)) -#define MAP(SZ,PCREL,TYPE) case F(SZ,PCREL): code = (TYPE); break - -arelent * -tc_gen_reloc (section, fixP) - asection *section; - fixS *fixP; -{ - arelent *rel; - bfd_reloc_code_real_type code = 0; - - debug ("In tc_gen_reloc()\n"); - debug ("fixP.size = %d\n", fixP->fx_size); - debug ("fixP.pcrel = %d\n", fixP->fx_pcrel); - debug ("addsy.name = %s\n", S_GET_NAME (fixP->fx_addsy)); - switch (F (fixP->fx_size, fixP->fx_pcrel)) - { - MAP (1, 0, BFD_RELOC_TIC30_LDP); - MAP (2, 0, BFD_RELOC_16); - MAP (3, 0, BFD_RELOC_24); - MAP (2, 1, BFD_RELOC_16_PCREL); - MAP (4, 0, BFD_RELOC_32); - default: - as_bad ("Can not do %d byte %srelocation", fixP->fx_size, - fixP->fx_pcrel ? "pc-relative " : ""); - } -#undef MAP -#undef F - - rel = (arelent *) xmalloc (sizeof (arelent)); - assert (rel != 0); - rel->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); - *rel->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy); - rel->address = fixP->fx_frag->fr_address + fixP->fx_where; - if (fixP->fx_pcrel) - rel->addend = fixP->fx_addnumber; - else - rel->addend = 0; - rel->howto = bfd_reloc_type_lookup (stdoutput, code); - if (!rel->howto) - { - const char *name; - name = S_GET_NAME (fixP->fx_addsy); - if (name == NULL) - name = "<unknown>"; - as_fatal ("Cannot generate relocation type for symbol %s, code %s", name, bfd_get_reloc_code_name (code)); - } - return rel; -} - -void -tc_aout_pre_write_hook () -{ - debug ("In tc_aout_pre_write_hook()\n"); -} - -void -md_operand (expressionP) - expressionS *expressionP; -{ - debug ("In md_operand()\n"); -} - -char output_invalid_buf[8]; - -char * -output_invalid (c) - char c; -{ - if (isprint (c)) - sprintf (output_invalid_buf, "'%c'", c); - else - sprintf (output_invalid_buf, "(0x%x)", (unsigned) c); - return output_invalid_buf; -} diff --git a/contrib/binutils/gas/config/tc-tic30.h b/contrib/binutils/gas/config/tc-tic30.h deleted file mode 100644 index d172d2e5c520c..0000000000000 --- a/contrib/binutils/gas/config/tc-tic30.h +++ /dev/null @@ -1,55 +0,0 @@ -/* tc-tic30.h -- Header file for tc-tic30.c - Copyright (C) 1998 Free Software Foundation. - Contributed by Steven Haworth (steve@pm.cse.rmit.edu.au) - - 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_TIC30_H_ -#define _TC_TIC30_H_ - -#define TC_TIC30 1 - -#ifdef OBJ_AOUT -#define TARGET_FORMAT "a.out-tic30" -#endif - -#define TARGET_ARCH bfd_arch_tic30 -#define TARGET_BYTES_BIG_ENDIAN 1 - -#define WORKING_DOT_WORD - -char *output_invalid PARAMS ((int c)); - -#define END_OF_INSN '\0' -#define MAX_OPERANDS 6 -#define DIRECT_REFERENCE '@' -#define INDIRECT_REFERENCE '*' -#define PARALLEL_SEPARATOR '|' -#define INSN_SIZE 4 - -/* Define this to 1 if you want the debug output to be on stdout, - otherwise stderr will be used. If stderr is used, there will be a - better synchronisation with the as_bad outputs, but you can't - capture the output. */ -#define USE_STDOUT 0 - -#define tc_unrecognized_line tic30_unrecognized_line - -extern int tic30_unrecognized_line PARAMS ((int)); - -#endif diff --git a/contrib/binutils/gas/config/tc-v850.c b/contrib/binutils/gas/config/tc-v850.c deleted file mode 100644 index e53054d87808e..0000000000000 --- a/contrib/binutils/gas/config/tc-v850.c +++ /dev/null @@ -1,2482 +0,0 @@ -/* tc-v850.c -- Assembler code for the NEC V850 - Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation. - - 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. */ - -#include <stdio.h> -#include <ctype.h> -#include "as.h" -#include "subsegs.h" -#include "opcode/v850.h" - -#define AREA_ZDA 0 -#define AREA_SDA 1 -#define AREA_TDA 2 - -/* sign-extend a 16-bit number */ -#define SEXT16(x) ((((x) & 0xffff) ^ (~ 0x7fff)) + 0x8000) - -/* Temporarily holds the reloc in a cons expression. */ -static bfd_reloc_code_real_type hold_cons_reloc; - -/* Set to TRUE if we want to be pedantic about signed overflows. */ -static boolean warn_signed_overflows = FALSE; -static boolean warn_unsigned_overflows = FALSE; - -/* Indicates the target BFD machine number. */ -static int machine = -1; - -/* Indicates the target processor(s) for the assemble. */ -static unsigned int processor_mask = -1; - - -/* Structure to hold information about predefined registers. */ -struct reg_name -{ - const char * name; - int value; -}; - -/* Generic assembler global variables which must be defined by all targets. */ - -/* Characters which always start a comment. */ -const char comment_chars[] = "#"; - -/* Characters which start a comment at the beginning of a line. */ -const char line_comment_chars[] = ";#"; - -/* Characters which may be used to separate multiple commands on a - single line. */ -const char line_separator_chars[] = ";"; - -/* Characters which are used to indicate an exponent in a floating - point number. */ -const char EXP_CHARS[] = "eE"; - -/* Characters which mean that a number is a floating point constant, - as in 0d1.0. */ -const char FLT_CHARS[] = "dD"; - - -const relax_typeS md_relax_table[] = -{ - /* Conditional branches. */ - {0xff, -0x100, 2, 1}, - {0x1fffff, -0x200000, 6, 0}, - /* Unconditional branches. */ - {0xff, -0x100, 2, 3}, - {0x1fffff, -0x200000, 4, 0}, -}; - - -static segT sdata_section = NULL; -static segT tdata_section = NULL; -static segT zdata_section = NULL; -static segT sbss_section = NULL; -static segT tbss_section = NULL; -static segT zbss_section = NULL; -static segT rosdata_section = NULL; -static segT rozdata_section = NULL; -static segT scommon_section = NULL; -static segT tcommon_section = NULL; -static segT zcommon_section = NULL; -static segT call_table_data_section = NULL; -static segT call_table_text_section = NULL; - -/* fixups */ -#define MAX_INSN_FIXUPS (5) -struct v850_fixup -{ - expressionS exp; - int opindex; - bfd_reloc_code_real_type reloc; -}; - -struct v850_fixup fixups [MAX_INSN_FIXUPS]; -static int fc; - - -void -v850_sdata (int ignore) -{ - obj_elf_section_change_hook(); - - subseg_set (sdata_section, (subsegT) get_absolute_expression ()); - - demand_empty_rest_of_line (); -} - -void -v850_tdata (int ignore) -{ - obj_elf_section_change_hook(); - - subseg_set (tdata_section, (subsegT) get_absolute_expression ()); - - demand_empty_rest_of_line (); -} - -void -v850_zdata (int ignore) -{ - obj_elf_section_change_hook(); - - subseg_set (zdata_section, (subsegT) get_absolute_expression ()); - - demand_empty_rest_of_line (); -} - -void -v850_sbss (int ignore) -{ - obj_elf_section_change_hook(); - - subseg_set (sbss_section, (subsegT) get_absolute_expression ()); - - demand_empty_rest_of_line (); -} - -void -v850_tbss (int ignore) -{ - obj_elf_section_change_hook(); - - subseg_set (tbss_section, (subsegT) get_absolute_expression ()); - - demand_empty_rest_of_line (); -} - -void -v850_zbss (int ignore) -{ - obj_elf_section_change_hook(); - - subseg_set (zbss_section, (subsegT) get_absolute_expression ()); - - demand_empty_rest_of_line (); -} - -void -v850_rosdata (int ignore) -{ - obj_elf_section_change_hook(); - - subseg_set (rosdata_section, (subsegT) get_absolute_expression ()); - - demand_empty_rest_of_line (); -} - -void -v850_rozdata (int ignore) -{ - obj_elf_section_change_hook(); - - subseg_set (rozdata_section, (subsegT) get_absolute_expression ()); - - demand_empty_rest_of_line (); -} - -void -v850_call_table_data (int ignore) -{ - obj_elf_section_change_hook(); - - subseg_set (call_table_data_section, (subsegT) get_absolute_expression ()); - - demand_empty_rest_of_line (); -} - -void -v850_call_table_text (int ignore) -{ - obj_elf_section_change_hook(); - - subseg_set (call_table_text_section, (subsegT) get_absolute_expression ()); - - demand_empty_rest_of_line (); -} - -void -v850_bss (int ignore) -{ - register int temp = get_absolute_expression (); - - obj_elf_section_change_hook(); - - subseg_set (bss_section, (subsegT) temp); - - demand_empty_rest_of_line (); -} - -void -v850_offset (int ignore) -{ - int temp = get_absolute_expression (); - - temp -= frag_now_fix(); - - if (temp > 0) - (void) frag_more (temp); - - demand_empty_rest_of_line (); -} - -/* Copied from obj_elf_common() in gas/config/obj-elf.c */ -static void -v850_comm (area) - int area; -{ - char * name; - char c; - char * p; - int temp; - int size; - symbolS * symbolP; - int have_align; - - name = input_line_pointer; - c = get_symbol_end (); - - /* just after name is now '\0' */ - p = input_line_pointer; - *p = c; - - SKIP_WHITESPACE (); - - if (*input_line_pointer != ',') - { - as_bad (_("Expected comma after symbol-name")); - ignore_rest_of_line (); - return; - } - - input_line_pointer ++; /* skip ',' */ - - if ((temp = get_absolute_expression ()) < 0) - { - /* xgettext:c-format */ - as_bad (_(".COMMon length (%d.) < 0! Ignored."), temp); - ignore_rest_of_line (); - return; - } - - size = temp; - *p = 0; - symbolP = symbol_find_or_make (name); - *p = c; - - if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP)) - { - as_bad (_("Ignoring attempt to re-define symbol")); - ignore_rest_of_line (); - return; - } - - if (S_GET_VALUE (symbolP) != 0) - { - if (S_GET_VALUE (symbolP) != size) - { - /* xgettext:c-format */ - as_warn (_("Length of .comm \"%s\" is already %ld. Not changed to %d."), - S_GET_NAME (symbolP), (long) S_GET_VALUE (symbolP), size); - } - } - - know (symbol_get_frag (symbolP) == & zero_address_frag); - - if (*input_line_pointer != ',') - have_align = 0; - else - { - have_align = 1; - input_line_pointer++; - SKIP_WHITESPACE (); - } - - if (! have_align || *input_line_pointer != '"') - { - if (! have_align) - temp = 0; - else - { - temp = get_absolute_expression (); - - if (temp < 0) - { - temp = 0; - as_warn (_("Common alignment negative; 0 assumed")); - } - } - - if (symbol_get_obj (symbolP)->local) - { - segT old_sec; - int old_subsec; - char * pfrag; - int align; - flagword applicable; - - old_sec = now_seg; - old_subsec = now_subseg; - - applicable = bfd_applicable_section_flags (stdoutput); - - applicable &= SEC_ALLOC; - - switch (area) - { - case AREA_SDA: - if (sbss_section == NULL) - { - sbss_section = subseg_new (".sbss", 0); - - bfd_set_section_flags (stdoutput, sbss_section, applicable); - - seg_info (sbss_section)->bss = 1; - } - break; - - case AREA_ZDA: - if (zbss_section == NULL) - { - zbss_section = subseg_new (".zbss", 0); - - bfd_set_section_flags (stdoutput, sbss_section, applicable); - - seg_info (zbss_section)->bss = 1; - } - break; - - case AREA_TDA: - if (tbss_section == NULL) - { - tbss_section = subseg_new (".tbss", 0); - - bfd_set_section_flags (stdoutput, tbss_section, applicable); - - seg_info (tbss_section)->bss = 1; - } - break; - } - - if (temp) - { - /* convert to a power of 2 alignment */ - for (align = 0; (temp & 1) == 0; temp >>= 1, ++align) - ; - - if (temp != 1) - { - as_bad (_("Common alignment not a power of 2")); - ignore_rest_of_line (); - return; - } - } - else - align = 0; - - switch (area) - { - case AREA_SDA: - record_alignment (sbss_section, align); - obj_elf_section_change_hook(); - subseg_set (sbss_section, 0); - break; - - case AREA_ZDA: - record_alignment (zbss_section, align); - obj_elf_section_change_hook(); - subseg_set (zbss_section, 0); - break; - - case AREA_TDA: - record_alignment (tbss_section, align); - obj_elf_section_change_hook(); - subseg_set (tbss_section, 0); - break; - - default: - abort(); - } - - if (align) - frag_align (align, 0, 0); - - switch (area) - { - case AREA_SDA: - if (S_GET_SEGMENT (symbolP) == sbss_section) - symbol_get_frag (symbolP)->fr_symbol = 0; - break; - - case AREA_ZDA: - if (S_GET_SEGMENT (symbolP) == zbss_section) - symbol_get_frag (symbolP)->fr_symbol = 0; - break; - - case AREA_TDA: - if (S_GET_SEGMENT (symbolP) == tbss_section) - symbol_get_frag (symbolP)->fr_symbol = 0; - break; - - default: - abort (); - } - - symbol_set_frag (symbolP, frag_now); - pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP, - (offsetT) size, (char *) 0); - *pfrag = 0; - S_SET_SIZE (symbolP, size); - - switch (area) - { - case AREA_SDA: - S_SET_SEGMENT (symbolP, sbss_section); - break; - - case AREA_ZDA: - S_SET_SEGMENT (symbolP, zbss_section); - break; - - case AREA_TDA: - S_SET_SEGMENT (symbolP, tbss_section); - break; - - default: - abort(); - } - - S_CLEAR_EXTERNAL (symbolP); - obj_elf_section_change_hook(); - subseg_set (old_sec, old_subsec); - } - else - { - allocate_common: - S_SET_VALUE (symbolP, (valueT) size); - S_SET_ALIGN (symbolP, temp); - S_SET_EXTERNAL (symbolP); - - switch (area) - { - case AREA_SDA: - if (scommon_section == NULL) - { - flagword applicable; - - applicable = bfd_applicable_section_flags (stdoutput); - - scommon_section = subseg_new (".scommon", 0); - - bfd_set_section_flags (stdoutput, scommon_section, applicable - & (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA - | SEC_HAS_CONTENTS) | SEC_IS_COMMON); - } - S_SET_SEGMENT (symbolP, scommon_section); - break; - - case AREA_ZDA: - if (zcommon_section == NULL) - { - flagword applicable; - - applicable = bfd_applicable_section_flags (stdoutput); - - zcommon_section = subseg_new (".zcommon", 0); - - bfd_set_section_flags (stdoutput, zcommon_section, applicable - & (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA - | SEC_HAS_CONTENTS) | SEC_IS_COMMON); - } - S_SET_SEGMENT (symbolP, zcommon_section); - break; - - case AREA_TDA: - if (tcommon_section == NULL) - { - flagword applicable; - - applicable = bfd_applicable_section_flags (stdoutput); - - tcommon_section = subseg_new (".tcommon", 0); - - bfd_set_section_flags (stdoutput, tcommon_section, applicable - & (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA - | SEC_HAS_CONTENTS) | SEC_IS_COMMON); - } - S_SET_SEGMENT (symbolP, tcommon_section); - break; - - default: - abort(); - } - } - } - else - { - input_line_pointer++; - /* @@ Some use the dot, some don't. Can we get some consistency?? */ - if (*input_line_pointer == '.') - input_line_pointer++; - /* @@ Some say data, some say bss. */ - if (strncmp (input_line_pointer, "bss\"", 4) - && strncmp (input_line_pointer, "data\"", 5)) - { - while (*--input_line_pointer != '"') - ; - input_line_pointer--; - goto bad_common_segment; - } - while (*input_line_pointer++ != '"') - ; - goto allocate_common; - } - - symbol_get_bfdsym (symbolP)->flags |= BSF_OBJECT; - - demand_empty_rest_of_line (); - return; - - { - bad_common_segment: - p = input_line_pointer; - while (*p && *p != '\n') - p++; - c = *p; - *p = '\0'; - as_bad (_("bad .common segment %s"), input_line_pointer + 1); - *p = c; - input_line_pointer = p; - ignore_rest_of_line (); - return; - } -} - -void -set_machine (int number) -{ - machine = number; - bfd_set_arch_mach (stdoutput, TARGET_ARCH, machine); - - switch (machine) - { - case 0: processor_mask = PROCESSOR_V850; break; - case bfd_mach_v850e: processor_mask = PROCESSOR_V850E; break; - case bfd_mach_v850ea: processor_mask = PROCESSOR_V850EA; break; - } -} - -/* The target specific pseudo-ops which we support. */ -const pseudo_typeS md_pseudo_table[] = -{ - {"sdata", v850_sdata, 0}, - {"tdata", v850_tdata, 0}, - {"zdata", v850_zdata, 0}, - {"sbss", v850_sbss, 0}, - {"tbss", v850_tbss, 0}, - {"zbss", v850_zbss, 0}, - {"rosdata", v850_rosdata, 0}, - {"rozdata", v850_rozdata, 0}, - {"bss", v850_bss, 0}, - {"offset", v850_offset, 0}, - {"word", cons, 4}, - {"zcomm", v850_comm, AREA_ZDA}, - {"scomm", v850_comm, AREA_SDA}, - {"tcomm", v850_comm, AREA_TDA}, - {"v850", set_machine, 0}, - {"call_table_data", v850_call_table_data, 0}, - {"call_table_text", v850_call_table_text, 0}, - {"v850e", set_machine, bfd_mach_v850e}, - {"v850ea", set_machine, bfd_mach_v850ea}, - { NULL, NULL, 0} -}; - -/* Opcode hash table. */ -static struct hash_control *v850_hash; - -/* This table is sorted. Suitable for searching by a binary search. */ -static const struct reg_name pre_defined_registers[] = -{ - { "ep", 30 }, /* ep - element ptr */ - { "gp", 4 }, /* gp - global ptr */ - { "hp", 2 }, /* hp - handler stack ptr */ - { "lp", 31 }, /* lp - link ptr */ - { "r0", 0 }, - { "r1", 1 }, - { "r10", 10 }, - { "r11", 11 }, - { "r12", 12 }, - { "r13", 13 }, - { "r14", 14 }, - { "r15", 15 }, - { "r16", 16 }, - { "r17", 17 }, - { "r18", 18 }, - { "r19", 19 }, - { "r2", 2 }, - { "r20", 20 }, - { "r21", 21 }, - { "r22", 22 }, - { "r23", 23 }, - { "r24", 24 }, - { "r25", 25 }, - { "r26", 26 }, - { "r27", 27 }, - { "r28", 28 }, - { "r29", 29 }, - { "r3", 3 }, - { "r30", 30 }, - { "r31", 31 }, - { "r4", 4 }, - { "r5", 5 }, - { "r6", 6 }, - { "r7", 7 }, - { "r8", 8 }, - { "r9", 9 }, - { "sp", 3 }, /* sp - stack ptr */ - { "tp", 5 }, /* tp - text ptr */ - { "zero", 0 }, -}; -#define REG_NAME_CNT (sizeof (pre_defined_registers) / sizeof (struct reg_name)) - - -static const struct reg_name system_registers[] = -{ - { "ctbp", 20 }, - { "ctpc", 16 }, - { "ctpsw", 17 }, - { "dbpc", 18 }, - { "dbpsw", 19 }, - { "ecr", 4 }, - { "eipc", 0 }, - { "eipsw", 1 }, - { "fepc", 2 }, - { "fepsw", 3 }, - { "psw", 5 }, -}; -#define SYSREG_NAME_CNT (sizeof (system_registers) / sizeof (struct reg_name)) - -static const struct reg_name system_list_registers[] = -{ - {"PS", 5 }, - {"SR", 0 + 1} -}; -#define SYSREGLIST_NAME_CNT (sizeof (system_list_registers) / sizeof (struct reg_name)) - -static const struct reg_name cc_names[] = -{ - { "c", 0x1 }, - { "e", 0x2 }, - { "ge", 0xe }, - { "gt", 0xf }, - { "h", 0xb }, - { "l", 0x1 }, - { "le", 0x7 }, - { "lt", 0x6 }, - { "n", 0x4 }, - { "nc", 0x9 }, - { "ne", 0xa }, - { "nh", 0x3 }, - { "nl", 0x9 }, - { "ns", 0xc }, - { "nv", 0x8 }, - { "nz", 0xa }, - { "p", 0xc }, - { "s", 0x4 }, - { "sa", 0xd }, - { "t", 0x5 }, - { "v", 0x0 }, - { "z", 0x2 }, -}; -#define CC_NAME_CNT (sizeof (cc_names) / sizeof (struct reg_name)) - -/* reg_name_search does a binary search of the given register table - to see if "name" is a valid regiter name. Returns the register - number from the array on success, or -1 on failure. */ - -static int -reg_name_search (regs, regcount, name, accept_numbers) - const struct reg_name * regs; - int regcount; - const char * name; - boolean accept_numbers; -{ - int middle, low, high; - int cmp; - symbolS * symbolP; - - /* If the register name is a symbol, then evaluate it. */ - if ((symbolP = symbol_find (name)) != NULL) - { - /* If the symbol is an alias for another name then use that. - If the symbol is an alias for a number, then return the number. */ - if (symbol_equated_p (symbolP)) - { - name = S_GET_NAME (symbol_get_value_expression (symbolP)->X_add_symbol); - } - else if (accept_numbers) - { - int reg = S_GET_VALUE (symbolP); - - if (reg >= 0 && reg <= 31) - return reg; - } - - /* Otherwise drop through and try parsing name normally. */ - } - - low = 0; - high = regcount - 1; - - do - { - middle = (low + high) / 2; - cmp = strcasecmp (name, regs[middle].name); - if (cmp < 0) - high = middle - 1; - else if (cmp > 0) - low = middle + 1; - else - return regs[middle].value; - } - while (low <= high); - return -1; -} - - -/* Summary of register_name(). - * - * in: Input_line_pointer points to 1st char of operand. - * - * out: A expressionS. - * The operand may have been a register: in this case, X_op == O_register, - * X_add_number is set to the register number, and truth is returned. - * Input_line_pointer->(next non-blank) char after operand, or is in - * its original state. - */ -static boolean -register_name (expressionP) - expressionS * expressionP; -{ - int reg_number; - char * name; - char * start; - char c; - - /* Find the spelling of the operand */ - start = name = input_line_pointer; - - c = get_symbol_end (); - - reg_number = reg_name_search (pre_defined_registers, REG_NAME_CNT, - name, FALSE); - - * input_line_pointer = c; /* put back the delimiting char */ - - /* look to see if it's in the register table */ - if (reg_number >= 0) - { - expressionP->X_op = O_register; - expressionP->X_add_number = reg_number; - - /* make the rest nice */ - expressionP->X_add_symbol = NULL; - expressionP->X_op_symbol = NULL; - - return true; - } - else - { - /* reset the line as if we had not done anything */ - input_line_pointer = start; - - return false; - } -} - -/* Summary of system_register_name(). - * - * in: Input_line_pointer points to 1st char of operand. - * expressionP points to an expression structure to be filled in. - * accept_numbers is true iff numerical register names may be used. - * accept_list_names is true iff the special names PS and SR may be - * accepted. - * - * out: A expressionS structure in expressionP. - * The operand may have been a register: in this case, X_op == O_register, - * X_add_number is set to the register number, and truth is returned. - * Input_line_pointer->(next non-blank) char after operand, or is in - * its original state. - */ -static boolean -system_register_name (expressionP, accept_numbers, accept_list_names) - expressionS * expressionP; - boolean accept_numbers; - boolean accept_list_names; -{ - int reg_number; - char * name; - char * start; - char c; - - /* Find the spelling of the operand */ - start = name = input_line_pointer; - - c = get_symbol_end (); - reg_number = reg_name_search (system_registers, SYSREG_NAME_CNT, name, - accept_numbers); - - * input_line_pointer = c; /* put back the delimiting char */ - - if (reg_number < 0 - && accept_numbers) - { - input_line_pointer = start; /* reset input_line pointer */ - - if (isdigit (* input_line_pointer)) - { - reg_number = strtol (input_line_pointer, & input_line_pointer, 10); - - /* Make sure that the register number is allowable. */ - if ( reg_number < 0 - || reg_number > 5 - && reg_number < 16 - || reg_number > 20 - ) - { - reg_number = -1; - } - } - else if (accept_list_names) - { - c = get_symbol_end (); - reg_number = reg_name_search (system_list_registers, - SYSREGLIST_NAME_CNT, name, FALSE); - - * input_line_pointer = c; /* put back the delimiting char */ - } - } - - /* look to see if it's in the register table */ - if (reg_number >= 0) - { - expressionP->X_op = O_register; - expressionP->X_add_number = reg_number; - - /* make the rest nice */ - expressionP->X_add_symbol = NULL; - expressionP->X_op_symbol = NULL; - - return true; - } - else - { - /* reset the line as if we had not done anything */ - input_line_pointer = start; - - return false; - } -} - -/* Summary of cc_name(). - * - * in: Input_line_pointer points to 1st char of operand. - * - * out: A expressionS. - * The operand may have been a register: in this case, X_op == O_register, - * X_add_number is set to the register number, and truth is returned. - * Input_line_pointer->(next non-blank) char after operand, or is in - * its original state. - */ -static boolean -cc_name (expressionP) - expressionS * expressionP; -{ - int reg_number; - char * name; - char * start; - char c; - - /* Find the spelling of the operand */ - start = name = input_line_pointer; - - c = get_symbol_end (); - reg_number = reg_name_search (cc_names, CC_NAME_CNT, name, FALSE); - - * input_line_pointer = c; /* put back the delimiting char */ - - /* look to see if it's in the register table */ - if (reg_number >= 0) - { - expressionP->X_op = O_constant; - expressionP->X_add_number = reg_number; - - /* make the rest nice */ - expressionP->X_add_symbol = NULL; - expressionP->X_op_symbol = NULL; - - return true; - } - else - { - /* reset the line as if we had not done anything */ - input_line_pointer = start; - - return false; - } -} - -static void -skip_white_space (void) -{ - while ( * input_line_pointer == ' ' - || * input_line_pointer == '\t') - ++ input_line_pointer; -} - -/* Summary of parse_register_list (). - * - * in: Input_line_pointer points to 1st char of a list of registers. - * insn is the partially constructed instruction. - * operand is the operand being inserted. - * - * out: NULL if the parse completed successfully, otherwise a - * pointer to an error message is returned. If the parse - * completes the correct bit fields in the instruction - * will be filled in. - * - * Parses register lists with the syntax: - * - * { rX } - * { rX, rY } - * { rX - rY } - * { rX - rY, rZ } - * etc - * - * and also parses constant epxressions whoes bits indicate the - * registers in the lists. The LSB in the expression refers to - * the lowest numbered permissable register in the register list, - * and so on upwards. System registers are considered to be very - * high numbers. - * - */ -static char * -parse_register_list -( - unsigned long * insn, - const struct v850_operand * operand -) -{ - static int type1_regs[ 32 ] = { 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 29, 28, 23, 22, 21, 20, 27, 26, 25, 24 }; - static int type2_regs[ 32 ] = { 19, 18, 17, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 31, 29, 28, 23, 22, 21, 20, 27, 26, 25, 24 }; - static int type3_regs[ 32 ] = { 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 15, 13, 12, 7, 6, 5, 4, 11, 10, 9, 8 }; - int * regs; - expressionS exp; - - - /* Select a register array to parse. */ - switch (operand->shift) - { - case 0xffe00001: regs = type1_regs; break; - case 0xfff8000f: regs = type2_regs; break; - case 0xfff8001f: regs = type3_regs; break; - default: - as_bad (_("unknown operand shift: %x\n"), operand->shift); - return _("internal failure in parse_register_list"); - } - - skip_white_space (); - - /* If the expression starts with a curly brace it is a register list. - Otherwise it is a constant expression, whoes bits indicate which - registers are to be included in the list. */ - - if (* input_line_pointer != '{') - { - int bits; - int reg; - int i; - - expression (& exp); - - if (exp.X_op != O_constant) - return _("constant expression or register list expected"); - - if (regs == type1_regs) - { - if (exp.X_add_number & 0xFFFFF000) - return _("high bits set in register list expression"); - - for (reg = 20; reg < 32; reg ++) - if (exp.X_add_number & (1 << (reg - 20))) - { - for (i = 0; i < 32; i++) - if (regs[i] == reg) - * insn |= (1 << i); - } - } - else if (regs == type2_regs) - { - if (exp.X_add_number & 0xFFFE0000) - return _("high bits set in register list expression"); - - for (reg = 1; reg < 16; reg ++) - if (exp.X_add_number & (1 << (reg - 1))) - { - for (i = 0; i < 32; i++) - if (regs[i] == reg) - * insn |= (1 << i); - } - - if (exp.X_add_number & (1 << 15)) - * insn |= (1 << 3); - - if (exp.X_add_number & (1 << 16)) - * insn |= (1 << 19); - } - else /* regs == type3_regs */ - { - if (exp.X_add_number & 0xFFFE0000) - return _("high bits set in register list expression"); - - for (reg = 16; reg < 32; reg ++) - if (exp.X_add_number & (1 << (reg - 16))) - { - for (i = 0; i < 32; i++) - if (regs[i] == reg) - * insn |= (1 << i); - } - - if (exp.X_add_number & (1 << 16)) - * insn |= (1 << 19); - } - - return NULL; - } - - input_line_pointer ++; - - /* Parse the register list until a terminator (closing curly brace or - new-line) is found. */ - for (;;) - { - if (register_name (& exp)) - { - int i; - - /* Locate the given register in the list, and if it is there, - insert the corresponding bit into the instruction. */ - for (i = 0; i < 32; i++) - { - if (regs[ i ] == exp.X_add_number) - { - * insn |= (1 << i); - break; - } - } - - if (i == 32) - { - return _("illegal register included in list"); - } - } - else if (system_register_name (& exp, true, true)) - { - if (regs == type1_regs) - { - return _("system registers cannot be included in list"); - } - else if (exp.X_add_number == 5) - { - if (regs == type2_regs) - return _("PSW cannot be included in list"); - else - * insn |= 0x8; - } - else if (exp.X_add_number < 4) - * insn |= 0x80000; - else - return _("High value system registers cannot be included in list"); - } - else if (* input_line_pointer == '}') - { - input_line_pointer ++; - break; - } - else if (* input_line_pointer == ',') - { - input_line_pointer ++; - continue; - } - else if (* input_line_pointer == '-') - { - /* We have encountered a range of registers: rX - rY */ - int j; - expressionS exp2; - - /* Skip the dash. */ - ++ input_line_pointer; - - /* Get the second register in the range. */ - if (! register_name (& exp2)) - { - return _("second register should follow dash in register list"); - exp2.X_add_number = exp.X_add_number; - } - - /* Add the rest of the registers in the range. */ - for (j = exp.X_add_number + 1; j <= exp2.X_add_number; j++) - { - int i; - - /* Locate the given register in the list, and if it is there, - insert the corresponding bit into the instruction. */ - for (i = 0; i < 32; i++) - { - if (regs[ i ] == j) - { - * insn |= (1 << i); - break; - } - } - - if (i == 32) - return _("illegal register included in list"); - } - } - else - { - break; - } - - skip_white_space (); - } - - return NULL; -} - -CONST char * md_shortopts = "m:"; - -struct option md_longopts[] = -{ - {NULL, no_argument, NULL, 0} -}; -size_t md_longopts_size = sizeof md_longopts; - - -void -md_show_usage (stream) - FILE * stream; -{ - fprintf (stream, _(" V850 options:\n")); - fprintf (stream, _(" -mwarn-signed-overflow Warn if signed immediate values overflow\n")); - fprintf (stream, _(" -mwarn-unsigned-overflow Warn if unsigned immediate values overflow\n")); - fprintf (stream, _(" -mv850 The code is targeted at the v850\n")); - fprintf (stream, _(" -mv850e The code is targeted at the v850e\n")); - fprintf (stream, _(" -mv850ea The code is targeted at the v850ea\n")); - fprintf (stream, _(" -mv850any The code is generic, despite any processor specific instructions\n")); -} - -int -md_parse_option (c, arg) - int c; - char * arg; -{ - if (c != 'm') - { - /* xgettext:c-format */ - fprintf (stderr, _("unknown command line option: -%c%s\n"), c, arg); - return 0; - } - - if (strcmp (arg, "warn-signed-overflow") == 0) - { - warn_signed_overflows = TRUE; - } - else if (strcmp (arg, "warn-unsigned-overflow") == 0) - { - warn_unsigned_overflows = TRUE; - } - else if (strcmp (arg, "v850") == 0) - { - machine = 0; - processor_mask = PROCESSOR_V850; - } - else if (strcmp (arg, "v850e") == 0) - { - machine = bfd_mach_v850e; - processor_mask = PROCESSOR_V850E; - } - else if (strcmp (arg, "v850ea") == 0) - { - machine = bfd_mach_v850ea; - processor_mask = PROCESSOR_V850EA; - } - else if (strcmp (arg, "v850any") == 0) - { - machine = 0; /* Tell the world that this is for any v850 chip. */ - processor_mask = PROCESSOR_V850EA; /* But support instructions for the extended versions. */ - } - else - { - /* xgettext:c-format */ - fprintf (stderr, _("unknown command line option: -%c%s\n"), c, arg); - return 0; - } - - return 1; -} - -symbolS * -md_undefined_symbol (name) - char * name; -{ - return 0; -} - -char * -md_atof (type, litp, sizep) - int type; - char * litp; - int * sizep; -{ - int prec; - LITTLENUM_TYPE words[4]; - char * t; - int i; - - switch (type) - { - case 'f': - prec = 2; - break; - - case 'd': - prec = 4; - break; - - default: - *sizep = 0; - return _("bad call to md_atof"); - } - - t = atof_ieee (input_line_pointer, type, words); - if (t) - input_line_pointer = t; - - *sizep = prec * 2; - - for (i = prec - 1; i >= 0; i--) - { - md_number_to_chars (litp, (valueT) words[i], 2); - litp += 2; - } - - return NULL; -} - - -/* Very gross. */ -void -md_convert_frag (abfd, sec, fragP) - bfd * abfd; - asection * sec; - fragS * fragP; -{ - subseg_change (sec, 0); - - /* In range conditional or unconditional branch. */ - if (fragP->fr_subtype == 0 || fragP->fr_subtype == 2) - { - fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, - fragP->fr_offset, 1, BFD_RELOC_UNUSED + (int)fragP->fr_opcode); - fragP->fr_var = 0; - fragP->fr_fix += 2; - } - /* Out of range conditional branch. Emit a branch around a jump. */ - else if (fragP->fr_subtype == 1) - { - unsigned char *buffer = - (unsigned char *) (fragP->fr_fix + fragP->fr_literal); - - /* Reverse the condition of the first branch. */ - buffer[0] ^= 0x08; - /* Mask off all the displacement bits. */ - buffer[0] &= 0x8f; - buffer[1] &= 0x07; - /* Now set the displacement bits so that we branch - around the unconditional branch. */ - buffer[0] |= 0x30; - - /* Now create the unconditional branch + fixup to the final - target. */ - md_number_to_chars (buffer + 2, 0x00000780, 4); - fix_new (fragP, fragP->fr_fix + 2, 4, fragP->fr_symbol, - fragP->fr_offset, 1, BFD_RELOC_UNUSED + - (int) fragP->fr_opcode + 1); - fragP->fr_var = 0; - fragP->fr_fix += 6; - } - /* Out of range unconditional branch. Emit a jump. */ - else if (fragP->fr_subtype == 3) - { - md_number_to_chars (fragP->fr_fix + fragP->fr_literal, 0x00000780, 4); - fix_new (fragP, fragP->fr_fix, 4, fragP->fr_symbol, - fragP->fr_offset, 1, BFD_RELOC_UNUSED + - (int) fragP->fr_opcode + 1); - fragP->fr_var = 0; - fragP->fr_fix += 4; - } - else - abort (); -} - -valueT -md_section_align (seg, addr) - asection * seg; - valueT addr; -{ - int align = bfd_get_section_alignment (stdoutput, seg); - return ((addr + (1 << align) - 1) & (-1 << align)); -} - -void -md_begin () -{ - char * prev_name = ""; - register const struct v850_opcode * op; - flagword applicable; - - if (strncmp (TARGET_CPU, "v850ea", 6) == 0) - { - if (machine == -1) - machine = bfd_mach_v850ea; - - if (processor_mask == -1) - processor_mask = PROCESSOR_V850EA; - } - else if (strncmp (TARGET_CPU, "v850e", 5) == 0) - { - if (machine == -1) - machine = bfd_mach_v850e; - - if (processor_mask == -1) - processor_mask = PROCESSOR_V850E; - } - else - if (strncmp (TARGET_CPU, "v850", 4) == 0) - { - if (machine == -1) - machine = 0; - - if (processor_mask == -1) - processor_mask = PROCESSOR_V850; - } - else - /* xgettext:c-format */ - as_bad (_("Unable to determine default target processor from string: %s"), - TARGET_CPU); - - v850_hash = hash_new(); - - /* Insert unique names into hash table. The V850 instruction set - has many identical opcode names that have different opcodes based - on the operands. This hash table then provides a quick index to - the first opcode with a particular name in the opcode table. */ - - op = v850_opcodes; - while (op->name) - { - if (strcmp (prev_name, op->name)) - { - prev_name = (char *) op->name; - hash_insert (v850_hash, op->name, (char *) op); - } - op++; - } - - bfd_set_arch_mach (stdoutput, TARGET_ARCH, machine); - - applicable = bfd_applicable_section_flags (stdoutput); - - call_table_data_section = subseg_new (".call_table_data", 0); - bfd_set_section_flags (stdoutput, call_table_data_section, - applicable & (SEC_ALLOC | SEC_LOAD | SEC_RELOC - | SEC_DATA | SEC_HAS_CONTENTS)); - - call_table_text_section = subseg_new (".call_table_text", 0); - bfd_set_section_flags (stdoutput, call_table_text_section, - applicable & (SEC_ALLOC | SEC_LOAD | SEC_READONLY - | SEC_CODE)); - - /* Restore text section as the current default. */ - subseg_set (text_section, 0); -} - - -static bfd_reloc_code_real_type -handle_ctoff (const struct v850_operand * operand) -{ - if (operand == NULL) - return BFD_RELOC_V850_CALLT_16_16_OFFSET; - - if ( operand->bits != 6 - || operand->shift != 0) - { - as_bad (_("ctoff() relocation used on an instruction which does not support it")); - return BFD_RELOC_64; /* Used to indicate an error condition. */ - } - - return BFD_RELOC_V850_CALLT_6_7_OFFSET; -} - -static bfd_reloc_code_real_type -handle_sdaoff (const struct v850_operand * operand) -{ - if (operand == NULL) return BFD_RELOC_V850_SDA_16_16_OFFSET; - if (operand->bits == 15 && operand->shift == 17) return BFD_RELOC_V850_SDA_15_16_OFFSET; - if (operand->bits == -1) return BFD_RELOC_V850_SDA_16_16_SPLIT_OFFSET; - - if ( operand->bits != 16 - || operand->shift != 16) - { - as_bad (_("sdaoff() relocation used on an instruction which does not support it")); - return BFD_RELOC_64; /* Used to indicate an error condition. */ - } - - return BFD_RELOC_V850_SDA_16_16_OFFSET; -} - -static bfd_reloc_code_real_type -handle_zdaoff (const struct v850_operand * operand) -{ - if (operand == NULL) return BFD_RELOC_V850_ZDA_16_16_OFFSET; - if (operand->bits == 15 && operand->shift == 17) return BFD_RELOC_V850_ZDA_15_16_OFFSET; - if (operand->bits == -1) return BFD_RELOC_V850_ZDA_16_16_SPLIT_OFFSET; - - if ( operand->bits != 16 - || operand->shift != 16) - { - as_bad (_("zdaoff() relocation used on an instruction which does not support it")); - return BFD_RELOC_64; /* Used to indicate an error condition. */ - } - - return BFD_RELOC_V850_ZDA_16_16_OFFSET; -} - -static bfd_reloc_code_real_type -handle_tdaoff (const struct v850_operand * operand) -{ - if (operand == NULL) return BFD_RELOC_V850_TDA_7_7_OFFSET; /* data item, not an instruction. */ - if (operand->bits == 6 && operand->shift == 1) return BFD_RELOC_V850_TDA_6_8_OFFSET; /* sld.w/sst.w, operand: D8_6 */ - if (operand->bits == 4 && operand->insert != NULL) return BFD_RELOC_V850_TDA_4_5_OFFSET; /* sld.hu, operand: D5-4 */ - if (operand->bits == 4 && operand->insert == NULL) return BFD_RELOC_V850_TDA_4_4_OFFSET; /* sld.bu, operand: D4 */ - if (operand->bits == 16 && operand->shift == 16) return BFD_RELOC_V850_TDA_16_16_OFFSET; /* set1 & chums, operands: D16 */ - - if (operand->bits != 7) - { - as_bad (_("tdaoff() relocation used on an instruction which does not support it")); - return BFD_RELOC_64; /* Used to indicate an error condition. */ - } - - return operand->insert != NULL - ? BFD_RELOC_V850_TDA_7_8_OFFSET /* sld.h/sst.h, operand: D8_7 */ - : BFD_RELOC_V850_TDA_7_7_OFFSET; /* sld.b/sst.b, opreand: D7 */ -} - -/* Warning: The code in this function relies upon the definitions - in the v850_operands[] array (defined in opcodes/v850-opc.c) - matching the hard coded values contained herein. */ - -static bfd_reloc_code_real_type -v850_reloc_prefix (const struct v850_operand * operand) -{ - boolean paren_skipped = false; - - - /* Skip leading opening parenthesis. */ - if (* input_line_pointer == '(') - { - ++ input_line_pointer; - paren_skipped = true; - } - -#define CHECK_(name, reloc) \ - if (strncmp (input_line_pointer, name##"(", strlen (name) + 1) == 0) \ - { \ - input_line_pointer += strlen (name); \ - return reloc; \ - } - - CHECK_ ("hi0", BFD_RELOC_HI16); - CHECK_ ("hi", BFD_RELOC_HI16_S); - CHECK_ ("lo", BFD_RELOC_LO16); - CHECK_ ("sdaoff", handle_sdaoff (operand)); - CHECK_ ("zdaoff", handle_zdaoff (operand)); - CHECK_ ("tdaoff", handle_tdaoff (operand)); - CHECK_ ("hilo", BFD_RELOC_32); - CHECK_ ("ctoff", handle_ctoff (operand)); - - /* Restore skipped parenthesis. */ - if (paren_skipped) - -- input_line_pointer; - - return BFD_RELOC_UNUSED; -} - -/* Insert an operand value into an instruction. */ - -static unsigned long -v850_insert_operand (insn, operand, val, file, line, str) - unsigned long insn; - const struct v850_operand * operand; - offsetT val; - char * file; - unsigned int line; - char * str; -{ - if (operand->insert) - { - const char * message = NULL; - - insn = operand->insert (insn, val, & message); - if (message != NULL) - { - if ((operand->flags & V850_OPERAND_SIGNED) - && ! warn_signed_overflows - && strstr (message, "out of range") != NULL) - { - /* skip warning... */ - } - else if ((operand->flags & V850_OPERAND_SIGNED) == 0 - && ! warn_unsigned_overflows - && strstr (message, "out of range") != NULL) - { - /* skip warning... */ - } - else if (str) - { - if (file == (char *) NULL) - as_warn ("%s: %s", str, message); - else - as_warn_where (file, line, "%s: %s", str, message); - } - else - { - if (file == (char *) NULL) - as_warn (message); - else - as_warn_where (file, line, message); - } - } - } - else - { - if (operand->bits != 32) - { - long min, max; - offsetT test; - - if ((operand->flags & V850_OPERAND_SIGNED) != 0) - { - if (! warn_signed_overflows) - max = (1 << operand->bits) - 1; - else - max = (1 << (operand->bits - 1)) - 1; - - min = - (1 << (operand->bits - 1)); - } - else - { - max = (1 << operand->bits) - 1; - - if (! warn_unsigned_overflows) - min = - (1 << (operand->bits - 1)); - else - min = 0; - } - - if (val < (offsetT) min || val > (offsetT) max) - { - /* xgettext:c-format */ - const char * err = _("operand out of range (%s not between %ld and %ld)"); - char buf[100]; - - /* Restore min and mix to expected values for decimal ranges. */ - if ((operand->flags & V850_OPERAND_SIGNED) - && ! warn_signed_overflows) - max = (1 << (operand->bits - 1)) - 1; - - if (! (operand->flags & V850_OPERAND_SIGNED) - && ! warn_unsigned_overflows) - min = 0; - - if (str) - { - sprintf (buf, "%s: ", str); - - sprint_value (buf + strlen (buf), val); - } - else - sprint_value (buf, val); - - if (file == (char *) NULL) - as_warn (err, buf, min, max); - else - as_warn_where (file, line, err, buf, min, max); - } - } - - insn |= (((long) val & ((1 << operand->bits) - 1)) << operand->shift); - } - - return insn; -} - - -static char copy_of_instruction [128]; - -void -md_assemble (str) - char * str; -{ - char * s; - char * start_of_operands; - struct v850_opcode * opcode; - struct v850_opcode * next_opcode; - const unsigned char * opindex_ptr; - int next_opindex; - int relaxable; - unsigned long insn; - unsigned long insn_size; - char * f; - int i; - int match; - boolean extra_data_after_insn = false; - unsigned extra_data_len; - unsigned long extra_data; - char * saved_input_line_pointer; - - - strncpy (copy_of_instruction, str, sizeof (copy_of_instruction) - 1); - - /* Get the opcode. */ - for (s = str; *s != '\0' && ! isspace (*s); s++) - continue; - - if (*s != '\0') - *s++ = '\0'; - - /* find the first opcode with the proper name */ - opcode = (struct v850_opcode *) hash_find (v850_hash, str); - if (opcode == NULL) - { - /* xgettext:c-format */ - as_bad (_("Unrecognized opcode: `%s'"), str); - ignore_rest_of_line (); - return; - } - - str = s; - while (isspace (* str)) - ++ str; - - start_of_operands = str; - - saved_input_line_pointer = input_line_pointer; - - for (;;) - { - const char * errmsg = NULL; - - match = 0; - - if ((opcode->processors & processor_mask) == 0) - { - errmsg = _("Target processor does not support this instruction."); - goto error; - } - - relaxable = 0; - fc = 0; - next_opindex = 0; - insn = opcode->opcode; - extra_data_after_insn = false; - - input_line_pointer = str = start_of_operands; - - for (opindex_ptr = opcode->operands; *opindex_ptr != 0; opindex_ptr ++) - { - const struct v850_operand * operand; - char * hold; - expressionS ex; - bfd_reloc_code_real_type reloc; - - if (next_opindex == 0) - { - operand = & v850_operands[ * opindex_ptr ]; - } - else - { - operand = & v850_operands[ next_opindex ]; - next_opindex = 0; - } - - errmsg = NULL; - - while (*str == ' ' || *str == ',' || *str == '[' || *str == ']') - ++ str; - - if (operand->flags & V850_OPERAND_RELAX) - relaxable = 1; - - /* Gather the operand. */ - hold = input_line_pointer; - input_line_pointer = str; - - /* lo(), hi(), hi0(), etc... */ - if ((reloc = v850_reloc_prefix (operand)) != BFD_RELOC_UNUSED) - { - /* This is a fake reloc, used to indicate an error condition. */ - if (reloc == BFD_RELOC_64) - { - match = 1; - goto error; - } - - expression (& ex); - - if (ex.X_op == O_constant) - { - switch (reloc) - { - case BFD_RELOC_V850_ZDA_16_16_OFFSET: - /* To cope with "not1 7, zdaoff(0xfffff006)[r0]" - and the like. */ - /* Fall through. */ - - case BFD_RELOC_LO16: - { - /* Truncate, then sign extend the value. */ - ex.X_add_number = SEXT16 (ex.X_add_number); - break; - } - - case BFD_RELOC_HI16: - { - /* Truncate, then sign extend the value. */ - ex.X_add_number = SEXT16 (ex.X_add_number >> 16); - break; - } - - case BFD_RELOC_HI16_S: - { - /* Truncate, then sign extend the value. */ - int temp = (ex.X_add_number >> 16) & 0xffff; - - temp += (ex.X_add_number >> 15) & 1; - - ex.X_add_number = SEXT16 (temp); - break; - } - - case BFD_RELOC_32: - if ((operand->flags & V850E_IMMEDIATE32) == 0) - { - errmsg = _("immediate operand is too large"); - goto error; - } - - extra_data_after_insn = true; - extra_data_len = 4; - extra_data = ex.X_add_number; - ex.X_add_number = 0; - break; - - default: - fprintf (stderr, "reloc: %d\n", reloc); - as_bad (_("AAARG -> unhandled constant reloc")); - break; - } - - if (fc > MAX_INSN_FIXUPS) - as_fatal (_("too many fixups")); - - fixups[ fc ].exp = ex; - fixups[ fc ].opindex = * opindex_ptr; - fixups[ fc ].reloc = reloc; - fc++; - } - else - { - if (reloc == BFD_RELOC_32) - { - if ((operand->flags & V850E_IMMEDIATE32) == 0) - { - errmsg = _("immediate operand is too large"); - goto error; - } - - extra_data_after_insn = true; - extra_data_len = 4; - extra_data = ex.X_add_number; - } - - if (fc > MAX_INSN_FIXUPS) - as_fatal (_("too many fixups")); - - fixups[ fc ].exp = ex; - fixups[ fc ].opindex = * opindex_ptr; - fixups[ fc ].reloc = reloc; - fc++; - } - } - else - { - errmsg = NULL; - - if ((operand->flags & V850_OPERAND_REG) != 0) - { - if (!register_name (& ex)) - { - errmsg = _("invalid register name"); - } - else if ((operand->flags & V850_NOT_R0) - && ex.X_add_number == 0) - { - errmsg = _("register r0 cannot be used here"); - - /* Force an error message to be generated by - skipping over any following potential matches - for this opcode. */ - opcode += 3; - } - } - else if ((operand->flags & V850_OPERAND_SRG) != 0) - { - if (!system_register_name (& ex, true, false)) - { - errmsg = _("invalid system register name"); - } - } - else if ((operand->flags & V850_OPERAND_EP) != 0) - { - char * start = input_line_pointer; - char c = get_symbol_end (); - - if (strcmp (start, "ep") != 0 && strcmp (start, "r30") != 0) - { - /* Put things back the way we found them. */ - *input_line_pointer = c; - input_line_pointer = start; - errmsg = _("expected EP register"); - goto error; - } - - *input_line_pointer = c; - str = input_line_pointer; - input_line_pointer = hold; - - while (*str == ' ' || *str == ',' || *str == '[' || *str == ']') - ++ str; - continue; - } - else if ((operand->flags & V850_OPERAND_CC) != 0) - { - if (!cc_name (& ex)) - { - errmsg = _("invalid condition code name"); - } - } - else if (operand->flags & V850E_PUSH_POP) - { - errmsg = parse_register_list (& insn, operand); - - /* The parse_register_list() function has already done - everything, so fake a dummy expression. */ - ex.X_op = O_constant; - ex.X_add_number = 0; - } - else if (operand->flags & V850E_IMMEDIATE16) - { - expression (& ex); - - if (ex.X_op != O_constant) - errmsg = _("constant expression expected"); - else if (ex.X_add_number & 0xffff0000) - { - if (ex.X_add_number & 0xffff) - errmsg = _("constant too big to fit into instruction"); - else if ((insn & 0x001fffc0) == 0x00130780) - ex.X_add_number >>= 16; - else - errmsg = _("constant too big to fit into instruction"); - } - - extra_data_after_insn = true; - extra_data_len = 2; - extra_data = ex.X_add_number; - ex.X_add_number = 0; - } - else if (operand->flags & V850E_IMMEDIATE32) - { - expression (& ex); - - if (ex.X_op != O_constant) - errmsg = _("constant expression expected"); - - extra_data_after_insn = true; - extra_data_len = 4; - extra_data = ex.X_add_number; - ex.X_add_number = 0; - } - else if (register_name (& ex) - && (operand->flags & V850_OPERAND_REG) == 0) - { - char c; - int exists = 0; - - /* It is possible that an alias has been defined that - matches a register name. For example the code may - include a ".set ZERO, 0" directive, which matches - the register name "zero". Attempt to reparse the - field as an expression, and only complain if we - cannot generate a constant. */ - - input_line_pointer = str; - - c = get_symbol_end (); - - if (symbol_find (str) != NULL) - exists = 1; - - * input_line_pointer = c; - input_line_pointer = str; - - expression (& ex); - - if (ex.X_op != O_constant) - { - /* If this register is actually occuring too early on - the parsing of the instruction, (because another - field is missing) then report this. */ - if (opindex_ptr[1] != 0 - && (v850_operands [opindex_ptr [1]].flags & V850_OPERAND_REG)) - errmsg = _("syntax error: value is missing before the register name"); - else - errmsg = _("syntax error: register not expected"); - - /* If we created a symbol in the process of this test then - delete it now, so that it will not be output with the real - symbols... */ - if (exists == 0 - && ex.X_op == O_symbol) - symbol_remove (ex.X_add_symbol, - & symbol_rootP, & symbol_lastP); - } - } - else if (system_register_name (& ex, false, false) - && (operand->flags & V850_OPERAND_SRG) == 0) - { - errmsg = _("syntax error: system register not expected"); - } - else if (cc_name (&ex) - && (operand->flags & V850_OPERAND_CC) == 0) - { - errmsg = _("syntax error: condition code not expected"); - } - else - { - expression (& ex); - /* Special case: - If we are assembling a MOV instruction (or a CALLT.... :-) - and the immediate value does not fit into the bits - available then create a fake error so that the next MOV - instruction will be selected. This one has a 32 bit - immediate field. */ - - if (((insn & 0x07e0) == 0x0200) - && ex.X_op == O_constant - && (ex.X_add_number < (- (1 << (operand->bits - 1))) - || ex.X_add_number > ((1 << operand->bits) - 1))) - errmsg = _("immediate operand is too large"); - } - - if (errmsg) - goto error; - -/* fprintf (stderr, " insn: %x, operand %d, op: %d, add_number: %d\n", - insn, opindex_ptr - opcode->operands, ex.X_op, ex.X_add_number); */ - - switch (ex.X_op) - { - case O_illegal: - errmsg = _("illegal operand"); - goto error; - case O_absent: - errmsg = _("missing operand"); - goto error; - case O_register: - if ((operand->flags & (V850_OPERAND_REG | V850_OPERAND_SRG)) == 0) - { - errmsg = _("invalid operand"); - goto error; - } - insn = v850_insert_operand (insn, operand, ex.X_add_number, - (char *) NULL, 0, - copy_of_instruction); - break; - - case O_constant: - insn = v850_insert_operand (insn, operand, ex.X_add_number, - (char *) NULL, 0, - copy_of_instruction); - break; - - default: - /* We need to generate a fixup for this expression. */ - if (fc >= MAX_INSN_FIXUPS) - as_fatal (_("too many fixups")); - - fixups[ fc ].exp = ex; - fixups[ fc ].opindex = * opindex_ptr; - fixups[ fc ].reloc = BFD_RELOC_UNUSED; - ++fc; - break; - } - } - - str = input_line_pointer; - input_line_pointer = hold; - - while (*str == ' ' || *str == ',' || *str == '[' || *str == ']' - || *str == ')') - ++str; - } - match = 1; - - error: - if (match == 0) - { - next_opcode = opcode + 1; - if (next_opcode->name != NULL - && strcmp (next_opcode->name, opcode->name) == 0) - { - opcode = next_opcode; - - /* Skip versions that are not supported by the target - processor. */ - if ((opcode->processors & processor_mask) == 0) - goto error; - - continue; - } - - as_bad ("%s: %s", copy_of_instruction, errmsg); - - if (* input_line_pointer == ']') - ++ input_line_pointer; - - ignore_rest_of_line (); - input_line_pointer = saved_input_line_pointer; - return; - } - break; - } - - while (isspace (*str)) - ++str; - - if (*str != '\0') - /* xgettext:c-format */ - as_bad (_("junk at end of line: `%s'"), str); - - input_line_pointer = str; - - /* Write out the instruction. */ - - if (relaxable && fc > 0) - { - insn_size = 2; - fc = 0; - - if (!strcmp (opcode->name, "br")) - { - f = frag_var (rs_machine_dependent, 4, 2, 2, - fixups[0].exp.X_add_symbol, - fixups[0].exp.X_add_number, - (char *)fixups[0].opindex); - md_number_to_chars (f, insn, insn_size); - md_number_to_chars (f + 2, 0, 2); - } - else - { - f = frag_var (rs_machine_dependent, 6, 4, 0, - fixups[0].exp.X_add_symbol, - fixups[0].exp.X_add_number, - (char *)fixups[0].opindex); - md_number_to_chars (f, insn, insn_size); - md_number_to_chars (f + 2, 0, 4); - } - } - else - { - /* Four byte insns have an opcode with the two high bits on. */ - if ((insn & 0x0600) == 0x0600) - insn_size = 4; - else - insn_size = 2; - - /* Special case: 32 bit MOV */ - if ((insn & 0xffe0) == 0x0620) - insn_size = 2; - - f = frag_more (insn_size); - - md_number_to_chars (f, insn, insn_size); - - if (extra_data_after_insn) - { - f = frag_more (extra_data_len); - - md_number_to_chars (f, extra_data, extra_data_len); - - extra_data_after_insn = false; - } - } - - /* Create any fixups. At this point we do not use a - bfd_reloc_code_real_type, but instead just use the - BFD_RELOC_UNUSED plus the operand index. This lets us easily - handle fixups for any operand type, although that is admittedly - not a very exciting feature. We pick a BFD reloc type in - md_apply_fix. */ - for (i = 0; i < fc; i++) - { - const struct v850_operand * operand; - bfd_reloc_code_real_type reloc; - - operand = & v850_operands[ fixups[i].opindex ]; - - reloc = fixups[i].reloc; - - if (reloc != BFD_RELOC_UNUSED) - { - reloc_howto_type * reloc_howto = bfd_reloc_type_lookup (stdoutput, - reloc); - int size; - int address; - fixS * fixP; - - if (!reloc_howto) - abort(); - - size = bfd_get_reloc_size (reloc_howto); - - /* XXX This will abort on an R_V850_8 reloc - - is this reloc actually used ? */ - if (size != 2 && size != 4) - abort (); - - address = (f - frag_now->fr_literal) + insn_size - size; - - if (reloc == BFD_RELOC_32) - { - address += 2; - } - - fixP = fix_new_exp (frag_now, address, size, - & fixups[i].exp, - reloc_howto->pc_relative, - reloc); - - switch (reloc) - { - case BFD_RELOC_LO16: - case BFD_RELOC_HI16: - case BFD_RELOC_HI16_S: - fixP->fx_no_overflow = 1; - break; - } - } - else - { - fix_new_exp ( - frag_now, - f - frag_now->fr_literal, 4, - & fixups[i].exp, - 1 /* FIXME: V850_OPERAND_RELATIVE ??? */, - (bfd_reloc_code_real_type) (fixups[i].opindex - + (int) BFD_RELOC_UNUSED) - ); - } - } - - input_line_pointer = saved_input_line_pointer; -} - - -/* If while processing a fixup, a reloc really needs to be created */ -/* then it is done here. */ - -arelent * -tc_gen_reloc (seg, fixp) - asection * seg; - fixS * fixp; -{ - arelent * reloc; - - reloc = (arelent *) xmalloc (sizeof (arelent)); - reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); - *reloc->sym_ptr_ptr= symbol_get_bfdsym (fixp->fx_addsy); - reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; - reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); - - if (reloc->howto == (reloc_howto_type *) NULL) - { - as_bad_where (fixp->fx_file, fixp->fx_line, - /* xgettext:c-format */ - _("reloc %d not supported by object file format"), - (int) fixp->fx_r_type); - - xfree (reloc); - - return NULL; - } - - if ( fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY - || fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT) - reloc->addend = fixp->fx_offset; - else - reloc->addend = fixp->fx_addnumber; - - return reloc; -} - -/* Assume everything will fit in two bytes, then expand as necessary. */ -int -md_estimate_size_before_relax (fragp, seg) - fragS * fragp; - asection * seg; -{ - if (fragp->fr_subtype == 0) - fragp->fr_var = 4; - else if (fragp->fr_subtype == 2) - fragp->fr_var = 2; - else - abort (); - return 2; -} - -long -v850_pcrel_from_section (fixp, section) - fixS * fixp; - segT section; -{ - /* If the symbol is undefined, or in a section other than our own, - or it is weak (in which case it may well be in another section, - then let the linker figure it out. */ - if (fixp->fx_addsy != (symbolS *) NULL - && (! S_IS_DEFINED (fixp->fx_addsy) - || S_IS_WEAK (fixp->fx_addsy) - || (S_GET_SEGMENT (fixp->fx_addsy) != section))) - return 0; - - return fixp->fx_frag->fr_address + fixp->fx_where; -} - -int -md_apply_fix3 (fixp, valuep, seg) - fixS * fixp; - valueT * valuep; - segT seg; -{ - valueT value; - char * where; - - if ( fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT - || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY) - { - fixp->fx_done = 0; - return 1; - } - - if (fixp->fx_addsy == (symbolS *) NULL) - { - value = * valuep; - fixp->fx_done = 1; - } - else if (fixp->fx_pcrel) - value = * valuep; - else - { - value = fixp->fx_offset; - if (fixp->fx_subsy != (symbolS *) NULL) - { - if (S_GET_SEGMENT (fixp->fx_subsy) == absolute_section) - value -= S_GET_VALUE (fixp->fx_subsy); - else - { - /* We don't actually support subtracting a symbol. */ - as_bad_where (fixp->fx_file, fixp->fx_line, - _("expression too complex")); - } - } - } - - if ((int) fixp->fx_r_type >= (int) BFD_RELOC_UNUSED) - { - int opindex; - const struct v850_operand * operand; - unsigned long insn; - - opindex = (int) fixp->fx_r_type - (int) BFD_RELOC_UNUSED; - operand = & v850_operands[ opindex ]; - - /* Fetch the instruction, insert the fully resolved operand - value, and stuff the instruction back again. - - Note the instruction has been stored in little endian - format! */ - where = fixp->fx_frag->fr_literal + fixp->fx_where; - - insn = bfd_getl32 ((unsigned char *) where); - insn = v850_insert_operand (insn, operand, (offsetT) value, - fixp->fx_file, fixp->fx_line, NULL); - bfd_putl32 ((bfd_vma) insn, (unsigned char *) where); - - if (fixp->fx_done) - { - /* Nothing else to do here. */ - return 1; - } - - /* Determine a BFD reloc value based on the operand information. - We are only prepared to turn a few of the operands into relocs. */ - - if (operand->bits == 22) - fixp->fx_r_type = BFD_RELOC_V850_22_PCREL; - else if (operand->bits == 9) - fixp->fx_r_type = BFD_RELOC_V850_9_PCREL; - else - { - /* fprintf (stderr, "bits: %d, insn: %x\n", operand->bits, insn); */ - - as_bad_where (fixp->fx_file, fixp->fx_line, - _("unresolved expression that must be resolved")); - fixp->fx_done = 1; - return 1; - } - } - else if (fixp->fx_done) - { - /* We still have to insert the value into memory! */ - where = fixp->fx_frag->fr_literal + fixp->fx_where; - - if (fixp->fx_size == 1) - * where = value & 0xff; - else if (fixp->fx_size == 2) - bfd_putl16 (value & 0xffff, (unsigned char *) where); - else if (fixp->fx_size == 4) - bfd_putl32 (value, (unsigned char *) where); - } - - fixp->fx_addnumber = value; - return 1; -} - - -/* Parse a cons expression. We have to handle hi(), lo(), etc - on the v850. */ -void -parse_cons_expression_v850 (exp) - expressionS * exp; -{ - /* See if there's a reloc prefix like hi() we have to handle. */ - hold_cons_reloc = v850_reloc_prefix (NULL); - - /* Do normal expression parsing. */ - expression (exp); -} - -/* Create a fixup for a cons expression. If parse_cons_expression_v850 - found a reloc prefix, then we use that reloc, else we choose an - appropriate one based on the size of the expression. */ -void -cons_fix_new_v850 (frag, where, size, exp) - fragS * frag; - int where; - int size; - expressionS *exp; -{ - if (hold_cons_reloc == BFD_RELOC_UNUSED) - { - if (size == 4) - hold_cons_reloc = BFD_RELOC_32; - if (size == 2) - hold_cons_reloc = BFD_RELOC_16; - if (size == 1) - hold_cons_reloc = BFD_RELOC_8; - } - - if (exp != NULL) - fix_new_exp (frag, where, size, exp, 0, hold_cons_reloc); - else - fix_new (frag, where, size, NULL, 0, 0, hold_cons_reloc); -} - -boolean -v850_fix_adjustable (fixP) - fixS * fixP; -{ - if (fixP->fx_addsy == NULL) - return 1; - - /* Prevent all adjustments to global symbols. */ - if (S_IS_EXTERN (fixP->fx_addsy)) - return 0; - - if (S_IS_WEAK (fixP->fx_addsy)) - return 0; - - /* Don't adjust function names */ - if (S_IS_FUNCTION (fixP->fx_addsy)) - return 0; - - /* We need the symbol name for the VTABLE entries */ - if ( fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT - || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY) - return 0; - - return 1; -} - -int -v850_force_relocation (fixP) - struct fix * fixP; -{ - if (fixP->fx_addsy && S_IS_WEAK (fixP->fx_addsy)) - return 1; - - if ( fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT - || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY) - return 1; - - return 0; -} diff --git a/contrib/binutils/gas/config/tc-v850.h b/contrib/binutils/gas/config/tc-v850.h deleted file mode 100644 index fad4d1cf8501d..0000000000000 --- a/contrib/binutils/gas/config/tc-v850.h +++ /dev/null @@ -1,85 +0,0 @@ -/* tc-v850.h -- Header file for tc-v850.c. - Copyright (C) 1996, 1997 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. */ - -#define TC_V850 - -#include <elf/v850.h> - -#define TARGET_BYTES_BIG_ENDIAN 0 - -#ifndef BFD_ASSEMBLER - #error V850 support requires BFD_ASSEMBLER -#endif - -/* The target BFD architecture. */ -#define TARGET_ARCH bfd_arch_v850 - -/* The target BFD format. */ -#define TARGET_FORMAT "elf32-v850" - -#define MD_APPLY_FIX3 -#define md_operand(x) - -#define obj_fix_adjustable(fixP) v850_fix_adjustable(fixP) -#define TC_FORCE_RELOCATION(fixp) v850_force_relocation(fixp) -extern int v850_force_relocation PARAMS ((struct fix *)); - -/* Permit temporary numeric labels. */ -#define LOCAL_LABELS_FB 1 - -#define DIFF_EXPR_OK /* foo-. gets turned into PC relative relocs */ - -/* We don't need to handle .word strangely. */ -#define WORKING_DOT_WORD - -#define md_number_to_chars number_to_chars_littleendian - -/* We need to handle lo(), hi(), etc etc in .hword, .word, etc - directives, so we have to parse "cons" expressions ourselves. */ -#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) parse_cons_expression_v850 (EXP) -#define TC_CONS_FIX_NEW cons_fix_new_v850 -extern const struct relax_type md_relax_table[]; -#define TC_GENERIC_RELAX_TABLE md_relax_table - - -/* This section must be in the small data area (pointed to by GP). */ -#define SHF_V850_GPREL 0x10000000 -/* This section must be in the tiny data area (pointed to by EP). */ -#define SHF_V850_EPREL 0x20000000 -/* This section must be in the zero data area (pointed to by R0). */ -#define SHF_V850_R0REL 0x40000000 - -#define ELF_TC_SPECIAL_SECTIONS \ - { ".sdata", SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_V850_GPREL }, \ - { ".rosdata", SHT_PROGBITS, SHF_ALLOC + SHF_V850_GPREL }, \ - { ".sbss", SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_V850_GPREL }, \ - { ".scommon", SHT_V850_SCOMMON, SHF_ALLOC + SHF_WRITE + SHF_V850_GPREL }, \ - { ".tdata", SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_V850_EPREL }, \ - { ".tbss", SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_V850_EPREL }, \ - { ".tcommon", SHT_V850_TCOMMON, SHF_ALLOC + SHF_WRITE + SHF_V850_R0REL }, \ - { ".zdata", SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_V850_R0REL }, \ - { ".rozdata", SHT_PROGBITS, SHF_ALLOC + SHF_V850_R0REL }, \ - { ".zbss", SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_V850_R0REL }, \ - { ".zcommon", SHT_V850_ZCOMMON, SHF_ALLOC + SHF_WRITE + SHF_V850_R0REL }, \ - { ".call_table_data", SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, \ - { ".call_table_text", SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_EXECINSTR }, - -#define MD_PCREL_FROM_SECTION(fixP,section) v850_pcrel_from_section (fixP, section) -extern long v850_pcrel_from_section (); diff --git a/contrib/binutils/gas/config/tc-z8k.c b/contrib/binutils/gas/config/tc-z8k.c deleted file mode 100644 index f89b14b3b32e3..0000000000000 --- a/contrib/binutils/gas/config/tc-z8k.c +++ /dev/null @@ -1,1589 +0,0 @@ -/* tc-z8k.c -- Assemble code for the Zilog Z800n - Copyright (C) 1992, 93, 94, 95, 96, 97, 98, 1999 Free Software Foundation. - - 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. */ - -/* - Written By Steve Chamberlain - sac@cygnus.com - */ -#define DEFINE_TABLE -#include <stdio.h> - -#include "opcodes/z8k-opc.h" - -#include "as.h" -#include "bfd.h" -#include <ctype.h> - -const char comment_chars[] = -{'!', 0}; -const char line_separator_chars[] = -{';', 0}; -const char line_comment_chars[] = -{'#', 0}; - -extern int machine; -extern int coff_flags; -int segmented_mode; -const int md_reloc_size; - -/* This table describes all the machine specific pseudo-ops the assembler - has to support. The fields are: - pseudo-op name without dot - function to call to execute this pseudo-op - Integer arg to pass to the function - */ - -void cons (); - -void -s_segm () -{ - segmented_mode = 1; - machine = bfd_mach_z8001; - coff_flags = F_Z8001; -} - -void -s_unseg () -{ - segmented_mode = 0; - machine = bfd_mach_z8002; - coff_flags = F_Z8002; -} - -static -void -even () -{ - frag_align (1, 0, 0); - record_alignment (now_seg, 1); -} - -void obj_coff_section (); - -int -tohex (c) - int c; -{ - if (isdigit (c)) - return c - '0'; - if (islower (c)) - return c - 'a' + 10; - return c - 'A' + 10; -} - -void -sval () -{ - - SKIP_WHITESPACE (); - if (*input_line_pointer == '\'') - { - int c; - input_line_pointer++; - c = *input_line_pointer++; - while (c != '\'') - { - if (c == '%') - { - c = (tohex (input_line_pointer[0]) << 4) - | tohex (input_line_pointer[1]); - input_line_pointer += 2; - } - FRAG_APPEND_1_CHAR (c); - c = *input_line_pointer++; - } - demand_empty_rest_of_line (); - } - -} -const pseudo_typeS md_pseudo_table[] = -{ - {"int", cons, 2}, - {"data.b", cons, 1}, - {"data.w", cons, 2}, - {"data.l", cons, 4}, - {"form", listing_psize, 0}, - {"heading", listing_title, 0}, - {"import", s_ignore, 0}, - {"page", listing_eject, 0}, - {"program", s_ignore, 0}, - {"z8001", s_segm, 0}, - {"z8002", s_unseg, 0}, - - - {"segm", s_segm, 0}, - {"unsegm", s_unseg, 0}, - {"unseg", s_unseg, 0}, - {"name", s_app_file, 0}, - {"global", s_globl, 0}, - {"wval", cons, 2}, - {"lval", cons, 4}, - {"bval", cons, 1}, - {"sval", sval, 0}, - {"rsect", obj_coff_section, 0}, - {"sect", obj_coff_section, 0}, - {"block", s_space, 0}, - {"even", even, 0}, - {0, 0, 0} -}; - -const char EXP_CHARS[] = "eE"; - -/* Chars that mean this number is a floating point constant */ -/* As in 0f12.456 */ -/* or 0d1.2345e12 */ -const char FLT_CHARS[] = "rRsSfFdDxXpP"; - -static struct hash_control *opcode_hash_control; /* Opcode mnemonics */ - -void -md_begin () -{ - opcode_entry_type *opcode; - char *prev_name = ""; - int idx = 0; - - opcode_hash_control = hash_new (); - - for (opcode = z8k_table; opcode->name; opcode++) - { - /* Only enter unique codes into the table */ - char *src = opcode->name; - - if (strcmp (opcode->name, prev_name)) - { - hash_insert (opcode_hash_control, opcode->name, (char *) opcode); - idx++; - } - opcode->idx = idx; - prev_name = opcode->name; - } - - /* default to z8002 */ - s_unseg (); - - /* insert the pseudo ops too */ - for (idx = 0; md_pseudo_table[idx].poc_name; idx++) - { - opcode_entry_type *fake_opcode; - fake_opcode = (opcode_entry_type *) malloc (sizeof (opcode_entry_type)); - fake_opcode->name = md_pseudo_table[idx].poc_name, - fake_opcode->func = (void *) (md_pseudo_table + idx); - fake_opcode->opcode = 250; - hash_insert (opcode_hash_control, fake_opcode->name, fake_opcode); - } - - linkrelax = 1; -} - -struct z8k_exp -{ - char *e_beg; - char *e_end; - expressionS e_exp; -}; -typedef struct z8k_op -{ - char regsize; /* 'b','w','r','q' */ - unsigned int reg; /* 0..15 */ - - int mode; - - unsigned int x_reg; /* any other register associated with the mode */ - expressionS exp; /* any expression */ -} - -op_type; - -static expressionS *da_operand; -static expressionS *imm_operand; - -int reg[16]; -int the_cc; -int the_ctrl; -int the_flags; -int the_interrupt; - -char * -DEFUN (whatreg, (reg, src), - int *reg AND - char *src) -{ - if (isdigit (src[1])) - { - *reg = (src[0] - '0') * 10 + src[1] - '0'; - return src + 2; - } - else - { - *reg = (src[0] - '0'); - return src + 1; - } -} - -/* - parse operands - - rh0-rh7, rl0-rl7 - r0-r15 - rr0-rr14 - rq0--rq12 - WREG r0,r1,r2,r3,r4,r5,r6,r7,fp,sp - r0l,r0h,..r7l,r7h - @WREG - @WREG+ - @-WREG - #const - - */ - -/* try and parse a reg name, returns number of chars consumed */ -char * -DEFUN (parse_reg, (src, mode, reg), - char *src AND - int *mode AND - unsigned int *reg) -{ - char *res = 0; - char regno; - - if (src[0] == 's' && src[1] == 'p') - { - if (segmented_mode) - { - *mode = CLASS_REG_LONG; - *reg = 14; - } - else - { - *mode = CLASS_REG_WORD; - *reg = 15; - } - return src + 2; - } - if (src[0] == 'r') - { - if (src[1] == 'r') - { - *mode = CLASS_REG_LONG; - res = whatreg (reg, src + 2); - regno = *reg; - if (regno > 14) - as_warn (_("register rr%d, out of range."),regno); - } - else if (src[1] == 'h') - { - *mode = CLASS_REG_BYTE; - res = whatreg (reg, src + 2); - regno = *reg; - if (regno > 7) - as_warn (_("register rh%d, out of range."),regno); - } - else if (src[1] == 'l') - { - *mode = CLASS_REG_BYTE; - res = whatreg (reg, src + 2); - regno = *reg; - if (regno > 7) - as_warn (_("register rl%d, out of range."),regno); - *reg += 8; - } - else if (src[1] == 'q') - { - *mode = CLASS_REG_QUAD; - res = whatreg (reg, src + 2); - regno = *reg; - if (regno > 12) - as_warn (_("register rq%d, out of range."),regno); - } - else - { - *mode = CLASS_REG_WORD; - res = whatreg (reg, src + 1); - regno = *reg; - if (regno > 15) - as_warn (_("register r%d, out of range."),regno); - } - } - return res; - -} - -char * -DEFUN (parse_exp, (s, op), - char *s AND - expressionS * op) -{ - char *save = input_line_pointer; - char *new; - - input_line_pointer = s; - expression (op); - if (op->X_op == O_absent) - as_bad (_("missing operand")); - new = input_line_pointer; - input_line_pointer = save; - return new; -} - -/* The many forms of operand: - - <rb> - <r> - <rr> - <rq> - @r - #exp - exp - exp(r) - r(#exp) - r(r) - - - - */ - -static -char * -DEFUN (checkfor, (ptr, what), - char *ptr AND - char what) -{ - if (*ptr == what) - ptr++; - else - { - as_bad (_("expected %c"), what); - } - return ptr; -} - -/* Make sure the mode supplied is the size of a word */ -static void -DEFUN (regword, (mode, string), - int mode AND - char *string) -{ - int ok; - - ok = CLASS_REG_WORD; - if (ok != mode) - { - as_bad (_("register is wrong size for a word %s"), string); - } -} - -/* Make sure the mode supplied is the size of an address */ -static void -DEFUN (regaddr, (mode, string), - int mode AND - char *string) -{ - int ok; - - ok = segmented_mode ? CLASS_REG_LONG : CLASS_REG_WORD; - if (ok != mode) - { - as_bad (_("register is wrong size for address %s"), string); - } -} - -struct ctrl_names -{ - int value; - char *name; -}; - -struct ctrl_names ctrl_table[] = -{ - 0x2, "fcw", - 0X3, "refresh", - 0x4, "psapseg", - 0x5, "psapoff", - 0x5, "psap", - 0x6, "nspseg", - 0x7, "nspoff", - 0x7, "nsp", - 0, 0 -}; - -static void -DEFUN (get_ctrl_operand, (ptr, mode, dst), - char **ptr AND - struct z8k_op *mode AND - unsigned int dst) -{ - char *src = *ptr; - int r; - int i; - - while (*src == ' ') - src++; - - mode->mode = CLASS_CTRL; - for (i = 0; ctrl_table[i].name; i++) - { - int j; - - for (j = 0; ctrl_table[i].name[j]; j++) - { - if (ctrl_table[i].name[j] != src[j]) - goto fail; - } - the_ctrl = ctrl_table[i].value; - *ptr = src + j; - return; - fail:; - } - the_ctrl = 0; - return; -} - -struct flag_names -{ - int value; - char *name; - -}; - -struct flag_names flag_table[] = -{ - 0x1, "p", - 0x1, "v", - 0x2, "s", - 0x4, "z", - 0x8, "c", - 0x0, "+", - 0, 0 -}; - -static void -DEFUN (get_flags_operand, (ptr, mode, dst), - char **ptr AND - struct z8k_op *mode AND - unsigned int dst) -{ - char *src = *ptr; - int r; - int i; - int j; - - while (*src == ' ') - src++; - - mode->mode = CLASS_FLAGS; - the_flags = 0; - for (j = 0; j <= 9; j++) - { - if (!src[j]) - goto done; - for (i = 0; flag_table[i].name; i++) - { - if (flag_table[i].name[0] == src[j]) - { - the_flags = the_flags | flag_table[i].value; - goto match; - } - } - goto done; - match: - ; - } - done: - *ptr = src + j; - return; -} - - -struct interrupt_names -{ - int value; - char *name; - -}; - -struct interrupt_names intr_table[] = -{ - 0x1, "nvi", - 0x2, "vi", - 0x3, "both", - 0x3, "all", - 0, 0 -}; - -static void -DEFUN (get_interrupt_operand, (ptr, mode, dst), - char **ptr AND - struct z8k_op *mode AND - unsigned int dst) -{ - char *src = *ptr; - int r; - int i; - - while (*src == ' ') - src++; - - mode->mode = CLASS_IMM; - for (i = 0; intr_table[i].name; i++) - { - int j; - - for (j = 0; intr_table[i].name[j]; j++) - { - if (intr_table[i].name[j] != src[j]) - goto fail; - } - the_interrupt = intr_table[i].value; - *ptr = src + j; - return; - fail:; - } - the_interrupt = 0x0; - return; -} - -struct cc_names -{ - int value; - char *name; - -}; - -struct cc_names table[] = -{ - 0x0, "f", - 0x1, "lt", - 0x2, "le", - 0x3, "ule", - 0x4, "ov", - 0x4, "pe", - 0x5, "mi", - 0x6, "eq", - 0x6, "z", - 0x7, "c", - 0x7, "ult", - 0x8, "t", - 0x9, "ge", - 0xa, "gt", - 0xb, "ugt", - 0xc, "nov", - 0xc, "po", - 0xd, "pl", - 0xe, "ne", - 0xe, "nz", - 0xf, "nc", - 0xf, "uge", - 0, 0 -}; - -static void -DEFUN (get_cc_operand, (ptr, mode, dst), - char **ptr AND - struct z8k_op *mode AND - unsigned int dst) -{ - char *src = *ptr; - int r; - int i; - - while (*src == ' ') - src++; - - mode->mode = CLASS_CC; - for (i = 0; table[i].name; i++) - { - int j; - - for (j = 0; table[i].name[j]; j++) - { - if (table[i].name[j] != src[j]) - goto fail; - } - the_cc = table[i].value; - *ptr = src + j; - return; - fail:; - } - the_cc = 0x8; -} - -static void -get_operand (ptr, mode, dst) - char **ptr; - struct z8k_op *mode; - unsigned int dst; -{ - char *src = *ptr; - char *end; - unsigned int num; - unsigned int len; - unsigned int size; - - mode->mode = 0; - - while (*src == ' ') - src++; - if (*src == '#') - { - mode->mode = CLASS_IMM; - imm_operand = &(mode->exp); - src = parse_exp (src + 1, &(mode->exp)); - } - else if (*src == '@') - { - int d; - - mode->mode = CLASS_IR; - src = parse_reg (src + 1, &d, &mode->reg); - } - else - { - int regn; - - end = parse_reg (src, &mode->mode, ®n); - - if (end) - { - int nw, nr; - - src = end; - if (*src == '(') - { - src++; - end = parse_reg (src, &nw, &nr); - if (end) - { - /* Got Ra(Rb) */ - src = end; - - if (*src != ')') - { - as_bad (_("Missing ) in ra(rb)")); - } - else - { - src++; - } - - regaddr (mode->mode, "ra(rb) ra"); -/* regword (mode->mode, "ra(rb) rb");*/ - mode->mode = CLASS_BX; - mode->reg = regn; - mode->x_reg = nr; - reg[ARG_RX] = nr; - } - else - { - /* Got Ra(disp) */ - if (*src == '#') - src++; - src = parse_exp (src, &(mode->exp)); - src = checkfor (src, ')'); - mode->mode = CLASS_BA; - mode->reg = regn; - mode->x_reg = 0; - imm_operand = &(mode->exp); - } - } - else - { - mode->reg = regn; - mode->x_reg = 0; - } - } - else - { - /* No initial reg */ - src = parse_exp (src, &(mode->exp)); - if (*src == '(') - { - src++; - end = parse_reg (src, &(mode->mode), ®n); - regword (mode->mode, "addr(Ra) ra"); - mode->mode = CLASS_X; - mode->reg = regn; - mode->x_reg = 0; - da_operand = &(mode->exp); - src = checkfor (end, ')'); - } - else - { - /* Just an address */ - mode->mode = CLASS_DA; - mode->reg = 0; - mode->x_reg = 0; - da_operand = &(mode->exp); - } - } - } - *ptr = src; -} - -static -char * -get_operands (opcode, op_end, operand) - opcode_entry_type *opcode; - char *op_end; - op_type *operand; -{ - char *ptr = op_end; -char *savptr; - switch (opcode->noperands) - { - case 0: - operand[0].mode = 0; - operand[1].mode = 0; - break; - - case 1: - ptr++; - if (opcode->arg_info[0] == CLASS_CC) - { - get_cc_operand (&ptr, operand + 0, 0); - } - else if (opcode->arg_info[0] == CLASS_FLAGS) - { - get_flags_operand (&ptr, operand + 0, 0); - } - else if (opcode->arg_info[0] == (CLASS_IMM +(ARG_IMM2))) - { - get_interrupt_operand (&ptr, operand + 0, 0); - } - else - { - get_operand (&ptr, operand + 0, 0); - } - operand[1].mode = 0; - break; - - case 2: - ptr++; - savptr = ptr; - if (opcode->arg_info[0] == CLASS_CC) - { - get_cc_operand (&ptr, operand + 0, 0); - } - else if (opcode->arg_info[0] == CLASS_CTRL) - { - get_ctrl_operand (&ptr, operand + 0, 0); - if (the_ctrl == 0) - { - ptr = savptr; - get_operand (&ptr, operand + 0, 0); - if (ptr == 0) - return; - if (*ptr == ',') - ptr++; - get_ctrl_operand (&ptr, operand + 1, 1); - return ptr; - } - } - else - { - get_operand (&ptr, operand + 0, 0); - } - if (ptr == 0) - return; - if (*ptr == ',') - ptr++; - get_operand (&ptr, operand + 1, 1); - break; - - case 3: - ptr++; - get_operand (&ptr, operand + 0, 0); - if (*ptr == ',') - ptr++; - get_operand (&ptr, operand + 1, 1); - if (*ptr == ',') - ptr++; - get_operand (&ptr, operand + 2, 2); - break; - - case 4: - ptr++; - get_operand (&ptr, operand + 0, 0); - if (*ptr == ',') - ptr++; - get_operand (&ptr, operand + 1, 1); - if (*ptr == ',') - ptr++; - get_operand (&ptr, operand + 2, 2); - if (*ptr == ',') - ptr++; - get_cc_operand (&ptr, operand + 3, 3); - break; - default: - abort (); - } - - return ptr; -} - -/* Passed a pointer to a list of opcodes which use different - addressing modes, return the opcode which matches the opcodes - provided - */ - -static -opcode_entry_type * -DEFUN (get_specific, (opcode, operands), - opcode_entry_type * opcode AND - op_type * operands) - -{ - opcode_entry_type *this_try = opcode; - int found = 0; - unsigned int noperands = opcode->noperands; - - unsigned int dispreg; - unsigned int this_index = opcode->idx; - - while (this_index == opcode->idx && !found) - { - unsigned int i; - - this_try = opcode++; - for (i = 0; i < noperands; i++) - { - int mode = operands[i].mode; - - if ((mode & CLASS_MASK) != (this_try->arg_info[i] & CLASS_MASK)) - { - /* it could be an pc rel operand, if this is a da mode and - we like disps, then insert it */ - - if (mode == CLASS_DA && this_try->arg_info[i] == CLASS_DISP) - { - /* This is the case */ - operands[i].mode = CLASS_DISP; - } - else if (mode == CLASS_BA && this_try->arg_info[i]) - { - /* Can't think of a way to turn what we've been given into - something that's ok */ - goto fail; - } - else if (this_try->arg_info[i] & CLASS_PR) - { - if (mode == CLASS_REG_LONG && segmented_mode) - { - /* ok */ - } - else if (mode == CLASS_REG_WORD && !segmented_mode) - { - /* ok */ - } - else - goto fail; - } - else - goto fail; - } - switch (mode & CLASS_MASK) - { - default: - break; - case CLASS_X: - case CLASS_IR: - case CLASS_BA: - case CLASS_BX: - case CLASS_DISP: - case CLASS_REG: - case CLASS_REG_WORD: - case CLASS_REG_BYTE: - case CLASS_REG_QUAD: - case CLASS_REG_LONG: - case CLASS_REGN0: - reg[this_try->arg_info[i] & ARG_MASK] = operands[i].reg; - break; - } - } - - found = 1; - fail:; - } - if (found) - return this_try; - else - return 0; -} - -static void -DEFUN (check_operand, (operand, width, string), - struct z8k_op *operand AND - unsigned int width AND - char *string) -{ - if (operand->exp.X_add_symbol == 0 - && operand->exp.X_op_symbol == 0) - { - - /* No symbol involved, let's look at offset, it's dangerous if any of - the high bits are not 0 or ff's, find out by oring or anding with - the width and seeing if the answer is 0 or all fs*/ - if ((operand->exp.X_add_number & ~width) != 0 && - (operand->exp.X_add_number | width) != (~0)) - { - as_warn (_("operand %s0x%x out of range."), string, operand->exp.X_add_number); - } - } - -} - -static char buffer[20]; - -static void -DEFUN (newfix, (ptr, type, operand), - int ptr AND - int type AND - expressionS * operand) -{ - if (operand->X_add_symbol - || operand->X_op_symbol - || operand->X_add_number) - { - fix_new_exp (frag_now, - ptr, - 1, - operand, - 0, - type); - } -} - -static char * -DEFUN (apply_fix, (ptr, type, operand, size), - char *ptr AND - int type AND - expressionS * operand AND - int size) -{ - int n = operand->X_add_number; - - operand->X_add_number = n; - newfix ((ptr - buffer) / 2, type, operand); -#if 1 - switch (size) - { - case 8: /* 8 nibbles == 32 bits */ - *ptr++ = n >> 28; - *ptr++ = n >> 24; - *ptr++ = n >> 20; - *ptr++ = n >> 16; - case 4: /* 4 niblles == 16 bits */ - *ptr++ = n >> 12; - *ptr++ = n >> 8; - case 2: - *ptr++ = n >> 4; - case 1: - *ptr++ = n >> 0; - break; - } -#endif - return ptr; - -} - -/* Now we know what sort of opcodes it is, lets build the bytes - - */ -#define INSERT(x,y) *x++ = y>>24; *x++ = y>> 16; *x++=y>>8; *x++ =y; -static void -build_bytes (this_try, operand) - opcode_entry_type * this_try; - struct z8k_op *operand; -{ - unsigned int i; - - int length; - char *output; - char *output_ptr = buffer; - char part; - int c; - char high; - int nib; - int nibble; - unsigned int *class_ptr; - - frag_wane (frag_now); - frag_new (0); - - memset (buffer, 20, 0); - class_ptr = this_try->byte_info; -top:; - - for (nibble = 0; c = *class_ptr++; nibble++) - { - - switch (c & CLASS_MASK) - { - default: - - abort (); - case CLASS_ADDRESS: - /* Direct address, we don't cope with the SS mode right now */ - if (segmented_mode) - { - da_operand->X_add_number |= 0x80000000; - output_ptr = apply_fix (output_ptr, R_IMM32, da_operand, 8); - } - else - { - output_ptr = apply_fix (output_ptr, R_IMM16, da_operand, 4); - } - da_operand = 0; - break; - case CLASS_DISP8: - /* pc rel 8 bit */ - output_ptr = apply_fix (output_ptr, R_JR, da_operand, 2); - da_operand = 0; - break; - - case CLASS_0DISP7: - /* pc rel 7 bit */ - *output_ptr = 0; - output_ptr = apply_fix (output_ptr, R_DISP7, da_operand, 2); - da_operand = 0; - break; - - case CLASS_1DISP7: - /* pc rel 7 bit */ - *output_ptr = 0x80; - output_ptr = apply_fix (output_ptr, R_DISP7, da_operand, 2); - output_ptr[-2] = 0x8; - da_operand = 0; - break; - - case CLASS_BIT_1OR2: - *output_ptr = c & 0xf; - if (imm_operand) - { - if (imm_operand->X_add_number == 2) - { - *output_ptr |= 2; - } - else if (imm_operand->X_add_number != 1) - { - as_bad (_("immediate must be 1 or 2")); - } - } - else - { - as_bad (_("immediate 1 or 2 expected")); - } - output_ptr++; - break; - case CLASS_CC: - *output_ptr++ = the_cc; - break; - case CLASS_0CCC: - *output_ptr++ = the_ctrl; - break; - case CLASS_1CCC: - *output_ptr++ = the_ctrl | 0x8; - break; - case CLASS_00II: - *output_ptr++ = (~the_interrupt & 0x3); - break; - case CLASS_01II: - *output_ptr++ = (~the_interrupt & 0x3) | 0x4; - break; - case CLASS_FLAGS: - *output_ptr++ = the_flags; - break; - case CLASS_BIT: - *output_ptr++ = c & 0xf; - break; - case CLASS_REGN0: - if (reg[c & 0xf] == 0) - { - as_bad (_("can't use R0 here")); - } - case CLASS_REG: - case CLASS_REG_BYTE: - case CLASS_REG_WORD: - case CLASS_REG_LONG: - case CLASS_REG_QUAD: - /* Insert bit mattern of - right reg */ - *output_ptr++ = reg[c & 0xf]; - break; - case CLASS_DISP: - output_ptr = apply_fix (output_ptr, R_IMM16, da_operand, 4); - da_operand = 0; - break; - - case CLASS_IMM: - { - nib = 0; - switch (c & ARG_MASK) - { - case ARG_IMM4: - output_ptr = apply_fix (output_ptr, R_IMM4L, imm_operand, 1); - break; - case ARG_IMM4M1: - imm_operand->X_add_number--; - output_ptr = apply_fix (output_ptr, R_IMM4L, imm_operand, 1); - break; - case ARG_IMMNMINUS1: - imm_operand->X_add_number--; - output_ptr = apply_fix (output_ptr, R_IMM4L, imm_operand, 1); - break; - case ARG_NIM8: - imm_operand->X_add_number = -imm_operand->X_add_number; - case ARG_IMM8: - output_ptr = apply_fix (output_ptr, R_IMM8, imm_operand, 2); - break; - case ARG_IMM16: - output_ptr = apply_fix (output_ptr, R_IMM16, imm_operand, 4); - break; - - case ARG_IMM32: - output_ptr = apply_fix (output_ptr, R_IMM32, imm_operand, 8); - break; - - default: - abort (); - } - } - } - } - - /* Copy from the nibble buffer into the frag */ - - { - int length = (output_ptr - buffer) / 2; - char *src = buffer; - char *fragp = frag_more (length); - - while (src < output_ptr) - { - *fragp = (src[0] << 4) | src[1]; - src += 2; - fragp++; - } - - } - -} - -/* This is the guts of the machine-dependent assembler. STR points to a - machine dependent instruction. This funciton is supposed to emit - the frags/bytes it assembles to. - */ - -void -DEFUN (md_assemble, (str), - char *str) -{ - char *op_start; - char *op_end; - unsigned int i; - struct z8k_op operand[3]; - opcode_entry_type *opcode; - opcode_entry_type *prev_opcode; - - char *dot = 0; - char c; - - /* Drop leading whitespace */ - while (*str == ' ') - str++; - - /* find the op code end */ - for (op_start = op_end = str; - *op_end != 0 && *op_end != ' '; - op_end++) - { - } - - ; - - if (op_end == op_start) - { - as_bad (_("can't find opcode ")); - } - c = *op_end; - - *op_end = 0; - - opcode = (opcode_entry_type *) hash_find (opcode_hash_control, - op_start); - - - if (opcode == NULL) - { - as_bad (_("unknown opcode")); - return; - } - - if (opcode->opcode == 250) - { - /* was really a pseudo op */ - - pseudo_typeS *p; - char oc; - - char *old = input_line_pointer; - *op_end = c; - - - input_line_pointer = op_end; - - oc = *old; - *old = '\n'; - while (*input_line_pointer == ' ') - input_line_pointer++; - p = (pseudo_typeS *) (opcode->func); - - (p->poc_handler) (p->poc_val); - input_line_pointer = old; - *old = oc; - } - else - { - input_line_pointer = get_operands (opcode, op_end, - operand); - prev_opcode = opcode; - - opcode = get_specific (opcode, operand); - - if (opcode == 0) - { - /* Couldn't find an opcode which matched the operands */ - char *where = frag_more (2); - - where[0] = 0x0; - where[1] = 0x0; - - as_bad (_("Can't find opcode to match operands")); - return; - } - - build_bytes (opcode, operand); - } -} - -void -DEFUN (tc_crawl_symbol_chain, (headers), - object_headers * headers) -{ - printf (_("call to tc_crawl_symbol_chain \n")); -} - -symbolS * -DEFUN (md_undefined_symbol, (name), - char *name) -{ - return 0; -} - -void -DEFUN (tc_headers_hook, (headers), - object_headers * headers) -{ - printf (_("call to tc_headers_hook \n")); -} - -/* Various routines to kill one day */ -/* Equal to MAX_PRECISION in atof-ieee.c */ -#define MAX_LITTLENUMS 6 - -/* Turn a string in input_line_pointer into a floating point constant of type - type, and store the appropriate bytes in *litP. The number of LITTLENUMS - emitted is stored in *sizeP . An error message is returned, or NULL on OK. - */ -char * -md_atof (type, litP, sizeP) - char type; - char *litP; - int *sizeP; -{ - int prec; - LITTLENUM_TYPE words[MAX_LITTLENUMS]; - LITTLENUM_TYPE *wordP; - char *t; - char *atof_ieee (); - - switch (type) - { - case 'f': - case 'F': - case 's': - case 'S': - prec = 2; - break; - - case 'd': - case 'D': - case 'r': - case 'R': - prec = 4; - break; - - case 'x': - case 'X': - prec = 6; - break; - - case 'p': - case 'P': - prec = 6; - break; - - default: - *sizeP = 0; - return _("Bad call to MD_ATOF()"); - } - t = atof_ieee (input_line_pointer, type, words); - if (t) - input_line_pointer = t; - - *sizeP = prec * sizeof (LITTLENUM_TYPE); - for (wordP = words; prec--;) - { - md_number_to_chars (litP, (long) (*wordP++), sizeof (LITTLENUM_TYPE)); - litP += sizeof (LITTLENUM_TYPE); - } - return 0; -} - -CONST char *md_shortopts = "z:"; -struct option md_longopts[] = { - {NULL, no_argument, NULL, 0} -}; -size_t md_longopts_size = sizeof(md_longopts); - -int -md_parse_option (c, arg) - int c; - char *arg; -{ - switch (c) - { - case 'z': - if (!strcmp (arg, "8001")) - s_segm (); - else if (!strcmp (arg, "8002")) - s_unseg (); - else - { - as_bad (_("invalid architecture -z%s"), arg); - return 0; - } - break; - - default: - return 0; - } - - return 1; -} - -void -md_show_usage (stream) - FILE *stream; -{ - fprintf(stream, _("\ -Z8K options:\n\ --z8001 generate segmented code\n\ --z8002 generate unsegmented code\n")); -} - -void -tc_aout_fix_to_chars () -{ - printf (_("call to tc_aout_fix_to_chars \n")); - abort (); -} - -void -md_convert_frag (headers, seg, fragP) - object_headers *headers; - segT seg; - fragS *fragP; -{ - printf (_("call to md_convert_frag \n")); - abort (); -} - -valueT -DEFUN (md_section_align, (seg, size), - segT seg AND - valueT size) -{ - return ((size + (1 << section_alignment[(int) seg]) - 1) & (-1 << section_alignment[(int) seg])); - -} - -void -md_apply_fix (fixP, val) - fixS *fixP; - long val; -{ - char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; - - switch (fixP->fx_r_type) - { - case R_IMM4L: - buf[0] = (buf[0] & 0xf0) | ((buf[0] + val) & 0xf); - break; - - case R_JR: - - *buf++ = val; - /* if (val != 0) abort();*/ - break; - - case R_DISP7: - - *buf++ += val; - /* if (val != 0) abort();*/ - break; - - case R_IMM8: - buf[0] += val; - break; - case R_IMM16: - *buf++ = (val >> 8); - *buf++ = val; - break; - case R_IMM32: - *buf++ = (val >> 24); - *buf++ = (val >> 16); - *buf++ = (val >> 8); - *buf++ = val; - break; -#if 0 - case R_DA | R_SEG: - *buf++ = (val >> 16); - *buf++ = 0x00; - *buf++ = (val >> 8); - *buf++ = val; - break; -#endif - - case 0: - md_number_to_chars (buf, val, fixP->fx_size); - break; - - default: - abort (); - - } -} - -int -md_estimate_size_before_relax (fragP, segment_type) - register fragS *fragP; - register segT segment_type; -{ - printf (_("call tomd_estimate_size_before_relax \n")); - abort (); -} - -/* Put number into target byte order */ - -void -DEFUN (md_number_to_chars, (ptr, use, nbytes), - char *ptr AND - valueT use AND - int nbytes) -{ - number_to_chars_bigendian (ptr, use, nbytes); -} -long -md_pcrel_from (fixP) - fixS *fixP; -{ - abort (); -} - -void -tc_coff_symbol_emit_hook (s) - symbolS *s; -{ -} - -void -tc_reloc_mangle (fix_ptr, intr, base) - fixS *fix_ptr; - struct internal_reloc *intr; - bfd_vma base; - -{ - symbolS *symbol_ptr; - - if (fix_ptr->fx_addsy && - fix_ptr->fx_subsy) - { - symbolS *add = fix_ptr->fx_addsy; - symbolS *sub = fix_ptr->fx_subsy; - if (S_GET_SEGMENT(add) != S_GET_SEGMENT(sub)) - { - as_bad(_("Can't subtract symbols in different sections %s %s"), - S_GET_NAME(add), S_GET_NAME(sub)); - } - else { - int diff = S_GET_VALUE(add) - S_GET_VALUE(sub); - fix_ptr->fx_addsy = 0; - fix_ptr->fx_subsy = 0; - fix_ptr->fx_offset += diff; - } - } - symbol_ptr = fix_ptr->fx_addsy; - - /* If this relocation is attached to a symbol then it's ok - to output it */ - if (fix_ptr->fx_r_type == 0) - { - /* cons likes to create reloc32's whatever the size of the reloc.. */ - switch (fix_ptr->fx_size) - { - case 2: - intr->r_type = R_IMM16; - break; - case 1: - intr->r_type = R_IMM8; - break; - case 4: - intr->r_type = R_IMM32; - break; - default: - abort (); - } - - } - else - { - intr->r_type = fix_ptr->fx_r_type; - } - - intr->r_vaddr = fix_ptr->fx_frag->fr_address + fix_ptr->fx_where + base; - intr->r_offset = fix_ptr->fx_offset; - - if (symbol_ptr) - intr->r_symndx = symbol_ptr->sy_number; - else - intr->r_symndx = -1; -} - diff --git a/contrib/binutils/gas/config/tc-z8k.h b/contrib/binutils/gas/config/tc-z8k.h deleted file mode 100644 index d88b656d6eee6..0000000000000 --- a/contrib/binutils/gas/config/tc-z8k.h +++ /dev/null @@ -1,54 +0,0 @@ -/* This file is tc-z8k.h - Copyright (C) 1987-1992, 93, 95, 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. */ - - -#define TC_Z8K -#define TARGET_BYTES_BIG_ENDIAN 1 - -#if ANSI_PROTOTYPES -struct internal_reloc; -#endif - -#define WORKING_DOT_WORD - -#ifndef BFD_ASSEMBLER -#define LOCAL_LABEL(x) 0 -#endif - -/* This macro translates between an internal fix and an coff reloc type */ -#define TC_COFF_FIX2RTYPE(fixP) abort(); - -#define BFD_ARCH bfd_arch_z8k -#define COFF_MAGIC 0x8000 -#define TC_COUNT_RELOC(x) (1) -#define IGNORE_NONSTANDARD_ESCAPES - -#define TC_RELOC_MANGLE(s,a,b,c) tc_reloc_mangle(a,b,c) -extern void tc_reloc_mangle - PARAMS ((struct fix *, struct internal_reloc *, bfd_vma)); - -#define DO_NOT_STRIP 0 -#define LISTING_HEADER "Zilog Z8000 GAS " -#define NEED_FX_R_TYPE 1 -#define RELOC_32 1234 - -#define md_operand(x) - -/* end of tc-z8k.h */ diff --git a/contrib/binutils/gas/config/te-386bsd.h b/contrib/binutils/gas/config/te-386bsd.h deleted file mode 100644 index dbff99027eaf4..0000000000000 --- a/contrib/binutils/gas/config/te-386bsd.h +++ /dev/null @@ -1,31 +0,0 @@ -/* te-386bsd.h -- 386BSD target environment declarations. - Copyright (C) 1987, 1990, 1991, 1992 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. */ - -#define TE_386BSD 1 - -#include "obj-format.h" - -/* - * Local Variables: - * comment-column: 0 - * fill-column: 131 - * End: - */ - -/* end of te-sun3.h */ diff --git a/contrib/binutils/gas/config/te-aux.h b/contrib/binutils/gas/config/te-aux.h deleted file mode 100644 index da6fa0164cf16..0000000000000 --- a/contrib/binutils/gas/config/te-aux.h +++ /dev/null @@ -1,17 +0,0 @@ -#define TE_AUX - -/* From obj-coff.h: - This internal_lineno crap is to stop namespace pollution from the - bfd internal coff headerfile. */ -#define internal_lineno bfd_internal_lineno -#include "coff/aux-coff.h" /* override bits in coff/internal.h */ -#undef internal_lineno - -#define COFF_NOLOAD_PROBLEM -#define KEEP_RELOC_INFO - -#include "obj-format.h" - -#ifndef LOCAL_LABELS_FB -#define LOCAL_LABELS_FB 1 -#endif diff --git a/contrib/binutils/gas/config/te-freebsd.h b/contrib/binutils/gas/config/te-freebsd.h deleted file mode 100644 index 13142359dcd72..0000000000000 --- a/contrib/binutils/gas/config/te-freebsd.h +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Target environment for FreeBSD. It is the same as the generic - * target, except it arranges to suppress the use of "/" as a comment - * character. Some code in the FreeBSD kernel uses "/" to mean - * division. (What a concept.) - */ -#define TE_FreeBSD 1 -#include "te-generic.h" diff --git a/contrib/binutils/gas/config/te-generic.h b/contrib/binutils/gas/config/te-generic.h deleted file mode 100644 index b8eda4505fb7c..0000000000000 --- a/contrib/binutils/gas/config/te-generic.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * This file is te-generic.h and is intended to be a template for - * target environment specific header files. - * - * It is my intent that this file will evolve into a file suitable for config, - * compile, and copying as an aid for testing and porting. xoxorich. - */ - -/* Added these, because if we don't know what we're targetting we may - need an assembler version of libgcc, and that will use local - labels. */ -#define LOCAL_LABELS_DOLLAR 1 -#define LOCAL_LABELS_FB 1 - -/* these define interfaces */ -#ifdef OBJ_HEADER -#include OBJ_HEADER -#else -#include "obj-format.h" -#endif - -/* end of te-generic.h */ diff --git a/contrib/binutils/gas/config/te-linux.h b/contrib/binutils/gas/config/te-linux.h deleted file mode 100644 index c235a7ab8a8ab..0000000000000 --- a/contrib/binutils/gas/config/te-linux.h +++ /dev/null @@ -1,4 +0,0 @@ -#define TE_LINUX -#define LOCAL_LABELS_FB 1 - -#include "obj-format.h" diff --git a/contrib/binutils/gas/config/te-multi.h b/contrib/binutils/gas/config/te-multi.h deleted file mode 100644 index b8eda4505fb7c..0000000000000 --- a/contrib/binutils/gas/config/te-multi.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * This file is te-generic.h and is intended to be a template for - * target environment specific header files. - * - * It is my intent that this file will evolve into a file suitable for config, - * compile, and copying as an aid for testing and porting. xoxorich. - */ - -/* Added these, because if we don't know what we're targetting we may - need an assembler version of libgcc, and that will use local - labels. */ -#define LOCAL_LABELS_DOLLAR 1 -#define LOCAL_LABELS_FB 1 - -/* these define interfaces */ -#ifdef OBJ_HEADER -#include OBJ_HEADER -#else -#include "obj-format.h" -#endif - -/* end of te-generic.h */ diff --git a/contrib/binutils/gas/config/te-nbsd.h b/contrib/binutils/gas/config/te-nbsd.h deleted file mode 100644 index cee4600077b21..0000000000000 --- a/contrib/binutils/gas/config/te-nbsd.h +++ /dev/null @@ -1,23 +0,0 @@ -/* te-nbsd.h -- NetBSD target environment declarations. - Copyright (C) 1987, 90, 91, 92, 94, 95, 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. */ - -#define TE_NetBSD 1 -#define LOCAL_LABELS_FB 1 -#include "obj-format.h" diff --git a/contrib/binutils/gas/config/te-pe.h b/contrib/binutils/gas/config/te-pe.h deleted file mode 100644 index 1c1f0b27bc1dd..0000000000000 --- a/contrib/binutils/gas/config/te-pe.h +++ /dev/null @@ -1,7 +0,0 @@ -#define TE_PE -#define LEX_AT 1 /* can have @'s inside labels */ - -/* The PE format supports long section names. */ -#define COFF_LONG_SECTION_NAMES - -#include "obj-format.h" diff --git a/contrib/binutils/gas/config/te-ppcnw.h b/contrib/binutils/gas/config/te-ppcnw.h deleted file mode 100644 index 2ddf050381c54..0000000000000 --- a/contrib/binutils/gas/config/te-ppcnw.h +++ /dev/null @@ -1,31 +0,0 @@ -/* te-ppcnw.h -- Power PC running Netware environment declarations. - Copyright (C) 1994 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. */ - -/* Added these, because if we don't know what we're targetting we may - need an assembler version of libgcc, and that will use local - labels. */ -#define LOCAL_LABELS_DOLLAR 1 -#define LOCAL_LABELS_FB 1 - -/* these define interfaces */ -#include "obj-format.h" - -/* gcc uses escape sequences for ppc/netware */ - -#undef NO_STRING_ESCAPES diff --git a/contrib/binutils/gas/config/te-sparcaout.h b/contrib/binutils/gas/config/te-sparcaout.h deleted file mode 100644 index 63101840fa4c9..0000000000000 --- a/contrib/binutils/gas/config/te-sparcaout.h +++ /dev/null @@ -1,21 +0,0 @@ -/* te-sparcaout.h -- embedded sparc-aout target environment declarations. - Copyright (C) 1996 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. */ - -#define TE_SPARCAOUT 1 -#include "obj-format.h" diff --git a/contrib/binutils/gas/config/te-svr4.h b/contrib/binutils/gas/config/te-svr4.h deleted file mode 100644 index 7217ee119e62a..0000000000000 --- a/contrib/binutils/gas/config/te-svr4.h +++ /dev/null @@ -1,4 +0,0 @@ -#define TE_SVR4 -#define LOCAL_LABELS_FB 1 - -#include "obj-format.h" diff --git a/contrib/binutils/gas/config/te-sysv32.h b/contrib/binutils/gas/config/te-sysv32.h deleted file mode 100644 index 923e6e5799f20..0000000000000 --- a/contrib/binutils/gas/config/te-sysv32.h +++ /dev/null @@ -1,6 +0,0 @@ -/* Remove leading underscore from the gcc generated symbol names */ -#define STRIP_UNDERSCORE - -#include "obj-format.h" - -/* end of te-sysv32.h */ |