📄 tc-arm.c
字号:
/* tc-arm.c -- Assemble for the ARM Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org) Modified by David Taylor (dtaylor@armltd.co.uk) This file is part of GAS, the GNU Assembler. GAS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GAS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GAS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include <ctype.h>#include <string.h>#define NO_RELOC 0#include "as.h"/* Need TARGET_CPU. */#include "config.h"#include "subsegs.h"#include "obstack.h"#include "symbols.h"#include "listing.h"#ifdef OBJ_ELF#include "elf/arm.h"#include "dwarf2dbg.h"#endif/* Types of processor to assemble for. */#define ARM_1 0x00000001#define ARM_2 0x00000002#define ARM_3 0x00000004#define ARM_250 ARM_3#define ARM_6 0x00000008#define ARM_7 ARM_6 /* Same core instruction set. */#define ARM_8 ARM_6 /* Same core instruction set. */#define ARM_9 ARM_6 /* Same core instruction set. */#define ARM_CPU_MASK 0x0000000f/* The following bitmasks control CPU extensions (ARM7 onwards): */#define ARM_EXT_LONGMUL 0x00000010 /* Allow long multiplies. */#define ARM_EXT_HALFWORD 0x00000020 /* Allow half word loads. */#define ARM_EXT_THUMB 0x00000040 /* Allow BX instruction. */#define ARM_EXT_V5 0x00000080 /* Allow CLZ, etc. */#define ARM_EXT_V5E 0x00000100 /* "El Segundo". */#define ARM_EXT_XSCALE 0x00000200 /* Allow MIA etc. *//* Architectures are the sum of the base and extensions. */#define ARM_ARCH_V3M ARM_EXT_LONGMUL#define ARM_ARCH_V4 (ARM_ARCH_V3M | ARM_EXT_HALFWORD)#define ARM_ARCH_V4T (ARM_ARCH_V4 | ARM_EXT_THUMB)#define ARM_ARCH_V5 (ARM_ARCH_V4 | ARM_EXT_V5)#define ARM_ARCH_V5T (ARM_ARCH_V5 | ARM_EXT_THUMB)#define ARM_ARCH_V5TE (ARM_ARCH_V5T | ARM_EXT_V5E)#define ARM_ARCH_XSCALE (ARM_ARCH_V5TE | ARM_EXT_XSCALE)/* Some useful combinations: */#define ARM_ANY 0x00ffffff#define ARM_2UP (ARM_ANY - ARM_1)#define ARM_ALL ARM_2UP /* Not arm1 only. */#define ARM_3UP 0x00fffffc#define ARM_6UP 0x00fffff8 /* Includes ARM7. */#define FPU_CORE 0x80000000#define FPU_FPA10 0x40000000#define FPU_FPA11 0x40000000#define FPU_NONE 0/* Some useful combinations. */#define FPU_ALL 0xff000000 /* Note this is ~ARM_ANY. */#define FPU_MEMMULTI 0x7f000000 /* Not fpu_core. */#ifndef CPU_DEFAULT#if defined __XSCALE__#define CPU_DEFAULT (ARM_9 | ARM_ARCH_XSCALE)#else#if defined __thumb__#define CPU_DEFAULT (ARM_7 | ARM_ARCH_V4T)#else#define CPU_DEFAULT ARM_ALL#endif#endif#endif#ifndef FPU_DEFAULT#define FPU_DEFAULT FPU_ALL#endif#define streq(a, b) (strcmp (a, b) == 0)#define skip_whitespace(str) while (*(str) == ' ') ++(str)static unsigned long cpu_variant = CPU_DEFAULT | FPU_DEFAULT;static int target_oabi = 0;#if defined OBJ_COFF || defined OBJ_ELF/* Flags stored in private area of BFD structure. */static boolean uses_apcs_26 = false;static boolean atpcs = false;static boolean support_interwork = false;static boolean uses_apcs_float = false;static boolean pic_code = false;#endif/* This array holds the chars that always start a comment. If the pre-processor is disabled, these aren't very useful. */CONST char comment_chars[] = "@";/* This array holds the chars that only start a comment at the beginning of a line. If the line seems to have the form '# 123 filename' .line and .file directives will appear in the pre-processed output. *//* Note that input_file.c hand checks for '#' at the beginning of the first line of the input file. This is because the compiler outputs #NO_APP at the beginning of its output. *//* Also note that comments like this one will always work. */CONST char line_comment_chars[] = "#";CONST char line_separator_chars[] = ";";/* Chars that can be used to separate mant from exp in floating point numbers. */CONST char EXP_CHARS[] = "eE";/* Chars that mean this number is a floating point constant. *//* As in 0f12.456 *//* or 0d1.2345e12 */CONST char FLT_CHARS[] = "rRsSfFdDxXeEpP";/* Prefix characters that indicate the start of an immediate value. */#define is_immediate_prefix(C) ((C) == '#' || (C) == '$')#ifdef OBJ_ELF/* Pre-defined "_GLOBAL_OFFSET_TABLE_" */symbolS * GOT_symbol;#endif/* Size of relocation record. */CONST int md_reloc_size = 8;/* 0: assemble for ARM, 1: assemble for Thumb, 2: assemble for Thumb even though target CPU does not support thumb instructions. */static int thumb_mode = 0;typedef struct arm_fix{ int thumb_mode;} arm_fix_data;struct arm_it{ CONST char * error; unsigned long instruction; int suffix; int size; struct { bfd_reloc_code_real_type type; expressionS exp; int pc_rel; } reloc;};struct arm_it inst;enum asm_shift_index{ SHIFT_LSL = 0, SHIFT_LSR, SHIFT_ASR, SHIFT_ROR, SHIFT_RRX};struct asm_shift_properties{ enum asm_shift_index index; unsigned long bit_field; unsigned int allows_0 : 1; unsigned int allows_32 : 1;};static const struct asm_shift_properties shift_properties [] ={ { SHIFT_LSL, 0, 1, 0}, { SHIFT_LSR, 0x20, 0, 1}, { SHIFT_ASR, 0x40, 0, 1}, { SHIFT_ROR, 0x60, 0, 0}, { SHIFT_RRX, 0x60, 0, 0}};struct asm_shift_name{ const char * name; const struct asm_shift_properties * properties;};static const struct asm_shift_name shift_names [] ={ { "asl", shift_properties + SHIFT_LSL }, { "lsl", shift_properties + SHIFT_LSL }, { "lsr", shift_properties + SHIFT_LSR }, { "asr", shift_properties + SHIFT_ASR }, { "ror", shift_properties + SHIFT_ROR }, { "rrx", shift_properties + SHIFT_RRX }, { "ASL", shift_properties + SHIFT_LSL }, { "LSL", shift_properties + SHIFT_LSL }, { "LSR", shift_properties + SHIFT_LSR }, { "ASR", shift_properties + SHIFT_ASR }, { "ROR", shift_properties + SHIFT_ROR }, { "RRX", shift_properties + SHIFT_RRX }};#define NO_SHIFT_RESTRICT 1#define SHIFT_RESTRICT 0#define NUM_FLOAT_VALS 8CONST char * fp_const[] ={ "0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0", 0};/* Number of littlenums required to hold an extended precision number. */#define MAX_LITTLENUMS 6LITTLENUM_TYPE fp_values[NUM_FLOAT_VALS][MAX_LITTLENUMS];#define FAIL (-1)#define SUCCESS (0)#define SUFF_S 1#define SUFF_D 2#define SUFF_E 3#define SUFF_P 4#define CP_T_X 0x00008000#define CP_T_Y 0x00400000#define CP_T_Pre 0x01000000#define CP_T_UD 0x00800000#define CP_T_WB 0x00200000#define CONDS_BIT 0x00100000#define LOAD_BIT 0x00100000#define TRANS_BIT 0x00200000#define DOUBLE_LOAD_FLAG 0x00000001struct asm_cond{ CONST char * template; unsigned long value;};/* This is to save a hash look-up in the common case. */#define COND_ALWAYS 0xe0000000static CONST struct asm_cond conds[] ={ {"eq", 0x00000000}, {"ne", 0x10000000}, {"cs", 0x20000000}, {"hs", 0x20000000}, {"cc", 0x30000000}, {"ul", 0x30000000}, {"lo", 0x30000000}, {"mi", 0x40000000}, {"pl", 0x50000000}, {"vs", 0x60000000}, {"vc", 0x70000000}, {"hi", 0x80000000}, {"ls", 0x90000000}, {"ge", 0xa0000000}, {"lt", 0xb0000000}, {"gt", 0xc0000000}, {"le", 0xd0000000}, {"al", 0xe0000000}, {"nv", 0xf0000000}};/* Warning: If the top bit of the set_bits is set, then the standard instruction bitmask is ignored, and the new bitmask is taken from the set_bits: */struct asm_flg{ CONST char * template; /* Basic flag string. */ unsigned long set_bits; /* Bits to set. */};static CONST struct asm_flg s_flag[] ={ {"s", CONDS_BIT}, {NULL, 0}};static CONST struct asm_flg ldr_flags[] ={ {"d", DOUBLE_LOAD_FLAG}, {"b", 0x00400000}, {"t", TRANS_BIT}, {"bt", 0x00400000 | TRANS_BIT}, {"h", 0x801000b0}, {"sh", 0x801000f0}, {"sb", 0x801000d0}, {NULL, 0}};static CONST struct asm_flg str_flags[] ={ {"d", DOUBLE_LOAD_FLAG}, {"b", 0x00400000}, {"t", TRANS_BIT}, {"bt", 0x00400000 | TRANS_BIT}, {"h", 0x800000b0}, {NULL, 0}};static CONST struct asm_flg byte_flag[] ={ {"b", 0x00400000}, {NULL, 0}};static CONST struct asm_flg cmp_flags[] ={ {"s", CONDS_BIT}, {"p", 0x0010f000}, {NULL, 0}};static CONST struct asm_flg ldm_flags[] ={ {"ed", 0x01800000}, {"fd", 0x00800000}, {"ea", 0x01000000}, {"fa", 0x00000000}, {"ib", 0x01800000}, {"ia", 0x00800000}, {"db", 0x01000000}, {"da", 0x00000000}, {NULL, 0}};static CONST struct asm_flg stm_flags[] ={ {"ed", 0x00000000}, {"fd", 0x01000000}, {"ea", 0x00800000}, {"fa", 0x01800000}, {"ib", 0x01800000}, {"ia", 0x00800000}, {"db", 0x01000000}, {"da", 0x00000000}, {NULL, 0}};static CONST struct asm_flg lfm_flags[] ={ {"fd", 0x00800000}, {"ea", 0x01000000}, {NULL, 0}};static CONST struct asm_flg sfm_flags[] ={ {"fd", 0x01000000}, {"ea", 0x00800000}, {NULL, 0}};static CONST struct asm_flg round_flags[] ={ {"p", 0x00000020}, {"m", 0x00000040}, {"z", 0x00000060}, {NULL, 0}};/* The implementation of the FIX instruction is broken on some assemblers, in that it accepts a precision specifier as well as a rounding specifier, despite the fact that this is meaningless. To be more compatible, we accept it as well, though of course it does not set any bits. */static CONST struct asm_flg fix_flags[] ={ {"p", 0x00000020}, {"m", 0x00000040}, {"z", 0x00000060}, {"sp", 0x00000020}, {"sm", 0x00000040}, {"sz", 0x00000060}, {"dp", 0x00000020}, {"dm", 0x00000040}, {"dz", 0x00000060}, {"ep", 0x00000020}, {"em", 0x00000040}, {"ez", 0x00000060}, {NULL, 0}};static CONST struct asm_flg except_flag[] ={ {"e", 0x00400000}, {NULL, 0}};static CONST struct asm_flg cplong_flag[] ={ {"l", 0x00400000}, {NULL, 0}};struct asm_psr{ CONST char * template; boolean cpsr; unsigned long field;};/* The bit that distnguishes CPSR and SPSR. */#define SPSR_BIT (1 << 22)/* How many bits to shift the PSR_xxx bits up by. */#define PSR_SHIFT 16#define PSR_c (1 << 0)#define PSR_x (1 << 1)#define PSR_s (1 << 2)#define PSR_f (1 << 3)static CONST struct asm_psr psrs[] ={ {"CPSR", true, PSR_c | PSR_f}, {"CPSR_all", true, PSR_c | PSR_f},
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -