📄 tc-v850.c
字号:
/* tc-v850.c -- Assembler code for the NEC V850 Copyright 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. GAS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GAS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GAS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include <stdio.h>#include <ctype.h>#include "as.h"#include "subsegs.h"#include "opcode/v850.h"#include "dwarf2dbg.h"#define AREA_ZDA 0#define AREA_SDA 1#define AREA_TDA 2/* Sign-extend a 16-bit number. */#define SEXT16(x) ((((x) & 0xffff) ^ (~0x7fff)) + 0x8000)/* Temporarily holds the reloc in a cons expression. */static bfd_reloc_code_real_type hold_cons_reloc = BFD_RELOC_UNUSED;/* Set to TRUE if we want to be pedantic about signed overflows. */static boolean warn_signed_overflows = FALSE;static boolean warn_unsigned_overflows = FALSE;/* Indicates the target BFD machine number. */static int machine = -1;/* Indicates the target processor(s) for the assemble. */static int processor_mask = -1;/* Structure to hold information about predefined registers. */struct reg_name { const char *name; int value;};/* Generic assembler global variables which must be defined by all targets. *//* Characters which always start a comment. */const char comment_chars[] = "#";/* Characters which start a comment at the beginning of a line. */const char line_comment_chars[] = ";#";/* Characters which may be used to separate multiple commands on a single line. */const char line_separator_chars[] = ";";/* Characters which are used to indicate an exponent in a floating point number. */const char EXP_CHARS[] = "eE";/* Characters which mean that a number is a floating point constant, as in 0d1.0. */const char FLT_CHARS[] = "dD";const relax_typeS md_relax_table[] = { /* Conditional branches. */ {0xff, -0x100, 2, 1}, {0x1fffff, -0x200000, 6, 0}, /* Unconditional branches. */ {0xff, -0x100, 2, 3}, {0x1fffff, -0x200000, 4, 0},};static segT sdata_section = NULL;static segT tdata_section = NULL;static segT zdata_section = NULL;static segT sbss_section = NULL;static segT tbss_section = NULL;static segT zbss_section = NULL;static segT rosdata_section = NULL;static segT rozdata_section = NULL;static segT scommon_section = NULL;static segT tcommon_section = NULL;static segT zcommon_section = NULL;static segT call_table_data_section = NULL;static segT call_table_text_section = NULL;/* Fixups. */#define MAX_INSN_FIXUPS (5)struct v850_fixup { expressionS exp; int opindex; bfd_reloc_code_real_type reloc;};struct v850_fixup fixups[MAX_INSN_FIXUPS];static int fc;voidv850_sdata (int ignore ATTRIBUTE_UNUSED){ obj_elf_section_change_hook (); subseg_set (sdata_section, (subsegT) get_absolute_expression ()); demand_empty_rest_of_line ();}voidv850_tdata (int ignore ATTRIBUTE_UNUSED){ obj_elf_section_change_hook (); subseg_set (tdata_section, (subsegT) get_absolute_expression ()); demand_empty_rest_of_line ();}voidv850_zdata (int ignore ATTRIBUTE_UNUSED){ obj_elf_section_change_hook (); subseg_set (zdata_section, (subsegT) get_absolute_expression ()); demand_empty_rest_of_line ();}voidv850_sbss (int ignore ATTRIBUTE_UNUSED){ obj_elf_section_change_hook (); subseg_set (sbss_section, (subsegT) get_absolute_expression ()); demand_empty_rest_of_line ();}voidv850_tbss (int ignore ATTRIBUTE_UNUSED){ obj_elf_section_change_hook (); subseg_set (tbss_section, (subsegT) get_absolute_expression ()); demand_empty_rest_of_line ();}voidv850_zbss (int ignore ATTRIBUTE_UNUSED){ obj_elf_section_change_hook (); subseg_set (zbss_section, (subsegT) get_absolute_expression ()); demand_empty_rest_of_line ();}voidv850_rosdata (int ignore ATTRIBUTE_UNUSED){ obj_elf_section_change_hook (); subseg_set (rosdata_section, (subsegT) get_absolute_expression ()); demand_empty_rest_of_line ();}voidv850_rozdata (int ignore ATTRIBUTE_UNUSED){ obj_elf_section_change_hook (); subseg_set (rozdata_section, (subsegT) get_absolute_expression ()); demand_empty_rest_of_line ();}voidv850_call_table_data (int ignore ATTRIBUTE_UNUSED){ obj_elf_section_change_hook (); subseg_set (call_table_data_section, (subsegT) get_absolute_expression ()); demand_empty_rest_of_line ();}voidv850_call_table_text (int ignore ATTRIBUTE_UNUSED){ obj_elf_section_change_hook (); subseg_set (call_table_text_section, (subsegT) get_absolute_expression ()); demand_empty_rest_of_line ();}voidv850_bss (int ignore ATTRIBUTE_UNUSED){ register int temp = get_absolute_expression (); obj_elf_section_change_hook (); subseg_set (bss_section, (subsegT) temp); demand_empty_rest_of_line ();}voidv850_offset (int ignore ATTRIBUTE_UNUSED){ int temp = get_absolute_expression (); temp -= frag_now_fix (); if (temp > 0) (void) frag_more (temp); demand_empty_rest_of_line ();}/* Copied from obj_elf_common() in gas/config/obj-elf.c. */static voidv850_comm (area) int area;{ char *name; char c; char *p; int temp; unsigned int size; symbolS *symbolP; int have_align; name = input_line_pointer; c = get_symbol_end (); /* Just after name is now '\0'. */ p = input_line_pointer; *p = c; SKIP_WHITESPACE (); if (*input_line_pointer != ',') { as_bad (_("Expected comma after symbol-name")); ignore_rest_of_line (); return; } /* Skip ','. */ input_line_pointer++; if ((temp = get_absolute_expression ()) < 0) { /* xgettext:c-format */ as_bad (_(".COMMon length (%d.) < 0! Ignored."), temp); ignore_rest_of_line (); return; } size = temp; *p = 0; symbolP = symbol_find_or_make (name); *p = c; if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP)) { as_bad (_("Ignoring attempt to re-define symbol")); ignore_rest_of_line (); return; } if (S_GET_VALUE (symbolP) != 0) { if (S_GET_VALUE (symbolP) != size) { /* xgettext:c-format */ as_warn (_("Length of .comm \"%s\" is already %ld. Not changed to %d."), S_GET_NAME (symbolP), (long) S_GET_VALUE (symbolP), size); } } know (symbol_get_frag (symbolP) == &zero_address_frag); if (*input_line_pointer != ',') have_align = 0; else { have_align = 1; input_line_pointer++; SKIP_WHITESPACE (); } if (! have_align || *input_line_pointer != '"') { if (! have_align) temp = 0; else { temp = get_absolute_expression (); if (temp < 0) { temp = 0; as_warn (_("Common alignment negative; 0 assumed")); } } if (symbol_get_obj (symbolP)->local) { segT old_sec; int old_subsec; char *pfrag; int align; flagword applicable; old_sec = now_seg; old_subsec = now_subseg; applicable = bfd_applicable_section_flags (stdoutput); applicable &= SEC_ALLOC; switch (area) { case AREA_SDA: if (sbss_section == NULL) { sbss_section = subseg_new (".sbss", 0); bfd_set_section_flags (stdoutput, sbss_section, applicable); seg_info (sbss_section)->bss = 1; } break; case AREA_ZDA: if (zbss_section == NULL) { zbss_section = subseg_new (".zbss", 0); bfd_set_section_flags (stdoutput, sbss_section, applicable); seg_info (zbss_section)->bss = 1; } break; case AREA_TDA: if (tbss_section == NULL) { tbss_section = subseg_new (".tbss", 0); bfd_set_section_flags (stdoutput, tbss_section, applicable); seg_info (tbss_section)->bss = 1; } break; } if (temp) { /* Convert to a power of 2 alignment. */ for (align = 0; (temp & 1) == 0; temp >>= 1, ++align) ; if (temp != 1) { as_bad (_("Common alignment not a power of 2")); ignore_rest_of_line (); return; } } else align = 0; switch (area) { case AREA_SDA: record_alignment (sbss_section, align); obj_elf_section_change_hook (); subseg_set (sbss_section, 0); break; case AREA_ZDA: record_alignment (zbss_section, align); obj_elf_section_change_hook (); subseg_set (zbss_section, 0); break; case AREA_TDA: record_alignment (tbss_section, align); obj_elf_section_change_hook (); subseg_set (tbss_section, 0); break; default: abort (); } if (align) frag_align (align, 0, 0); switch (area) { case AREA_SDA: if (S_GET_SEGMENT (symbolP) == sbss_section) symbol_get_frag (symbolP)->fr_symbol = 0; break; case AREA_ZDA: if (S_GET_SEGMENT (symbolP) == zbss_section) symbol_get_frag (symbolP)->fr_symbol = 0; break; case AREA_TDA: if (S_GET_SEGMENT (symbolP) == tbss_section) symbol_get_frag (symbolP)->fr_symbol = 0; break; default: abort (); } symbol_set_frag (symbolP, frag_now); pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP, (offsetT) size, (char *) 0); *pfrag = 0; S_SET_SIZE (symbolP, size); switch (area) { case AREA_SDA: S_SET_SEGMENT (symbolP, sbss_section); break; case AREA_ZDA: S_SET_SEGMENT (symbolP, zbss_section); break; case AREA_TDA: S_SET_SEGMENT (symbolP, tbss_section); break; default: abort (); } S_CLEAR_EXTERNAL (symbolP); obj_elf_section_change_hook (); subseg_set (old_sec, old_subsec); } else { allocate_common: S_SET_VALUE (symbolP, (valueT) size); S_SET_ALIGN (symbolP, temp); S_SET_EXTERNAL (symbolP); switch (area) { case AREA_SDA: if (scommon_section == NULL) { flagword applicable = bfd_applicable_section_flags (stdoutput); scommon_section = subseg_new (".scommon", 0); bfd_set_section_flags (stdoutput, scommon_section, (applicable & (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA | SEC_HAS_CONTENTS)) | SEC_IS_COMMON); } S_SET_SEGMENT (symbolP, scommon_section); break; case AREA_ZDA: if (zcommon_section == NULL) { flagword applicable = bfd_applicable_section_flags (stdoutput); zcommon_section = subseg_new (".zcommon", 0); bfd_set_section_flags (stdoutput, zcommon_section, (applicable & (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA | SEC_HAS_CONTENTS)) | SEC_IS_COMMON); } S_SET_SEGMENT (symbolP, zcommon_section); break; case AREA_TDA: if (tcommon_section == NULL) { flagword applicable = bfd_applicable_section_flags (stdoutput); tcommon_section = subseg_new (".tcommon", 0); bfd_set_section_flags (stdoutput, tcommon_section, ((applicable & (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA | SEC_HAS_CONTENTS)) | SEC_IS_COMMON)); } S_SET_SEGMENT (symbolP, tcommon_section); break; default: abort (); } } } else { input_line_pointer++; /* @@ Some use the dot, some don't. Can we get some consistency?? */ if (*input_line_pointer == '.') input_line_pointer++; /* @@ Some say data, some say bss. */ if (strncmp (input_line_pointer, "bss\"", 4) && strncmp (input_line_pointer, "data\"", 5)) { while (*--input_line_pointer != '"') ; input_line_pointer--; goto bad_common_segment; } while (*input_line_pointer++ != '"') ; goto allocate_common; } symbol_get_bfdsym (symbolP)->flags |= BSF_OBJECT; demand_empty_rest_of_line (); return; { bad_common_segment: p = input_line_pointer; while (*p && *p != '\n') p++; c = *p; *p = '\0'; as_bad (_("bad .common segment %s"), input_line_pointer + 1); *p = c; input_line_pointer = p; ignore_rest_of_line (); return; }}voidset_machine (int number){ machine = number; bfd_set_arch_mach (stdoutput, TARGET_ARCH, machine); switch (machine) { case 0: processor_mask = PROCESSOR_V850; break; case bfd_mach_v850e: processor_mask = PROCESSOR_V850E; break; case bfd_mach_v850ea: processor_mask = PROCESSOR_V850EA; break; }}/* The target specific pseudo-ops which we support. */const pseudo_typeS md_pseudo_table[] = { {"sdata", v850_sdata, 0}, {"tdata", v850_tdata, 0}, {"zdata", v850_zdata, 0}, {"sbss", v850_sbss, 0}, {"tbss", v850_tbss, 0}, {"zbss", v850_zbss, 0}, {"rosdata", v850_rosdata, 0}, {"rozdata", v850_rozdata, 0}, {"bss", v850_bss, 0}, {"offset", v850_offset, 0}, {"word", cons, 4}, {"zcomm", v850_comm, AREA_ZDA}, {"scomm", v850_comm, AREA_SDA}, {"tcomm", v850_comm, AREA_TDA}, {"v850", set_machine, 0}, {"call_table_data", v850_call_table_data, 0}, {"call_table_text", v850_call_table_text, 0}, {"v850e", set_machine, bfd_mach_v850e}, {"v850ea", set_machine, bfd_mach_v850ea}, {"file", dwarf2_directive_file, 0}, {"loc", dwarf2_directive_loc, 0}, { NULL, NULL, 0}};/* Opcode hash table. */static struct hash_control *v850_hash;/* This table is sorted. Suitable for searching by a binary search. */static const struct reg_name pre_defined_registers[] = { { "ep", 30 }, /* ep - element ptr */ { "gp", 4 }, /* gp - global ptr */ { "hp", 2 }, /* hp - handler stack ptr */ { "lp", 31 }, /* lp - link ptr */ { "r0", 0 }, { "r1", 1 }, { "r10", 10 }, { "r11", 11 }, { "r12", 12 }, { "r13", 13 }, { "r14", 14 }, { "r15", 15 }, { "r16", 16 }, { "r17", 17 }, { "r18", 18 },
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -