diff options
author | David Edelsohn <dje.gcc@gmail.com> | 1997-09-18 21:12:06 +0000 |
---|---|---|
committer | David Edelsohn <dje.gcc@gmail.com> | 1997-09-18 21:12:06 +0000 |
commit | af6f39b4c4eee27579833f65d2658342f8c439d8 (patch) | |
tree | 6b867b555b28b7b6ea4ccba5901557798d5a9c9e | |
parent | 920b87c43724f613f00c167a34515078346af717 (diff) | |
download | gdb-af6f39b4c4eee27579833f65d2658342f8c439d8.zip gdb-af6f39b4c4eee27579833f65d2658342f8c439d8.tar.gz gdb-af6f39b4c4eee27579833f65d2658342f8c439d8.tar.bz2 |
* config/tc-sparc.c: Reorganize file.
(SPECIAL_CASE_NONE): New macro.
(md_assemble): Use it.
-rw-r--r-- | gas/ChangeLog | 5 | ||||
-rw-r--r-- | gas/config/tc-sparc.c | 1658 |
2 files changed, 809 insertions, 854 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog index 8e68fd8..e86c6e7 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -5,7 +5,10 @@ Thu Sep 18 14:11:56 1997 Nick Clifton <nickc@cygnus.com> Thu Sep 18 11:24:01 1997 Doug Evans <dje@canuck.cygnus.com> - * config/tc-sparc.c (parse_keyword_arg): Allow numbers in reg names. + * config/tc-sparc.c: Reorganize file. + (parse_keyword_arg): Allow numbers in reg names. + (SPECIAL_CASE_NONE): New macro. + (md_assemble): Use it. Wed Sep 17 16:54:20 1997 Nick Clifton <nickc@cygnus.com> diff --git a/gas/config/tc-sparc.c b/gas/config/tc-sparc.c index 8a9f849..c58b2e5 100644 --- a/gas/config/tc-sparc.c +++ b/gas/config/tc-sparc.c @@ -35,6 +35,7 @@ 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)); /* Current architecture. We don't bump up unless necessary. */ static enum sparc_opcode_arch_val current_architecture = SPARC_OPCODE_ARCH_V6; @@ -162,540 +163,222 @@ struct sparc_it the_insn, set_insn; static void output_insn PARAMS ((const struct sparc_opcode *, struct sparc_it *)); - -/* 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 (); - if (val > max) - return 0; - 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; -} - -#if 0 -static void print_insn PARAMS ((struct sparc_it *insn)); -#endif -static int getExpression PARAMS ((char *str)); - -static char *expr_end; -static int special_case; - -/* - * Instructions that require wierd handling because they're longer than - * 4 bytes. - */ -#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 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; - + /* - * sort of like s_lcomm + * 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 a 64 bit world. + * -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. If 32 bit + * environments, v9 is not bumped up to, the user must pass -Av9. + * + * -xarch=v8plus{,a} is for compatibility with the Sun assembler. * + * 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 + * -Av9 does not automatically create a v9 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 v9 object files unless v9 insns + * are seen. + * + * Note: + * Bumping between incompatible architectures is always an + * error. For example, from sparclite to v9. */ -#ifndef OBJ_ELF -static int max_alignment = 15; + +#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 SPARC_BIENDIAN +#define OPTION_LITTLE_ENDIAN (OPTION_MD_BASE + 3) + {"EL", no_argument, NULL, OPTION_LITTLE_ENDIAN}, +#define OPTION_BIG_ENDIAN (OPTION_MD_BASE + 4) + {"EB", no_argument, NULL, OPTION_BIG_ENDIAN}, #endif +#define OPTION_ENFORCE_ALIGNED_DATA (OPTION_MD_BASE + 5) + {"enforce-aligned-data", no_argument, NULL, OPTION_ENFORCE_ALIGNED_DATA}, + {NULL, no_argument, NULL, 0} +}; +size_t md_longopts_size = sizeof(md_longopts); -static void -s_reserve (ignore) - int ignore; +int +md_parse_option (c, arg) + int c; + char *arg; { - 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 != ',') + switch (c) { - as_bad ("Expected comma after name"); - ignore_rest_of_line (); - return; - } + case OPTION_BUMP: + warn_on_bump = 1; + warn_after_architecture = SPARC_OPCODE_ARCH_V6; + break; - ++input_line_pointer; + case OPTION_XARCH: + /* This is for compatibility with Sun's assembler. + We could add v8plus and v8plusa to sparc_opcode_archs, + but that table is used to describe architectures whereas here we + want the argument to describe *both* the architecture and the file + format. */ + if (strcmp (arg, "v8plus") == 0) + arg = "v9"; + else if (strcmp (arg, "v8plusa") == 0) + arg = "v9a"; + else + { + as_bad ("invalid architecture -xarch=%s", arg); + return 0; + } - if ((size = get_absolute_expression ()) < 0) - { - as_bad ("BSS length (%d.) <0! Ignored.", size); - ignore_rest_of_line (); - return; - } /* bad length */ + /* fall through */ - *p = 0; - symbolP = symbol_find_or_make (name); - *p = c; + case 'A': + { + enum sparc_opcode_arch_val new_arch = sparc_opcode_lookup_arch (arg); - 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 (new_arch == SPARC_OPCODE_ARCH_BAD) + { + as_bad ("invalid architecture -A%s", arg); + return 0; + } - if (input_line_pointer[2] == '.') - input_line_pointer += 7; - else - input_line_pointer += 6; - SKIP_WHITESPACE (); + max_architecture = new_arch; + architecture_requested = 1; + } + break; - if (*input_line_pointer == ',') - { - ++input_line_pointer; + case OPTION_SPARC: + /* Ignore -sparc, used by SunOS make default .s.o rule. */ + break; - SKIP_WHITESPACE (); - if (*input_line_pointer == '\n') - { - as_bad ("Missing alignment"); - return; - } + case OPTION_ENFORCE_ALIGNED_DATA: + enforce_aligned_data = 1; + break; - align = get_absolute_expression (); -#ifndef OBJ_ELF - if (align > max_alignment) - { - align = max_alignment; - as_warn ("Alignment too large: %d. assumed.", align); - } +#ifdef SPARC_BIENDIAN + case OPTION_LITTLE_ENDIAN: + target_big_endian = 0; + break; + case OPTION_BIG_ENDIAN: + target_big_endian = 1; + break; #endif - if (align < 0) - { - align = 0; - as_warn ("Alignment negative. 0 assumed."); - } - - record_alignment (bss_section, align); - - /* convert to a power of 2 alignment */ - for (temp = 0; (align & 1) == 0; align >>= 1, ++temp);; - - if (align != 1) - { - as_bad ("Alignment not a power of 2"); - ignore_rest_of_line (); - return; - } /* not a power of two */ - align = temp; - } /* if has optional alignment */ - else - align = 0; - - if (!S_IS_DEFINED (symbolP) #ifdef OBJ_AOUT - && S_GET_OTHER (symbolP) == 0 - && S_GET_DESC (symbolP) == 0 + case 'k': + sparc_pic_code = 1; + break; #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 */ +#ifdef OBJ_ELF + case 'V': + print_version_id (); + break; - if (align) - frag_align (align, 0, 0); /* do alignment */ + case 'Q': + /* Qy - do emit .comment + Qn - do not emit .comment */ + break; - /* detach from old frag */ - if (S_GET_SEGMENT(symbolP) == bss_section) - symbolP->sy_frag->fr_symbol = NULL; + case 's': + /* use .stab instead of .stab.excl */ + break; - symbolP->sy_frag = frag_now; - pfrag = frag_var (rs_org, 1, 1, (relax_substateT)0, symbolP, - (offsetT) size, (char *)0); - *pfrag = 0; + case 'q': + /* quick -- native assembler does fewer checks */ + break; - S_SET_SEGMENT (symbolP, bss_section); + case 'K': + if (strcmp (arg, "PIC") != 0) + as_warn ("Unrecognized option following -K"); + else + sparc_pic_code = 1; + break; +#endif - subseg_set (current_seg, current_subseg); - } + default: + return 0; } - else - { - as_warn("Ignoring attempt to re-define symbol %s", - S_GET_NAME (symbolP)); - } /* if not redefining */ - demand_empty_rest_of_line (); + return 1; } -static void -s_common (ignore) - int ignore; +void +md_show_usage (stream) + FILE *stream; { - char *name; - char c; - char *p; - int temp, size; - symbolS *symbolP; + const struct sparc_opcode_arch *arch; - 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); - } - } - else - { -#ifndef OBJ_ELF - S_SET_VALUE (symbolP, (valueT) size); - S_SET_EXTERNAL (symbolP); -#endif - } - know (symbolP->sy_frag == &zero_address_frag); - if (*input_line_pointer != ',') + fprintf(stream, "SPARC options:\n"); + for (arch = &sparc_opcode_archs[0]; arch->name; arch++) { - as_bad ("Expected comma after common length"); - ignore_rest_of_line (); - return; + if (arch != &sparc_opcode_archs[0]) + fprintf (stream, " | "); + fprintf (stream, "-A%s", arch->name); } - 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 ("Common alignment too large: %d. assumed", temp); - } -#endif - if (temp < 0) - { - temp = 0; - as_warn ("Common alignment negative; 0 assumed"); - } -#ifdef OBJ_ELF - if (symbolP->local) - { - segT old_sec; - int old_subsec; - char *p; - int align; - - 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) - symbolP->sy_frag->fr_symbol = 0; - symbolP->sy_frag = 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 + 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 - { - allocate_common: - S_SET_VALUE (symbolP, (valueT) size); #ifdef OBJ_ELF - S_SET_ALIGN (symbolP, temp); + fprintf (stream, "\ +-KPIC generate PIC\n\ +-V print assembler version number\n\ +-q ignored\n\ +-Qy, -Qn ignored\n\ +-s ignored\n"); #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 - symbolP->bsym->flags |= BSF_OBJECT; +#ifdef SPARC_BIENDIAN + fprintf (stream, "\ +-EL generate code for a little endian machine\n\ +-EB generate code for a big endian machine\n"); #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); } - -/* 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 = 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_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. */ - -void -sparc_handle_align (fragp) - fragS *fragp; -{ - if (fragp->fr_type == rs_align_code - && fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix != 0) - as_bad_where (fragp->fr_file, fragp->fr_line, "misaligned data"); -} - + /* sparc64 priviledged registers */ struct priv_reg_entry @@ -736,7 +419,7 @@ cmp_reg_entry (parg, 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. */ @@ -839,37 +522,94 @@ sparc_md_end () } #endif } + +/* 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 (); + if (val > max) + return 0; + if (val < ~max) + return 0; + return 1; +} -/* Utility to output one insn. */ +/* Return non-zero if VAL is in the range -(MAX/2+1) to MAX. + (e.g. -15 to +31). */ -static void -output_insn (insn, the_insn) - const struct sparc_opcode *insn; - struct sparc_it *the_insn; +static INLINE int +in_bitfield_range (val, max) + bfd_signed_vma val, max; { - char *toP = frag_more (4); + if (max <= 0) + abort (); + if (val > max) + return 0; + if (val < ~(max >> 1)) + return 0; + return 1; +} - /* 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); +static int +sparc_ffs (mask) + unsigned int mask; +{ + int i; - /* put out the symbol-dependent stuff */ - if (the_insn->reloc != BFD_RELOC_NONE) - { - fix_new_exp (frag_now, /* which frag */ - (toP - frag_now->fr_literal), /* where */ - 4, /* size */ - &the_insn->exp, - the_insn->pcrel, - the_insn->reloc); - } + if (mask == 0) + return -1; - last_insn = insn; - last_opcode = the_insn->opcode; + 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; + +/* For communication between md_assemble and sparc_ip. */ +static int special_case; + +/* 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 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; + +/* Main entry point to assemble one instruction. */ + void md_assemble (str) char *str; @@ -877,7 +617,7 @@ md_assemble (str) const struct sparc_opcode *insn; know (str); - special_case = 0; + special_case = SPECIAL_CASE_NONE; sparc_ip (str, &insn); /* We warn about attempts to put a floating point branch in a delay slot, @@ -911,7 +651,7 @@ md_assemble (str) switch (special_case) { - case 0: + case SPECIAL_CASE_NONE: /* normal insn */ output_insn (insn, &the_insn); break; @@ -1128,66 +868,7 @@ md_assemble (str) } } -/* 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 (*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 md_assemble to do the actual parsing. */ static void sparc_ip (str, pinsn) @@ -1916,7 +1597,7 @@ sparc_ip (str, pinsn) else break; } - /* Note that if the getExpression() fails, we will still + /* 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. */ @@ -1936,7 +1617,7 @@ sparc_ip (str, pinsn) { s1 -= 3; *s1 = '\0'; - (void) getExpression (s); + (void) get_expression (s); *s1 = '+'; s = s1; continue; @@ -1945,14 +1626,14 @@ sparc_ip (str, pinsn) { s1 -= 4; *s1 = '\0'; - (void) getExpression (s); + (void) get_expression (s); *s1 = '+'; s = s1; continue; } } } - (void) getExpression (s); + (void) get_expression (s); s = expr_end; if (the_insn.exp.X_op == O_constant @@ -2281,8 +1962,71 @@ sparc_ip (str, pinsn) the_insn.opcode = opcode; } +/* 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 (*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 -getExpression (str) +get_expression (str) char *str; { char *save_in; @@ -2305,9 +2049,38 @@ getExpression (str) expr_end = input_line_pointer; input_line_pointer = save_in; return 0; -} /* getExpression() */ +} + +/* 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) + { + fix_new_exp (frag_now, /* which frag */ + (toP - frag_now->fr_literal), /* where */ + 4, /* size */ + &the_insn->exp, + the_insn->pcrel, + the_insn->reloc); + } + 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. @@ -2400,7 +2173,7 @@ md_number_to_chars (buf, val, n) else number_to_chars_littleendian (buf, val, n); } - + /* Apply a fixS to the frags, now that we know the value it ought to hold. */ @@ -2751,320 +2524,499 @@ tc_gen_reloc (section, fixp) return reloc; } + +/* We have no need to default values of symbols. */ +/* ARGSUSED */ +symbolS * +md_undefined_symbol (name) + char *name; +{ + return 0; +} /* md_undefined_symbol() */ -#if 0 -/* for debugging only */ -static void -print_insn (insn) - struct sparc_it *insn; +/* Round up a section size to the appropriate boundary. */ +valueT +md_section_align (segment, size) + segT segment; + valueT size; { - const char *const Reloc[] = { - "RELOC_8", - "RELOC_16", - "RELOC_32", - "RELOC_DISP8", - "RELOC_DISP16", - "RELOC_DISP32", - "RELOC_WDISP30", - "RELOC_WDISP22", - "RELOC_HI22", - "RELOC_22", - "RELOC_13", - "RELOC_LO10", - "RELOC_SFA_BASE", - "RELOC_SFA_OFF13", - "RELOC_BASE10", - "RELOC_BASE13", - "RELOC_BASE22", - "RELOC_PC10", - "RELOC_PC22", - "RELOC_JMP_TBL", - "RELOC_SEGOFF16", - "RELOC_GLOB_DAT", - "RELOC_JMP_SLOT", - "RELOC_RELATIVE", - "NO_RELOC" - }; +#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 +} - if (insn->error) - fprintf (stderr, "ERROR: %s\n"); - fprintf (stderr, "opcode=0x%08x\n", insn->opcode); - fprintf (stderr, "reloc = %s\n", Reloc[insn->reloc]); - fprintf (stderr, "exp = {\n"); - fprintf (stderr, "\t\tX_add_symbol = %s\n", - ((insn->exp.X_add_symbol != NULL) - ? ((S_GET_NAME (insn->exp.X_add_symbol) != NULL) - ? S_GET_NAME (insn->exp.X_add_symbol) - : "???") - : "0")); - fprintf (stderr, "\t\tX_sub_symbol = %s\n", - ((insn->exp.X_op_symbol != NULL) - ? (S_GET_NAME (insn->exp.X_op_symbol) - ? S_GET_NAME (insn->exp.X_op_symbol) - : "???") - : "0")); - fprintf (stderr, "\t\tX_add_number = %d\n", - insn->exp.X_add_number); - fprintf (stderr, "}\n"); +/* 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 + || (fixP->fx_addsy->bsym->flags & BSF_SECTION_SYM) != 0) + ret += fixP->fx_size; + return ret; } -#endif /* - * 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, -Av9, -Av9a, -Asparclite - * -xarch=v8plus, -xarch=v8plusa - * Select the architecture. 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. If 32 bit - * environments, v9 is not bumped up to, the user must pass -Av9. - * - * -xarch=v8plus{,a} is for compatibility with the Sun assembler. - * - * 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 - * -Av9 does not automatically create a v9 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 v9 object files unless v9 insns - * are seen. - * - * Note: - * Bumping between incompatible architectures is always an - * error. For example, from sparclite to v9. + * sort of like s_lcomm */ -#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 SPARC_BIENDIAN -#define OPTION_LITTLE_ENDIAN (OPTION_MD_BASE + 3) - {"EL", no_argument, NULL, OPTION_LITTLE_ENDIAN}, -#define OPTION_BIG_ENDIAN (OPTION_MD_BASE + 4) - {"EB", no_argument, NULL, OPTION_BIG_ENDIAN}, +#ifndef OBJ_ELF +static int max_alignment = 15; #endif -#define OPTION_ENFORCE_ALIGNED_DATA (OPTION_MD_BASE + 5) - {"enforce-aligned-data", no_argument, NULL, OPTION_ENFORCE_ALIGNED_DATA}, - {NULL, no_argument, NULL, 0} -}; -size_t md_longopts_size = sizeof(md_longopts); -int -md_parse_option (c, arg) - int c; - char *arg; +static void +s_reserve (ignore) + int ignore; { - switch (c) + 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 != ',') { - case OPTION_BUMP: - warn_on_bump = 1; - warn_after_architecture = SPARC_OPCODE_ARCH_V6; - break; + as_bad ("Expected comma after name"); + ignore_rest_of_line (); + return; + } - case OPTION_XARCH: - /* ??? We could add v8plus and v8plusa to sparc_opcode_archs. - But we might want v8plus to mean something different than v9 - someday, and we'd recognize more -xarch options than Sun's - assembler does (which may lead to a conflict someday). */ - if (strcmp (arg, "v8plus") == 0) - arg = "v9"; - else if (strcmp (arg, "v8plusa") == 0) - arg = "v9a"; - else - { - as_bad ("invalid architecture -xarch=%s", arg); - return 0; - } + ++input_line_pointer; - /* fall through */ + if ((size = get_absolute_expression ()) < 0) + { + as_bad ("BSS length (%d.) <0! Ignored.", size); + ignore_rest_of_line (); + return; + } /* bad length */ - case 'A': - { - enum sparc_opcode_arch_val new_arch = sparc_opcode_lookup_arch (arg); + *p = 0; + symbolP = symbol_find_or_make (name); + *p = c; - if (new_arch == SPARC_OPCODE_ARCH_BAD) - { - as_bad ("invalid architecture -A%s", arg); - return 0; - } - else - { - max_architecture = new_arch; - architecture_requested = 1; - } - } - break; + if (strncmp (input_line_pointer, ",\"bss\"", 6) != 0 + && strncmp (input_line_pointer, ",\".bss\"", 7) != 0) + { + as_bad ("bad .reserve segment -- expected BSS segment"); + return; + } - case OPTION_SPARC: - /* Ignore -sparc, used by SunOS make default .s.o rule. */ - break; + if (input_line_pointer[2] == '.') + input_line_pointer += 7; + else + input_line_pointer += 6; + SKIP_WHITESPACE (); - case OPTION_ENFORCE_ALIGNED_DATA: - enforce_aligned_data = 1; - break; + if (*input_line_pointer == ',') + { + ++input_line_pointer; -#ifdef SPARC_BIENDIAN - case OPTION_LITTLE_ENDIAN: - target_big_endian = 0; - break; - case OPTION_BIG_ENDIAN: - target_big_endian = 1; - break; + SKIP_WHITESPACE (); + if (*input_line_pointer == '\n') + { + as_bad ("Missing alignment"); + return; + } + + align = get_absolute_expression (); +#ifndef OBJ_ELF + if (align > max_alignment) + { + align = max_alignment; + as_warn ("Alignment too large: %d. assumed.", align); + } #endif + if (align < 0) + { + align = 0; + as_warn ("Alignment negative. 0 assumed."); + } + + record_alignment (bss_section, align); + + /* convert to a power of 2 alignment */ + for (temp = 0; (align & 1) == 0; align >>= 1, ++temp);; + + if (align != 1) + { + as_bad ("Alignment not a power of 2"); + ignore_rest_of_line (); + return; + } /* not a power of two */ + + align = temp; + } /* if has optional alignment */ + else + align = 0; + if (!S_IS_DEFINED (symbolP) #ifdef OBJ_AOUT - case 'k': - sparc_pic_code = 1; - break; + && 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; -#ifdef OBJ_ELF - case 'V': - print_version_id (); - break; + subseg_set (bss_section, 1); /* switch to bss */ - case 'Q': - /* Qy - do emit .comment - Qn - do not emit .comment */ - break; + if (align) + frag_align (align, 0, 0); /* do alignment */ - case 's': - /* use .stab instead of .stab.excl */ - break; + /* detach from old frag */ + if (S_GET_SEGMENT(symbolP) == bss_section) + symbolP->sy_frag->fr_symbol = NULL; - case 'q': - /* quick -- native assembler does fewer checks */ - break; + symbolP->sy_frag = frag_now; + pfrag = frag_var (rs_org, 1, 1, (relax_substateT)0, symbolP, + (offsetT) size, (char *)0); + *pfrag = 0; - case 'K': - if (strcmp (arg, "PIC") != 0) - as_warn ("Unrecognized option following -K"); - else - sparc_pic_code = 1; - break; -#endif + S_SET_SEGMENT (symbolP, bss_section); - default: - return 0; + subseg_set (current_seg, current_subseg); + } } + else + { + as_warn("Ignoring attempt to re-define symbol %s", + S_GET_NAME (symbolP)); + } /* if not redefining */ - return 1; + demand_empty_rest_of_line (); } -void -md_show_usage (stream) - FILE *stream; +static void +s_common (ignore) + int ignore; { - const struct sparc_opcode_arch *arch; + char *name; + char c; + char *p; + int temp, size; + symbolS *symbolP; - fprintf(stream, "SPARC options:\n"); - for (arch = &sparc_opcode_archs[0]; arch->name; arch++) + 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 != ',') { - if (arch != &sparc_opcode_archs[0]) - fprintf (stream, " | "); - fprintf (stream, "-A%s", arch->name); + as_bad ("Expected comma after symbol-name"); + ignore_rest_of_line (); + return; } - 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"); + 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); + } + } + else + { +#ifndef OBJ_ELF + S_SET_VALUE (symbolP, (valueT) size); + S_SET_EXTERNAL (symbolP); +#endif + } + know (symbolP->sy_frag == &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 ("Common alignment too large: %d. assumed", temp); + } #endif + if (temp < 0) + { + temp = 0; + as_warn ("Common alignment negative; 0 assumed"); + } #ifdef OBJ_ELF - fprintf (stream, "\ --KPIC generate PIC\n\ --V print assembler version number\n\ --q ignored\n\ --Qy, -Qn ignored\n\ --s ignored\n"); + if (symbolP->local) + { + segT old_sec; + int old_subsec; + char *p; + int align; + + 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) + symbolP->sy_frag->fr_symbol = 0; + symbolP->sy_frag = 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 #endif -#ifdef SPARC_BIENDIAN - fprintf (stream, "\ --EL generate code for a little endian machine\n\ --EB generate code for a big endian machine\n"); + { + allocate_common: + S_SET_VALUE (symbolP, (valueT) size); +#ifdef OBJ_ELF + S_SET_ALIGN (symbolP, temp); +#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 + symbolP->bsym->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; + } } - -/* We have no need to default values of symbols. */ -/* ARGSUSED */ -symbolS * -md_undefined_symbol (name) - char *name; +/* Handle the .empty pseudo-op. This supresses the warnings about + invalid delay slot usage. */ + +static void +s_empty (ignore) + int ignore; { - return 0; -} /* md_undefined_symbol() */ + /* The easy way to implement is to just forget about the last + instruction. */ + last_insn = NULL; +} -/* Round up a section size to the appropriate boundary. */ -valueT -md_section_align (segment, size) - segT segment; - valueT size; +static void +s_seg (ignore) + int ignore; { -#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 + + 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 (); } -/* 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; +static void +s_data1 () { - long ret; + subseg_set (data_section, 1); + demand_empty_rest_of_line (); +} - ret = fixP->fx_where + fixP->fx_frag->fr_address; - if (! sparc_pic_code - || fixP->fx_addsy == NULL - || (fixP->fx_addsy->bsym->flags & BSF_SECTION_SYM) != 0) - ret += fixP->fx_size; - return ret; +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); +} + +/* 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 = 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_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); } -/* end of tc-sparc.c */ +/* 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_next->fr_address - fragp->fr_address - fragp->fr_fix != 0) + as_bad_where (fragp->fr_file, fragp->fr_line, "misaligned data"); +} |