diff options
Diffstat (limited to 'gas/config')
-rw-r--r-- | gas/config/obj-coff.c | 24 | ||||
-rw-r--r-- | gas/config/obj-coff.h | 192 | ||||
-rw-r--r-- | gas/config/tc-or32.c | 1636 | ||||
-rw-r--r-- | gas/config/tc-or32.h | 63 |
4 files changed, 1810 insertions, 105 deletions
diff --git a/gas/config/obj-coff.c b/gas/config/obj-coff.c index 759389a..c956d62 100644 --- a/gas/config/obj-coff.c +++ b/gas/config/obj-coff.c @@ -1,6 +1,6 @@ /* coff object file format Copyright 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001 + 1999, 2000, 2001, 2002 Free Software Foundation, Inc. This file is part of GAS. @@ -1889,7 +1889,7 @@ count_entries_in_chain (idx) { if (fixup_ptr->fx_done == 0 && TC_COUNT_RELOC (fixup_ptr)) { -#ifdef TC_A29K +#if defined(TC_A29K) || defined(TC_OR32) if (fixup_ptr->fx_r_type == RELOC_CONSTH) nrelocs += 2; else @@ -2048,6 +2048,20 @@ do_relocs_for (abfd, h, file_cursor) ext_ptr++; } #endif +#if defined(TC_OR32) + /* The or32 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; @@ -2127,6 +2141,7 @@ fill_section (abfd, h, file_cursor) COFF_NOLOAD_PROBLEM, and have only one test here. */ #ifndef TC_I386 #ifndef TC_A29K +#ifndef TC_OR32 #ifndef COFF_NOLOAD_PROBLEM /* Apparently the SVR3 linker (and exec syscall) and UDI mondfe progrem are confused by noload sections. */ @@ -2134,6 +2149,7 @@ fill_section (abfd, h, file_cursor) #endif #endif #endif +#endif } else if (strcmp (s->s_name, ".lit") == 0) s->s_flags = STYP_LIT | STYP_TEXT; @@ -4420,7 +4436,7 @@ fixup_segment (segP, this_segment_type) break; default: -#if defined(TC_A29K) || (defined(TE_PE) && defined(TC_I386)) || defined(TC_M88K) +#if defined(TC_A29K) || (defined(TE_PE) && defined(TC_I386)) || defined(TC_M88K) || defined(TC_OR32) /* This really should be handled in the linker, but backward compatibility forbids. */ add_number += S_GET_VALUE (add_symbolP); @@ -4466,7 +4482,7 @@ fixup_segment (segP, this_segment_type) if (pcrel) { -#if !defined(TC_M88K) && !(defined(TE_PE) && defined(TC_I386)) && !defined(TC_A29K) +#if !defined(TC_M88K) && !(defined(TE_PE) && defined(TC_I386)) && !defined(TC_A29K) && !defined(TC_OR32) /* This adjustment is not correct on the m88k, for which the linker does all the computation. */ add_number -= md_pcrel_from (fixP); diff --git a/gas/config/obj-coff.h b/gas/config/obj-coff.h index 98948be..1a50359 100644 --- a/gas/config/obj-coff.h +++ b/gas/config/obj-coff.h @@ -1,6 +1,6 @@ /* coff object file format Copyright 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000 + 1999, 2000, 2002 Free Software Foundation, Inc. This file is part of GAS. @@ -90,6 +90,11 @@ #define TARGET_FORMAT "coff-a29k-big" #endif +#ifdef TC_OR32 +#include "coff/or32.h" +#define TARGET_FORMAT "coff-or32-big" +#endif + #ifdef TC_I960 #include "coff/i960.h" #define TARGET_FORMAT "coff-Intel-little" @@ -190,9 +195,7 @@ extern void coff_obj_symbol_new_hook PARAMS ((symbolS *)); 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. +/* 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. @@ -226,9 +229,7 @@ extern void coff_obj_read_begin_hook PARAMS ((void)); See doc/internals.texi for a brief discussion of the history, if you care. - Ken Raeburn, 5 May 1994 - - *********************************************************************** */ + Ken Raeburn, 5 May 1994. */ #ifdef BFD_ASSEMBLER @@ -257,10 +258,10 @@ extern void coff_obj_read_begin_hook PARAMS ((void)); extern void obj_coff_section PARAMS ((int)); -/* The number of auxiliary entries */ +/* 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 */ +/* 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. */ @@ -271,9 +272,9 @@ 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 */ +/* 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) @@ -297,15 +298,13 @@ extern void SA_SET_SYM_ENDNDX PARAMS ((symbolS *, symbolS *)); #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. - */ +/* 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 */ @@ -330,7 +329,7 @@ extern void SA_SET_SYM_ENDNDX PARAMS ((symbolS *, symbolS *)); #define SF_GET_SEGMENT (0x00200000) /* Get the section of the forward symbol. */ /* All other bits are unused. */ -/* Accessors */ +/* 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) @@ -352,7 +351,7 @@ extern void SA_SET_SYM_ENDNDX PARAMS ((symbolS *, symbolS *)); #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 */ +/* 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)) @@ -414,7 +413,7 @@ extern symbolS *coff_last_function; #endif #endif -/* sanity check */ +/* Sanity check. */ #ifdef TC_I960 #ifndef C_LEAFSTAT @@ -424,8 +423,8 @@ hey ! Where is the C_LEAFSTAT definition ? i960 - coff support is depending on i #else /* not BFD_ASSEMBLER */ -#ifdef TC_A29K -/* Allow translate from aout relocs to coff relocs */ +#if defined TC_A29K || defined TC_OR32 +/* Allow translate from aout relocs to coff relocs. */ #define NO_RELOC 20 #define RELOC_32 1 #define RELOC_8 2 @@ -447,7 +446,7 @@ extern const segT N_TYPE_seg[]; /* SYMBOL TABLE */ -/* Symbol table entry data type */ +/* Symbol table entry data type. */ typedef struct { @@ -455,18 +454,17 @@ typedef struct struct internal_syment ost_entry; /* Auxiliary entry. */ union internal_auxent ost_auxent[OBJ_COFF_MAX_AUXENTRIES]; - /* obj_coff internal use only flags */ + /* 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 */ +/* Symbol table macros and constants. */ /* Possible and usefull section number in symbol table - * The values of TEXT, DATA and BSS may not be portable. - */ + The values of TEXT, DATA and BSS may not be portable. */ #define C_ABS_SECTION N_ABS #define C_UNDEF_SECTION N_UNDEF @@ -475,27 +473,25 @@ typedef struct #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. - */ +/* 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 */ +/* 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) */ + 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 */ +/* 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 */ +/* 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)) \ @@ -504,13 +500,11 @@ typedef struct || (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 */ +/* 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) - */ +/* 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. */ @@ -526,41 +520,41 @@ typedef struct ((s)->sy_symbol.ost_entry.n_sclass == C_WEAKEXT) #endif -/* Accessors */ -/* The name of the symbol */ +/* 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 */ +/* The pointer to the string table. */ #define S_GET_OFFSET(s) ((s)->sy_symbol.ost_entry.n_offset) -/* The numeric value of the segment */ +/* The numeric value of the segment. */ #define S_GET_SEGMENT(s) s_get_segment(s) -/* The data type */ +/* The data type. */ #define S_GET_DATA_TYPE(s) ((s)->sy_symbol.ost_entry.n_type) -/* The storage class */ +/* The storage class. */ #define S_GET_STORAGE_CLASS(s) ((s)->sy_symbol.ost_entry.n_sclass) -/* The number of auxiliary entries */ +/* 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 */ +/* 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 */ +/* 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 */ +/* 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 */ +/* The data type. */ #define S_SET_DATA_TYPE(s,v) ((s)->sy_symbol.ost_entry.n_type = (v)) -/* The storage class */ +/* The storage class. */ #define S_SET_STORAGE_CLASS(s,v) ((s)->sy_symbol.ost_entry.n_sclass = (v)) -/* The number of auxiliary entries */ +/* 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) */ +/* 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 */ +/* 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) @@ -577,7 +571,7 @@ typedef struct #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 */ +/* 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)) @@ -592,15 +586,13 @@ typedef struct #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. - */ +/* 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 */ @@ -626,7 +618,7 @@ typedef struct #define SF_ADJ_LNNOPTR (0x00400000) /* Has a lnnoptr */ /* All other bits are unused. */ -/* Accessors */ +/* 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) @@ -648,7 +640,7 @@ typedef struct #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 */ +/* 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)) @@ -671,12 +663,10 @@ typedef struct #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 header macro and type definition. */ -/* - * File position calculators. Beware to use them when all the - * appropriate fields are set in the header. - */ +/* 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) @@ -714,8 +704,8 @@ typedef struct H_GET_TEXT_SIZE(h) + H_GET_DATA_SIZE(h) + \ H_GET_RELOCATION_SIZE(h) + H_GET_LINENO_SIZE(h)) -/* Accessors */ -/* aouthdr */ +/* 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) @@ -724,7 +714,7 @@ typedef struct #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 */ +/* 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) @@ -733,7 +723,7 @@ typedef struct #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 */ +/* 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) @@ -750,8 +740,8 @@ typedef struct #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 */ +/* 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)) @@ -760,7 +750,7 @@ typedef struct #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 */ +/* 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)) @@ -768,30 +758,30 @@ typedef struct #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 */ +/* 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 */ +/* 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 */ + 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 */ + 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) @@ -823,7 +813,7 @@ extern void c_section_header PARAMS ((struct internal_scnhdr * header, void tc_coff_symbol_emit_hook PARAMS ((symbolS *)); #endif -/* sanity check */ +/* Sanity check. */ #ifdef TC_I960 #ifndef C_LEAFSTAT diff --git a/gas/config/tc-or32.c b/gas/config/tc-or32.c new file mode 100644 index 0000000..4f0c2ec --- /dev/null +++ b/gas/config/tc-or32.c @@ -0,0 +1,1636 @@ +/* Assembly backend for the OpenRISC 1000. + Copyright (C) 2002 Free Software Foundation, Inc. + Contributed by Damjan Lampret <lampret@opencores.org>. + Modified bu Johan Rydberg, <johan.rydberg@netinsight.se>. + Based upon a29k port. + + 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. */ + +/* tc-a29k.c used as a template. */ + +#include "safe-ctype.h" +#include "as.h" +#include "opcode/or32.h" + +#ifdef BFD_ASSEMBLER +#include "elf/or32.h" +#endif + +#define DEBUG 0 + +#ifndef REGISTER_PREFIX +#define REGISTER_PREFIX '%' +#endif + +/* Make it easier to clone this machine desc into another one. */ +#define machine_opcode or32_opcode +#define machine_opcodes or32_opcodes +#define machine_ip or32_ip +#define machine_it or32_it + +/* Handle of the OPCODE hash table. */ +static struct hash_control *op_hash = NULL; + +struct machine_it + { + char * error; + unsigned long opcode; + struct nlist * nlistp; + expressionS exp; + int pcrel; + int reloc_offset; /* Offset of reloc within insn. */ + int reloc; + } +the_insn; + +static void machine_ip PARAMS ((char *)); + +const pseudo_typeS md_pseudo_table[] = + { + {"align", s_align_bytes, 4 }, + {"space", s_space, 0 }, + {"cputype", s_ignore, 0 }, + {"reg", s_lsym, 0 }, /* Register equate, same as equ. */ + {"sect", s_ignore, 0 }, /* Creation of coff sections. */ + {"proc", s_ignore, 0 }, /* Start of a function. */ + {"endproc", s_ignore, 0 }, /* Function end. */ + {"word", cons, 4 }, + {NULL, 0, 0 }, + }; + +int md_short_jump_size = 4; +int md_long_jump_size = 4; + +#if defined(BFD_HEADERS) +#ifdef RELSZ +const int md_reloc_size = RELSZ; /* Coff headers. */ +#else +const int md_reloc_size = 12; /* Something else headers. */ +#endif +#else +const int md_reloc_size = 12; /* Not bfdized. */ +#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[] = "#"; + +/* We needed an unused char for line separation to work around the + lack of macros, using sed and such. */ +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"; + +/* "l.jalr r9" precalculated opcode. */ +static unsigned long jalr_r9_opcode; + + +static int check_invalid_opcode PARAMS ((unsigned long)); +static void encode PARAMS ((const struct machine_opcode *, unsigned long *, signed long, char)); +#ifdef BFD_ASSEMBLER +static char * parse_operand PARAMS ((char *, expressionS *, int)); +#endif + +/* Set bits in machine opcode according to insn->encoding + description and passed operand. */ + +static void +encode (insn, opcode, param_val, param_ch) + const struct machine_opcode *insn; + unsigned long *opcode; + signed long param_val; + char param_ch; +{ + int opc_pos = 0; + int param_pos = 0; + char *enc; + +#if DEBUG + printf (" encode: opcode=%.8lx param_val=%.8lx abs=%.8lx param_ch=%c\n", + *opcode, param_val, abs (param_val), param_ch); +#endif + for (enc = insn->encoding; *enc != '\0'; enc++) + if (*enc == param_ch) + { + if (enc - 2 >= insn->encoding && (*(enc - 2) == '0') && (*(enc - 1) == 'x')) + continue; + else + param_pos ++; + } + + opc_pos = 32; + + for (enc = insn->encoding; *enc != '\0';) + { + if ((*enc == '0') && (*(enc + 1) == 'x')) + { + int tmp = strtol (enc, NULL, 16); + + opc_pos -= 4; + *opcode |= tmp << opc_pos; + enc += 3; + } + else if ((*enc == '0') || (*enc == '-')) + { + opc_pos--; + enc++; + } + else if (*enc == '1') + { + opc_pos--; + *opcode |= 1 << opc_pos; + enc++; + } + else if (*enc == param_ch) + { + opc_pos--; + param_pos--; + *opcode |= ((param_val >> param_pos) & 0x1) << opc_pos; + enc++; + } + else if (ISALPHA (*enc)) + { + opc_pos--; + enc++; + } + else + enc++; + } + +#if DEBUG + printf (" opcode=%.8lx\n", *opcode); +#endif +} + +/* 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 () +{ + const char *retval = NULL; + int lose = 0; + int skipnext = 0; + unsigned int i; + + /* Hash up all the opcodes for fast use later. */ + op_hash = hash_new (); + + for (i = 0; i < or32_num_opcodes; i++) + { + const char *name = machine_opcodes[i].name; + + if (skipnext) + { + skipnext = 0; + continue; + } + + retval = hash_insert (op_hash, name, (PTR) &machine_opcodes[i]); + if (retval != NULL) + { + fprintf (stderr, "internal error: can't hash `%s': %s\n", + machine_opcodes[i].name, retval); + lose = 1; + } + } + + if (lose) + as_fatal (_("Broken assembler. No assembly attempted.")); + + encode (&machine_opcodes[insn_index ("l.jalr")], &jalr_r9_opcode, 9, 'B'); +} + +/* Returs non zero if instruction is to be used. */ + +static int +check_invalid_opcode (opcode) + unsigned long opcode; +{ + return opcode == jalr_r9_opcode; +} + +/* Assemble a single instruction. Its label has already been handled + by the generic front end. We just parse opcode and operands, and + produce the bytes of data and relocation. */ + +void +md_assemble (str) + char *str; +{ + char *toP; + +#if DEBUG + printf ("NEW INSTRUCTION\n"); +#endif + + know (str); + machine_ip (str); + toP = frag_more (4); + + /* Put out the opcode. */ + md_number_to_chars (toP, the_insn.opcode, 4); + + /* Put out the symbol-dependent stuff. */ +#ifdef BFD_ASSEMBLER + if (the_insn.reloc != BFD_RELOC_NONE) +#else + if (the_insn.reloc != NO_RELOC) +#endif + { + fix_new_exp (frag_now, + (toP - frag_now->fr_literal + the_insn.reloc_offset), + 4, /* size */ + &the_insn.exp, + the_insn.pcrel, + the_insn.reloc); + } +} + +/* This is true of the we have issued a "lo(" or "hi"(. */ +static int waiting_for_shift = 0; + +static int mask_or_shift = 0; + +#ifdef BFD_ASSEMBLER +static char * +parse_operand (s, operandp, opt) + char *s; + expressionS *operandp; + int opt; +{ + char *save = input_line_pointer; + char *new; + +#if DEBUG + printf (" PROCESS NEW OPERAND(%s) == %c (%d)\n", s, opt ? opt : '!', opt); +#endif + + input_line_pointer = s; + + if (strncasecmp (s, "HI(", 3) == 0) + { + waiting_for_shift = 1; + mask_or_shift = BFD_RELOC_HI16; + + input_line_pointer += 3; + } + else if (strncasecmp (s, "LO(", 3) == 0) + { + mask_or_shift = BFD_RELOC_LO16; + + input_line_pointer += 3; + } + else + mask_or_shift = 0; + + if ((*s == '(') && (*(s+1) == 'r')) + s++; + + if ((*s == 'r') && ISDIGIT (*(s + 1))) + { + operandp->X_add_number = strtol (s + 1, NULL, 10); + operandp->X_op = O_register; + for (; (*s != ',') && (*s != '\0');) + s++; + input_line_pointer = save; + return s; + } + + expression (operandp); + + if (operandp->X_op == O_absent) + { + if (! opt) + as_bad (_("missing operand")); + else + { + operandp->X_add_number = 0; + operandp->X_op = O_constant; + } + } + + new = input_line_pointer; + input_line_pointer = save; + +#if DEBUG + printf (" %s=parse_operand(%s): operandp->X_op = %u\n", new, s, operandp->X_op); +#endif + + return new; +} +#else + +char * +parse_operand (s, operandp, opt) + char *s; + expressionS *operandp; + int opt; +{ + char *save = input_line_pointer; + char *new; + +#if DEBUG + printf (" PROCESS NEW OPERAND(%s) == %c (%d)\n", s, opt ? opt : '!', opt); +#endif + + input_line_pointer = s; + + if (strncasecmp (s, "HI(", 3) == 0) + { + waiting_for_shift = 1; + mask_or_shift = RELOC_CONSTH; + + input_line_pointer += 3; + } + else if (strncasecmp (s, "LO(", 3) == 0) + { + mask_or_shift = RELOC_CONST; + + input_line_pointer += 3; + } + else + mask_or_shift = 0; + + + expression (operandp); + + if (operandp->X_op == O_absent) + { + if (! opt) + as_bad (_("missing operand")); + else + { + operandp->X_add_number = 0; + operandp->X_op = O_constant; + } + } + + new = input_line_pointer; + input_line_pointer = save; + + if ((operandp->X_op == O_symbol) && (*s != '_')) + { +#if DEBUG + printf ("symbol: '%s'\n", save); +#endif + + for (save = s; s < new; s++) + if ((*s == REGISTER_PREFIX) && (*(s + 1) == 'r')) /* Register prefix. */ + s++; + + if ((*s == 'r') && ISDIGIT (*(s + 1))) + { + operandp->X_add_number = strtol (s + 1, NULL, 10); + operandp->X_op = O_register; + } + s = save; + } + +#if DEBUG + printf (" %s=parse_operand(%s): operandp->X_op = %u\n", new, s, operandp->X_op); +#endif + + return new; +} +#endif + +/* Instruction parsing. Takes a string containing the opcode. + Operands are at input_line_pointer. Output is in the_insn. + Warnings or errors are generated. */ + +#ifdef BFD_ASSEMBLER +static void +machine_ip (str) + char *str; +{ + char *s; + const char *args; + const struct machine_opcode *insn; + char *argsStart; + unsigned long opcode; + expressionS the_operand; + expressionS *operand = &the_operand; + unsigned int regno; + int reloc = BFD_RELOC_NONE; + +#if DEBUG + printf ("machine_ip(%s)\n", str); +#endif + + s = str; + for (; ISALNUM (*s) || *s == '.'; ++s) + if (ISUPPER (*s)) + *s = TOLOWER (*s); + + switch (*s) + { + case '\0': + break; + + case ' ': /* FIXME-SOMEDAY more whitespace. */ + *s++ = '\0'; + break; + + default: + as_bad (_("unknown opcode1: `%s'"), str); + return; + } + + if ((insn = (struct machine_opcode *) hash_find (op_hash, str)) == NULL) + { + as_bad (_("unknown opcode2 `%s'."), str); + return; + } + + argsStart = s; + opcode = 0; + memset (&the_insn, '\0', sizeof (the_insn)); + the_insn.reloc = BFD_RELOC_NONE; + + reloc = BFD_RELOC_NONE; + + /* Build the opcode, checking as we go to make sure that the + operands match. + + If an operand matches, we modify the_insn or opcode appropriately, + and do a "continue". If an operand fails to match, we "break". */ + if (insn->args[0] != '\0') + { + /* Prime the pump. */ + s = parse_operand (s, operand, insn->args[0] == 'I'); + } + + for (args = insn->args;; ++args) + { +#if DEBUG + printf (" args = %s\n", args); +#endif + switch (*args) + { + case '\0': /* End of args. */ + /* We have have 0 args, do the bazoooka! */ + if (args == insn->args) + encode (insn, &opcode, 0, 0); + + if (*s == '\0') + { + /* We are truly done. */ + the_insn.opcode = opcode; + if (check_invalid_opcode (opcode)) + as_bad (_("instruction not allowed: %s"), str); + return; + } + as_bad (_("too many operands: %s"), s); + break; + + case ',': /* Must match a comma. */ + if (*s++ == ',') + { + reloc = BFD_RELOC_NONE; + + /* Parse next operand. */ + s = parse_operand (s, operand, args[1] == 'I'); +#if DEBUG + printf (" ',' case: operand->X_add_number = %d, *args = %s, *s = %s\n", + operand->X_add_number, args, s); +#endif + continue; + } + break; + + case '(': /* Must match a (. */ + s = parse_operand (s, operand, args[1] == 'I'); + continue; + + case ')': /* Must match a ). */ + continue; + + case 'r': /* A general register. */ + args++; + + if (operand->X_op != O_register) + break; /* Only registers. */ + + know (operand->X_add_symbol == 0); + know (operand->X_op_symbol == 0); + regno = operand->X_add_number; + encode (insn, &opcode, regno, *args); +#if DEBUG + printf (" r: operand->X_op = %d\n", operand->X_op); +#endif + continue; + + default: + /* if (! ISALPHA (*args)) + break; */ /* Only immediate values. */ + + if (mask_or_shift) + { +#if DEBUG + printf ("mask_or_shift = %d\n", mask_or_shift); +#endif + reloc = mask_or_shift; + } + mask_or_shift = 0; + + if (strncasecmp (args, "LO(", 3) == 0) + { +#if DEBUG + printf ("reloc_const\n"); +#endif + reloc = BFD_RELOC_LO16; + } + else if (strncasecmp (args, "HI(", 3) == 0) + { +#if DEBUG + printf ("reloc_consth\n"); +#endif + reloc = BFD_RELOC_HI16; + } + + if (*s == '(') + { + operand->X_op = O_constant; +#if 0 + operand->X_add_number = 0; /* ??? if enabled load/store offsets + are zero. */ +#endif + } + else if (*s == ')') + s += 1; +#if DEBUG + printf (" default case: operand->X_add_number = %d, *args = %s, *s = %s\n", operand->X_add_number, args, s); +#endif + if (operand->X_op == O_constant) + { + if (reloc == BFD_RELOC_NONE) + { + bfd_vma v, mask; + + mask = 0x3ffffff; + v = abs (operand->X_add_number) & ~ mask; + if (v) + as_bad (_("call/jmp target out of range (1)")); + } + + if (reloc == BFD_RELOC_HI16) + operand->X_add_number = ((operand->X_add_number >> 16) & 0xffff); + + the_insn.pcrel = 0; + encode (insn, &opcode, operand->X_add_number, *args); + /* the_insn.reloc = BFD_RELOC_NONE; */ + continue; + } + + if (reloc == BFD_RELOC_NONE) + the_insn.reloc = BFD_RELOC_32_GOT_PCREL; + else + the_insn.reloc = reloc; + + /* the_insn.reloc = insn->reloc; */ +#if DEBUG + printf (" reloc sym=%d\n", the_insn.reloc); + printf (" BFD_RELOC_NONE=%d\n", BFD_RELOC_NONE); +#endif + the_insn.exp = *operand; + + /* the_insn.reloc_offset = 1; */ + the_insn.pcrel = 1; /* Assume PC-relative jump. */ + + /* FIXME-SOON, Do we figure out whether abs later, after + know sym val? */ + if (reloc == BFD_RELOC_LO16 || reloc == BFD_RELOC_HI16) + the_insn.pcrel = 0; + + encode (insn, &opcode, operand->X_add_number, *args); + continue; + } + + /* Types or values of args don't match. */ + as_bad (_("invalid operands")); + return; + } +} + +#else + +static void +machine_ip (str) + char *str; +{ + char *s; + const char *args; + const struct machine_opcode *insn; + char *argsStart; + unsigned long opcode; + expressionS the_operand; + expressionS *operand = &the_operand; + unsigned int regno; + int reloc = NO_RELOC; + +#if DEBUG + printf ("machine_ip(%s)\n", str); +#endif + + s = str; + for (; ISALNUM (*s) || *s == '.'; ++s) + if (ISUPPER (*s)) + *s = TOLOWER (*s); + + switch (*s) + { + case '\0': + break; + + case ' ': /* FIXME-SOMEDAY more whitespace. */ + *s++ = '\0'; + break; + + default: + as_bad (_("unknown opcode1: `%s'"), str); + return; + } + + if ((insn = (struct machine_opcode *) hash_find (op_hash, str)) == NULL) + { + as_bad (_("unknown opcode2 `%s'."), str); + return; + } + + argsStart = s; + opcode = 0; + memset (&the_insn, '\0', sizeof (the_insn)); + the_insn.reloc = NO_RELOC; + + reloc = NO_RELOC; + + /* Build the opcode, checking as we go to make sure that the + operands match. + + If an operand matches, we modify the_insn or opcode appropriately, + and do a "continue". If an operand fails to match, we "break". */ + if (insn->args[0] != '\0') + /* Prime the pump. */ + s = parse_operand (s, operand, + insn->args[0] == 'I' + || strcmp (insn->name, "l.nop") == 0); + + for (args = insn->args;; ++args) + { +#if DEBUG + printf (" args = %s\n", args); +#endif + switch (*args) + { + case '\0': /* End of args. */ + /* We have have 0 args, do the bazoooka! */ + if (args == insn->args) + encode (insn, &opcode, 0, 0); + + if (*s == '\0') + { + /* We are truly done. */ + the_insn.opcode = opcode; + if (check_invalid_opcode (opcode)) + as_bad (_("instruction not allowed: %s"), str); + return; + } + as_bad (_("too many operands: %s"), s); + break; + + case ',': /* Must match a comma. */ + if (*s++ == ',') + { + reloc = NO_RELOC; + + /* Parse next operand. */ + s = parse_operand (s, operand, args[1] == 'I'); +#if DEBUG + printf (" ',' case: operand->X_add_number = %d, *args = %s, *s = %s\n", + operand->X_add_number, args, s); +#endif + continue; + } + break; + + case '(': /* Must match a (. */ + s = parse_operand (s, operand, args[1] == 'I'); + continue; + + case ')': /* Must match a ). */ + continue; + + case 'r': /* A general register. */ + args++; + + if (operand->X_op != O_register) + break; /* Only registers. */ + + know (operand->X_add_symbol == 0); + know (operand->X_op_symbol == 0); + regno = operand->X_add_number; + encode (insn, &opcode, regno, *args); +#if DEBUG + printf (" r: operand->X_op = %d\n", operand->X_op); +#endif + continue; + + default: + /* if (! ISALPHA (*args)) + break; */ /* Only immediate values. */ + + if (mask_or_shift) + { +#if DEBUG + printf ("mask_or_shift = %d\n", mask_or_shift); +#endif + reloc = mask_or_shift; + } + mask_or_shift = 0; + + if (strncasecmp (args, "LO(", 3) == 0) + { +#if DEBUG + printf ("reloc_const\n"); +#endif + reloc = RELOC_CONST; + } + else if (strncasecmp (args, "HI(", 3) == 0) + { +#if DEBUG + printf ("reloc_consth\n"); +#endif + reloc = RELOC_CONSTH; + } + + if (*s == '(') + { + operand->X_op = O_constant; +#if 0 + operand->X_add_number = 0; /* ??? if enabled load/store offsets + are zero. */ +#endif + } + else if (*s == ')') + s += 1; +#if DEBUG + printf (" default case: operand->X_add_number = %d, *args = %s, *s = %s\n", + operand->X_add_number, args, s); +#endif + if (operand->X_op == O_constant) + { + if (reloc == NO_RELOC) + { + unsigned long v, mask; + + mask = 0x3ffffff; + v = abs (operand->X_add_number) & ~ mask; + if (v) + as_bad (_("call/jmp target out of range (1)")); + } + + if (reloc == RELOC_CONSTH) + operand->X_add_number = ((operand->X_add_number>>16) & 0xffff); + + the_insn.pcrel = 0; + encode (insn, &opcode, operand->X_add_number, *args); + /* the_insn.reloc = NO_RELOC; */ + continue; + } + + if (reloc == NO_RELOC) + the_insn.reloc = RELOC_JUMPTARG; + else + the_insn.reloc = reloc; +#if DEBUG + printf (" reloc sym=%d\n", the_insn.reloc); + printf (" NO_RELOC=%d\n", NO_RELOC); +#endif + the_insn.exp = *operand; + + /* the_insn.reloc_offset = 1; */ + the_insn.pcrel = 1; /* Assume PC-relative jump. */ + + /* FIXME-SOON, Do we figure out whether abs later, after + know sym val? */ + if (reloc == RELOC_CONST || reloc == RELOC_CONSTH) + the_insn.pcrel = 0; + + encode (insn, &opcode, operand->X_add_number, *args); + continue; + } + + /* Types or values of args don't match. */ + as_bad (_("invalid operands")); + return; + } +} +#endif + +/* 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 prec; + LITTLENUM_TYPE words[MAX_LITTLENUMS]; + LITTLENUM_TYPE *wordP; + 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); + + for (wordP = words; prec--;) + { + md_number_to_chars (litP, (valueT) (*wordP++), sizeof (LITTLENUM_TYPE)); + litP += sizeof (LITTLENUM_TYPE); + } + + return NULL; +} + +/* Write out big-endian. */ + +void +md_number_to_chars (buf, val, n) + char *buf; + valueT val; + int n; +{ + number_to_chars_bigendian (buf, val, n); +} + +#ifdef BFD_ASSEMBLER +void +md_apply_fix3 (fixP, val, seg) + fixS * fixP; + valueT * val; + segT seg ATTRIBUTE_UNUSED; +{ + char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; + long t_val; + + t_val = (long) *val; + +#if DEBUG + printf ("md_apply_fix val:%x\n", t_val); +#endif + + fixP->fx_addnumber = t_val; /* Remember value for emit_reloc. */ + + know (fixP->fx_size == 4); + know (fixP->fx_r_type < BFD_RELOC_NONE); + + switch (fixP->fx_r_type) + { + case BFD_RELOC_32: /* XXXXXXXX pattern in a word. */ +#if DEBUG + printf ("reloc_const: val=%x\n", t_val); +#endif + buf[0] = t_val >> 24; + buf[1] = t_val >> 16; + buf[2] = t_val >> 8; + buf[3] = t_val; + break; + + case BFD_RELOC_16: /* XXXX0000 pattern in a word. */ +#if DEBUG + printf ("reloc_const: val=%x\n", t_val); +#endif + buf[0] = t_val >> 8; + buf[1] = t_val; + break; + + case BFD_RELOC_8: /* XX000000 pattern in a word. */ +#if DEBUG + printf ("reloc_const: val=%x\n", t_val); +#endif + buf[0] = t_val; + break; + + case BFD_RELOC_LO16: /* 0000XXXX pattern in a word. */ +#if DEBUG + printf ("reloc_const: val=%x\n", t_val); +#endif + buf[2] = t_val >> 8; /* Holds bits 0000XXXX. */ + buf[3] = t_val; + break; + + case BFD_RELOC_HI16: /* 0000XXXX pattern in a word. */ +#if DEBUG + printf ("reloc_consth: val=%x\n", t_val); +#endif + buf[2] = t_val >> 24; /* Holds bits XXXX0000. */ + buf[3] = t_val >> 16; + break; + + case BFD_RELOC_32_GOT_PCREL: /* 0000XXXX pattern in a word. */ + if (!fixP->fx_done) + { + /* The linker tries to support both AMD and old GNU style + R_IREL relocs. That means that if the addend is exactly + the negative of the address within the section, the + linker will not handle it correctly. */ +#if 0 + if (fixP->fx_pcrel + && t_val != 0 + && t_val == - (fixP->fx_frag->fr_address + fixP->fx_where)) + as_bad_where + (fixP->fx_file, fixP->fx_line, + _("the linker will not handle this relocation correctly (1)")); +#endif + } + else if (fixP->fx_pcrel) + { + long v = t_val >> 28; + + if (v != 0 && v != -1) + as_bad_where (fixP->fx_file, fixP->fx_line, + _("call/jmp target out of range (2)")); + } + else + /* This case was supposed to be handled in machine_ip. */ + abort (); + + buf[0] |= (t_val >> 26) & 0x03; /* Holds bits 0FFFFFFC of address. */ + buf[1] = t_val >> 18; + buf[2] = t_val >> 10; + buf[3] = t_val >> 2; + break; + + case BFD_RELOC_VTABLE_INHERIT: + case BFD_RELOC_VTABLE_ENTRY: + fixP->fx_done = 0; + break; + + case BFD_RELOC_NONE: + default: + as_bad (_("bad relocation type: 0x%02x"), fixP->fx_r_type); + break; + } + + if (fixP->fx_addsy == (symbolS *) NULL) + fixP->fx_done = 1; +} +#else +void +md_apply_fix3 (fixP, valP, seg) + fixS *fixP; + valueT *valP; + segT seg ATTRIBUTE_UNUSED; +{ + long val = *(long*)valP; + char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; + +#if DEBUG + printf ("md_apply_fix val:%x\n", val); +#endif + + fixP->fx_addnumber = val; /* Remember value for emit_reloc. */ + + know (fixP->fx_size == 4); + know (fixP->fx_r_type < NO_RELOC); + + /* This is a hack. There should be a better way to handle this. */ + if (fixP->fx_r_type == RELOC_WDISP30 && fixP->fx_addsy) + val += fixP->fx_where + fixP->fx_frag->fr_address; + + switch (fixP->fx_r_type) + { + case RELOC_32: + buf[0] = val >> 24; + buf[1] = val >> 16; + buf[2] = val >> 8; + buf[3] = val; + break; + + case RELOC_8: + buf[0] = val; + break; + + case RELOC_WDISP30: + val = (val >>= 2) + 1; + buf[0] |= (val >> 24) & 0x3f; + buf[1] = (val >> 16); + buf[2] = val >> 8; + buf[3] = val; + break; + + case RELOC_HI22: + buf[1] |= (val >> 26) & 0x3f; + buf[2] = val >> 18; + buf[3] = val >> 10; + break; + + case RELOC_LO10: + buf[2] |= (val >> 8) & 0x03; + buf[3] = val; + break; + + case RELOC_BASE13: + buf[2] |= (val >> 8) & 0x1f; + buf[3] = val; + break; + + case RELOC_WDISP22: + val = (val >>= 2) + 1; + /* FALLTHROUGH */ + case RELOC_BASE22: + buf[1] |= (val >> 16) & 0x3f; + buf[2] = val >> 8; + buf[3] = val; + break; + + case RELOC_JUMPTARG: /* 0000XXXX pattern in a word. */ + if (!fixP->fx_done) + { + /* The linker tries to support both AMD and old GNU style + R_IREL relocs. That means that if the addend is exactly + the negative of the address within the section, the + linker will not handle it correctly. */ +#if 0 + if (fixP->fx_pcrel + && val != 0 + && val == - (fixP->fx_frag->fr_address + fixP->fx_where)) + as_bad_where + (fixP->fx_file, fixP->fx_line, + _("the linker will not handle this relocation correctly (1)")); +#endif + } + else if (fixP->fx_pcrel) + { + long v = val >> 28; +#if 1 + if (v != 0 && v != -1) + as_bad_where (fixP->fx_file, fixP->fx_line, + _("call/jmp target out of range (2)")); +#endif + } + else + /* This case was supposed to be handled in machine_ip. */ + abort (); + + buf[0] |= (val >> 26) & 0x03; /* Holds bits 0FFFFFFC of address. */ + buf[1] = val >> 18; + buf[2] = val >> 10; + buf[3] = val >> 2; + break; + + case RELOC_CONST: /* 0000XXXX pattern in a word. */ +#if DEBUG + printf ("reloc_const: val=%x\n", val); +#endif + buf[2] = val >> 8; /* Holds bits 0000XXXX. */ + buf[3] = val; + break; + + case RELOC_CONSTH: /* 0000XXXX pattern in a word. */ +#if DEBUG + printf ("reloc_consth: val=%x\n", val); +#endif + buf[2] = val >> 24; /* Holds bits XXXX0000. */ + buf[3] = val >> 16; + break; + + case BFD_RELOC_VTABLE_INHERIT: + case BFD_RELOC_VTABLE_ENTRY: + fixP->fx_done = 0; + break; + + case NO_RELOC: + default: + as_bad (_("bad relocation type: 0x%02x"), fixP->fx_r_type); + break; + } + + if (fixP->fx_addsy == (symbolS *) NULL) + fixP->fx_done = 1; +} +#endif + +#ifdef OBJ_COFF +short +tc_coff_fix2rtype (fixP) + fixS *fixP; +{ +#if DEBUG + printf ("tc_coff_fix2rtype\n"); +#endif + + switch (fixP->fx_r_type) + { + case RELOC_32: + return (R_WORD); + case RELOC_8: + return (R_BYTE); + case RELOC_CONST: + return (R_ILOHALF); + case RELOC_CONSTH: + return (R_IHIHALF); + case RELOC_JUMPTARG: + return (R_IREL); + default: + printf ("need %d\n", fixP->fx_r_type); + abort (); + } + + return 0; +} + +#endif /* OBJ_COFF */ + +/* Should never be called for or32. */ + +void +md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol) + char * ptr ATTRIBUTE_UNUSED; + addressT from_addr ATTRIBUTE_UNUSED; + addressT to_addr ATTRIBUTE_UNUSED; + fragS * frag ATTRIBUTE_UNUSED; + symbolS * to_symbol ATTRIBUTE_UNUSED; +{ + as_fatal ("or32_create_short_jmp\n"); +} + +/* Should never be called for or32. */ + +#ifndef BFD_ASSEMBLER +void +md_convert_frag (headers, seg, fragP) + object_headers * headers ATTRIBUTE_UNUSED; + segT seg ATTRIBUTE_UNUSED; + register fragS * fragP ATTRIBUTE_UNUSED; +{ + as_fatal ("or32_convert_frag\n"); +} + +#else +void +md_convert_frag (headers, seg, fragP) + bfd * headers ATTRIBUTE_UNUSED; + segT seg ATTRIBUTE_UNUSED; + fragS * fragP ATTRIBUTE_UNUSED; +{ + as_fatal ("or32_convert_frag\n"); +} +#endif + +/* Should never be called for or32. */ + +void +md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol) + char * ptr ATTRIBUTE_UNUSED; + addressT from_addr ATTRIBUTE_UNUSED; + addressT to_addr ATTRIBUTE_UNUSED; + fragS * frag ATTRIBUTE_UNUSED; + symbolS * to_symbol ATTRIBUTE_UNUSED; +{ + as_fatal ("or32_create_long_jump\n"); +} + +/* Should never be called for or32. */ + +int +md_estimate_size_before_relax (fragP, segtype) + fragS * fragP ATTRIBUTE_UNUSED; + segT segtype ATTRIBUTE_UNUSED; +{ + as_fatal ("or32_estimate_size_before_relax\n"); + return 0; +} + +/* Translate internal representation of relocation info to target format. + + On sparc/29k: first 4 bytes are normal unsigned long address, next three + bytes are index, most sig. byte first. Byte 7 is broken up with + bit 7 as external, bits 6 & 5 unused, and the lower + five bits as relocation type. Next 4 bytes are long addend. */ +/* Thanx and a tip of the hat to Michael Bloom, mb@ttidca.tti.com. */ + +#ifdef OBJ_AOUT +void +tc_aout_fix_to_chars (where, fixP, segment_address_in_file) + char *where; + fixS *fixP; + relax_addressT segment_address_in_file; +{ + long r_symbolnum; + +#if DEBUG + printf ("tc_aout_fix_to_chars\n"); +#endif + + know (fixP->fx_r_type < BFD_RELOC_NONE); + know (fixP->fx_addsy != NULL); + + md_number_to_chars + (where, + 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[4] = (r_symbolnum >> 16) & 0x0ff; + where[5] = (r_symbolnum >> 8) & 0x0ff; + where[6] = r_symbolnum & 0x0ff; + where[7] = (((!S_IS_DEFINED (fixP->fx_addsy)) << 7) & 0x80) | (0 & 0x60) | (fixP->fx_r_type & 0x1F); + + /* Also easy. */ + md_number_to_chars (&where[8], fixP->fx_addnumber, 4); +} + +#endif /* OBJ_AOUT */ + +const char *md_shortopts = ""; + +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 ATTRIBUTE_UNUSED; + char * arg ATTRIBUTE_UNUSED; +{ + return 0; +} + +void +md_show_usage (stream) + FILE * stream ATTRIBUTE_UNUSED; +{ +} + +/* This is called when a line is unrecognized. This is used to handle + definitions of or32 style local labels. */ + +int +or32_unrecognized_line (c) + int c; +{ + int lab; + char *s; + + if (c != '$' + || ! ISDIGIT ((unsigned char) input_line_pointer[0])) + return 0; + + s = input_line_pointer; + + lab = 0; + while (ISDIGIT ((unsigned char) *s)) + { + lab = lab * 10 + *s - '0'; + ++s; + } + + if (*s != ':') + /* Not a label definition. */ + return 0; + + if (dollar_label_defined (lab)) + { + as_bad (_("label \"$%d\" redefined"), lab); + return 0; + } + + define_dollar_label (lab); + colon (dollar_label_name (lab, 0)); + input_line_pointer = s + 1; + + return 1; +} + +#ifndef BFD_ASSEMBLER +/* Record a fixup for a cons expression. */ +/* + void +or32_cons_fix_new (frag, where, nbytes, exp) + fragS *frag; + int where; + int nbytes; + expressionS *exp; +{ + fix_new_exp (frag, where, nbytes, exp, 0, + nbytes == 5 ? RELOC_32 + : nbytes == 2 ? RELOC_16 + : RELOC_8); +} +void +tc_aout_pre_write_hook () +{ +#if DEBUG + printf ("In tc_aout_pre_write_hook()\n"); +#endif +} +*/ +#endif + +/* Default the values of symbols known that should be "predefined". We + don't bother to predefine them unless you actually use one, since there + are a lot of them. */ + +symbolS * +md_undefined_symbol (name) + char *name ATTRIBUTE_UNUSED; +{ +#ifndef BFD_ASSEMBLER + long regnum; + char testbuf[5 + /*SLOP*/ 5]; + +#if DEBUG + printf ("md_undefined_symbol(%s)\n", name); +#endif + + /* Register name. */ + if (name[0] == 'r' || name[0] == 'R' || name[0] == 'a' || name[0] == 'b') + { + long maxreg; + + /* Parse the number, make sure it has no extra zeroes or + trailing chars. */ + regnum = atol (& name[1]); + + if (regnum > 31) + as_fatal (_("register out of range")); + + sprintf (testbuf, "%ld", regnum); + + if (strcmp (testbuf, &name[1]) != 0) + return NULL; /* gr007 or lr7foo or whatever. */ + + /* We have a wiener! Define and return a new symbol for it. */ + return (symbol_new (name, SEG_REGISTER, (valueT) regnum, + &zero_address_frag)); + } +#endif + return NULL; +} + +/* Parse an operand that is machine-specific. */ + +void +md_operand (expressionP) + expressionS *expressionP; +{ +#if DEBUG + printf (" md_operand(input_line_pointer = %s)\n", input_line_pointer); +#endif + + if (input_line_pointer[0] == REGISTER_PREFIX && input_line_pointer[1] == 'r') + { + /* We have a numeric register expression. No biggy. */ + input_line_pointer += 2; /* Skip %r */ + (void) expression (expressionP); + + if (expressionP->X_op != O_constant + || expressionP->X_add_number > 255) + as_bad (_("Invalid expression after %%%%\n")); + expressionP->X_op = O_register; + } + else if (input_line_pointer[0] == '&') + { + /* We are taking the 'address' of a register...this one is not + in the manual, but it *is* in traps/fpsymbol.h! What they + seem to want is the register number, as an absolute number. */ + input_line_pointer++; /* Skip & */ + (void) expression (expressionP); + + if (expressionP->X_op != O_register) + as_bad (_("invalid register in & expression")); + else + expressionP->X_op = O_constant; + } + else if (input_line_pointer[0] == '$' + && ISDIGIT ((unsigned char) input_line_pointer[1])) + { + long lab; + char *name; + symbolS *sym; + + /* This is a local label. */ + ++input_line_pointer; + lab = (long) get_absolute_expression (); + + if (dollar_label_defined (lab)) + { + name = dollar_label_name (lab, 0); + sym = symbol_find (name); + } + else + { + name = dollar_label_name (lab, 1); + sym = symbol_find_or_make (name); + } + + expressionP->X_op = O_symbol; + expressionP->X_add_symbol = sym; + expressionP->X_add_number = 0; + } + else if (input_line_pointer[0] == '$') + { + char *s; + char type; + int fieldnum, fieldlimit; + LITTLENUM_TYPE floatbuf[8]; + + /* $float(), $doubleN(), or $extendN() convert floating values + to integers. */ + s = input_line_pointer; + + ++s; + + fieldnum = 0; + if (strncmp (s, "double", sizeof "double" - 1) == 0) + { + s += sizeof "double" - 1; + type = 'd'; + fieldlimit = 2; + } + else if (strncmp (s, "float", sizeof "float" - 1) == 0) + { + s += sizeof "float" - 1; + type = 'f'; + fieldlimit = 1; + } + else if (strncmp (s, "extend", sizeof "extend" - 1) == 0) + { + s += sizeof "extend" - 1; + type = 'x'; + fieldlimit = 4; + } + else + return; + + if (ISDIGIT (*s)) + { + fieldnum = *s - '0'; + ++s; + } + if (fieldnum >= fieldlimit) + return; + + SKIP_WHITESPACE (); + if (*s != '(') + return; + ++s; + SKIP_WHITESPACE (); + + s = atof_ieee (s, type, floatbuf); + if (s == NULL) + return; + s = s; + + SKIP_WHITESPACE (); + if (*s != ')') + return; + ++s; + SKIP_WHITESPACE (); + + input_line_pointer = s; + expressionP->X_op = O_constant; + expressionP->X_unsigned = 1; + expressionP->X_add_number = ((floatbuf[fieldnum * 2] + << LITTLENUM_NUMBER_OF_BITS) + + floatbuf[fieldnum * 2 + 1]); + } +} + +/* Round up a section size to the appropriate boundary. */ + +valueT +md_section_align (segment, size) + segT segment ATTRIBUTE_UNUSED; + valueT size ATTRIBUTE_UNUSED; +{ + return size; /* Byte alignment is fine. */ +} + +/* Exactly what point is a PC-relative offset relative TO? + On the 29000, they're relative to the address of the instruction, + which we have set up as the address of the fixup too. */ + +long +md_pcrel_from (fixP) + fixS *fixP; +{ + return fixP->fx_where + fixP->fx_frag->fr_address; +} + +/* Generate a reloc for a fixup. */ + +#ifdef BFD_ASSEMBLER +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->address = fixp->fx_frag->fr_address + fixp->fx_where + fixp->fx_addnumber;*/ + 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; + } + + 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; +} +#endif + diff --git a/gas/config/tc-or32.h b/gas/config/tc-or32.h new file mode 100644 index 0000000..b78cf93 --- /dev/null +++ b/gas/config/tc-or32.h @@ -0,0 +1,63 @@ +/* tc-or32.h -- Assemble for the OpenRISC 1000. + Copyright (C) 2002 Free Software Foundation, Inc. + Contributed by Damjan Lampret <lampret@opencores.org>. + Based upon a29k port. + + 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_OR32 + +#define TARGET_BYTES_BIG_ENDIAN 1 + +#define LEX_DOLLAR 1 + +#ifdef OBJ_ELF +#define TARGET_FORMAT "elf32-or32" +#define TARGET_ARCH bfd_arch_or32 +#endif + +#ifdef OBJ_COFF +#define TARGET_FORMAT "coff-or32-big" +#define reloc_type int +#endif + +#define tc_unrecognized_line(c) or32_unrecognized_line (c) + +extern int or32_unrecognized_line PARAMS ((int)); + +#define tc_headers_hook(a) ; /* not used */ +#define tc_headers_hook(a) ; /* not used */ +#define tc_crawl_symbol_chain(a) ; /* not used */ +#define tc_coff_symbol_emit_hook(a) ; /* not used */ + +#define AOUT_MACHTYPE 80 +#define TC_COFF_FIX2RTYPE(fix_ptr) tc_coff_fix2rtype (fix_ptr) +#define BFD_ARCH bfd_arch_or32 +#define COFF_MAGIC SIPFBOMAGIC + +/* Should the reloc be output ? + on the 29k, this is true only if there is a symbol attatched. + on the h8, this is allways true, since no fixup is done. */ +#define TC_COUNT_RELOC(x) (x->fx_addsy) +#define TC_CONS_RELOC RELOC_32 + +#define COFF_FLAGS F_AR32W +#define NEED_FX_R_TYPE + +#define ZERO_BASED_SEGMENTS + |