📄 tc-ia64.c
字号:
/* tc-ia64.c -- Assembler for the HP/Intel IA-64 architecture. Copyright 1998, 1999, 2000, 2001 Free Software Foundation, Inc. Contributed by David Mosberger-Tang <davidm@hpl.hp.com> This file is part of GAS, the GNU Assembler. GAS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GAS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GAS; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *//* TODO: - optional operands - directives: .alias .eb .estate .lb .popsection .previous .psr .pushsection - labels are wrong if automatic alignment is introduced (e.g., checkout the second real10 definition in test-data.s) - DV-related stuff: <reg>.safe_across_calls and any other DV-related directives I don't have documentation for. verify mod-sched-brs reads/writes are checked/marked (and other notes) */#include "as.h"#include "dwarf2dbg.h"#include "subsegs.h"#include "opcode/ia64.h"#include "elf/ia64.h"#define NELEMS(a) ((int) (sizeof (a)/sizeof ((a)[0])))#define MIN(a,b) ((a) < (b) ? (a) : (b))#define NUM_SLOTS 4#define PREV_SLOT md.slot[(md.curr_slot + NUM_SLOTS - 1) % NUM_SLOTS]#define CURR_SLOT md.slot[md.curr_slot]#define O_pseudo_fixup (O_max + 1)enum special_section { SPECIAL_SECTION_BSS = 0, SPECIAL_SECTION_SBSS, SPECIAL_SECTION_SDATA, SPECIAL_SECTION_RODATA, SPECIAL_SECTION_COMMENT, SPECIAL_SECTION_UNWIND, SPECIAL_SECTION_UNWIND_INFO };enum reloc_func { FUNC_FPTR_RELATIVE, FUNC_GP_RELATIVE, FUNC_LT_RELATIVE, FUNC_PC_RELATIVE, FUNC_PLT_RELATIVE, FUNC_SEC_RELATIVE, FUNC_SEG_RELATIVE, FUNC_LTV_RELATIVE, FUNC_LT_FPTR_RELATIVE, };enum reg_symbol { REG_GR = 0, REG_FR = (REG_GR + 128), REG_AR = (REG_FR + 128), REG_CR = (REG_AR + 128), REG_P = (REG_CR + 128), REG_BR = (REG_P + 64), REG_IP = (REG_BR + 8), REG_CFM, REG_PR, REG_PR_ROT, REG_PSR, REG_PSR_L, REG_PSR_UM, /* The following are pseudo-registers for use by gas only. */ IND_CPUID, IND_DBR, IND_DTR, IND_ITR, IND_IBR, IND_MEM, IND_MSR, IND_PKR, IND_PMC, IND_PMD, IND_RR, /* The following pseudo-registers are used for unwind directives only: */ REG_PSP, REG_PRIUNAT, REG_NUM };enum dynreg_type { DYNREG_GR = 0, /* dynamic general purpose register */ DYNREG_FR, /* dynamic floating point register */ DYNREG_PR, /* dynamic predicate register */ DYNREG_NUM_TYPES };enum operand_match_result { OPERAND_MATCH, OPERAND_OUT_OF_RANGE, OPERAND_MISMATCH };/* On the ia64, we can't know the address of a text label until the instructions are packed into a bundle. To handle this, we keep track of the list of labels that appear in front of each instruction. */struct label_fix{ struct label_fix *next; struct symbol *sym;};extern int target_big_endian;/* 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[] = "rRsSfFdDxXpP";/* ia64-specific option processing: */const char *md_shortopts = "m:N:x::";struct option md_longopts[] = {#define OPTION_MCONSTANT_GP (OPTION_MD_BASE + 1) {"mconstant-gp", no_argument, NULL, OPTION_MCONSTANT_GP},#define OPTION_MAUTO_PIC (OPTION_MD_BASE + 2) {"mauto-pic", no_argument, NULL, OPTION_MAUTO_PIC} };size_t md_longopts_size = sizeof (md_longopts);static struct { struct hash_control *pseudo_hash; /* pseudo opcode hash table */ struct hash_control *reg_hash; /* register name hash table */ struct hash_control *dynreg_hash; /* dynamic register hash table */ struct hash_control *const_hash; /* constant hash table */ struct hash_control *entry_hash; /* code entry hint hash table */ symbolS *regsym[REG_NUM]; /* If X_op is != O_absent, the registername for the instruction's qualifying predicate. If NULL, p0 is assumed for instructions that are predicatable. */ expressionS qp; unsigned int manual_bundling : 1, debug_dv: 1, detect_dv: 1, explicit_mode : 1, /* which mode we're in */ default_explicit_mode : 1, /* which mode is the default */ mode_explicitly_set : 1, /* was the current mode explicitly set? */ auto_align : 1, keep_pending_output : 1; /* Each bundle consists of up to three instructions. We keep track of four most recent instructions so we can correctly set the end_of_insn_group for the last instruction in a bundle. */ int curr_slot; int num_slots_in_use; struct slot { unsigned int end_of_insn_group : 1, manual_bundling_on : 1, manual_bundling_off : 1; signed char user_template; /* user-selected template, if any */ unsigned char qp_regno; /* qualifying predicate */ /* This duplicates a good fraction of "struct fix" but we can't use a "struct fix" instead since we can't call fix_new_exp() until we know the address of the instruction. */ int num_fixups; struct insn_fix { bfd_reloc_code_real_type code; enum ia64_opnd opnd; /* type of operand in need of fix */ unsigned int is_pcrel : 1; /* is operand pc-relative? */ expressionS expr; /* the value to be inserted */ } fixup[2]; /* at most two fixups per insn */ struct ia64_opcode *idesc; struct label_fix *label_fixups; struct label_fix *tag_fixups; struct unw_rec_list *unwind_record; /* Unwind directive. */ expressionS opnd[6]; char *src_file; unsigned int src_line; struct dwarf2_line_info debug_line; } slot[NUM_SLOTS]; segT last_text_seg; struct dynreg { struct dynreg *next; /* next dynamic register */ const char *name; unsigned short base; /* the base register number */ unsigned short num_regs; /* # of registers in this set */ } *dynreg[DYNREG_NUM_TYPES], in, loc, out, rot; flagword flags; /* ELF-header flags */ struct mem_offset { unsigned hint:1; /* is this hint currently valid? */ bfd_vma offset; /* mem.offset offset */ bfd_vma base; /* mem.offset base */ } mem_offset; int path; /* number of alt. entry points seen */ const char **entry_labels; /* labels of all alternate paths in the current DV-checking block. */ int maxpaths; /* size currently allocated for entry_labels */ /* Support for hardware errata workarounds. */ /* Record data about the last three insn groups. */ struct group { /* B-step workaround. For each predicate register, this is set if the corresponding insn group conditionally sets this register with one of the affected instructions. */ int p_reg_set[64]; /* B-step workaround. For each general register, this is set if the corresponding insn a) is conditional one one of the predicate registers for which P_REG_SET is 1 in the corresponding entry of the previous group, b) sets this general register with one of the affected instructions. */ int g_reg_set_conditionally[128]; } last_groups[3]; int group_idx; }md;/* application registers: */#define AR_K0 0#define AR_K7 7#define AR_RSC 16#define AR_BSP 17#define AR_BSPSTORE 18#define AR_RNAT 19#define AR_UNAT 36#define AR_FPSR 40#define AR_ITC 44#define AR_PFS 64#define AR_LC 65static const struct { const char *name; int regnum; }ar[] = { {"ar.k0", 0}, {"ar.k1", 1}, {"ar.k2", 2}, {"ar.k3", 3}, {"ar.k4", 4}, {"ar.k5", 5}, {"ar.k6", 6}, {"ar.k7", 7}, {"ar.rsc", 16}, {"ar.bsp", 17}, {"ar.bspstore", 18}, {"ar.rnat", 19}, {"ar.fcr", 21}, {"ar.eflag", 24}, {"ar.csd", 25}, {"ar.ssd", 26}, {"ar.cflg", 27}, {"ar.fsr", 28}, {"ar.fir", 29}, {"ar.fdr", 30}, {"ar.ccv", 32}, {"ar.unat", 36}, {"ar.fpsr", 40}, {"ar.itc", 44}, {"ar.pfs", 64}, {"ar.lc", 65}, {"ar.ec", 66}, };#define CR_IPSR 16#define CR_ISR 17#define CR_IIP 19#define CR_IFA 20#define CR_ITIR 21#define CR_IIPA 22#define CR_IFS 23#define CR_IIM 24#define CR_IHA 25#define CR_IVR 65#define CR_TPR 66#define CR_EOI 67#define CR_IRR0 68#define CR_IRR3 71#define CR_LRR0 80#define CR_LRR1 81/* control registers: */static const struct { const char *name; int regnum; }cr[] = { {"cr.dcr", 0}, {"cr.itm", 1}, {"cr.iva", 2}, {"cr.pta", 8}, {"cr.gpta", 9}, {"cr.ipsr", 16}, {"cr.isr", 17}, {"cr.iip", 19}, {"cr.ifa", 20}, {"cr.itir", 21}, {"cr.iipa", 22}, {"cr.ifs", 23}, {"cr.iim", 24}, {"cr.iha", 25}, {"cr.lid", 64}, {"cr.ivr", 65}, {"cr.tpr", 66}, {"cr.eoi", 67}, {"cr.irr0", 68}, {"cr.irr1", 69}, {"cr.irr2", 70}, {"cr.irr3", 71}, {"cr.itv", 72}, {"cr.pmv", 73}, {"cr.cmcv", 74}, {"cr.lrr0", 80}, {"cr.lrr1", 81} };#define PSR_MFL 4#define PSR_IC 13#define PSR_DFL 18#define PSR_CPL 32static const struct const_desc { const char *name; valueT value; }const_bits[] = { /* PSR constant masks: */ /* 0: reserved */ {"psr.be", ((valueT) 1) << 1}, {"psr.up", ((valueT) 1) << 2}, {"psr.ac", ((valueT) 1) << 3}, {"psr.mfl", ((valueT) 1) << 4}, {"psr.mfh", ((valueT) 1) << 5}, /* 6-12: reserved */ {"psr.ic", ((valueT) 1) << 13}, {"psr.i", ((valueT) 1) << 14}, {"psr.pk", ((valueT) 1) << 15}, /* 16: reserved */ {"psr.dt", ((valueT) 1) << 17}, {"psr.dfl", ((valueT) 1) << 18}, {"psr.dfh", ((valueT) 1) << 19}, {"psr.sp", ((valueT) 1) << 20}, {"psr.pp", ((valueT) 1) << 21}, {"psr.di", ((valueT) 1) << 22}, {"psr.si", ((valueT) 1) << 23}, {"psr.db", ((valueT) 1) << 24}, {"psr.lp", ((valueT) 1) << 25}, {"psr.tb", ((valueT) 1) << 26}, {"psr.rt", ((valueT) 1) << 27}, /* 28-31: reserved */ /* 32-33: cpl (current privilege level) */ {"psr.is", ((valueT) 1) << 34}, {"psr.mc", ((valueT) 1) << 35}, {"psr.it", ((valueT) 1) << 36}, {"psr.id", ((valueT) 1) << 37}, {"psr.da", ((valueT) 1) << 38}, {"psr.dd", ((valueT) 1) << 39}, {"psr.ss", ((valueT) 1) << 40}, /* 41-42: ri (restart instruction) */ {"psr.ed", ((valueT) 1) << 43}, {"psr.bn", ((valueT) 1) << 44}, };/* indirect register-sets/memory: */static const struct { const char *name; int regnum; }indirect_reg[] = { { "CPUID", IND_CPUID }, { "cpuid", IND_CPUID }, { "dbr", IND_DBR }, { "dtr", IND_DTR }, { "itr", IND_ITR }, { "ibr", IND_IBR }, { "msr", IND_MSR }, { "pkr", IND_PKR }, { "pmc", IND_PMC }, { "pmd", IND_PMD }, { "rr", IND_RR }, };/* Pseudo functions used to indicate relocation types (these functions start with an at sign (@). */static struct { const char *name; enum pseudo_type { PSEUDO_FUNC_NONE, PSEUDO_FUNC_RELOC, PSEUDO_FUNC_CONST, PSEUDO_FUNC_REG, PSEUDO_FUNC_FLOAT } type; union { unsigned long ival; symbolS *sym; } u; }pseudo_func[] = { /* reloc pseudo functions (these must come first!): */ { "fptr", PSEUDO_FUNC_RELOC, { 0 } }, { "gprel", PSEUDO_FUNC_RELOC, { 0 } }, { "ltoff", PSEUDO_FUNC_RELOC, { 0 } }, { "pcrel", PSEUDO_FUNC_RELOC, { 0 } }, { "pltoff", PSEUDO_FUNC_RELOC, { 0 } }, { "secrel", PSEUDO_FUNC_RELOC, { 0 } }, { "segrel", PSEUDO_FUNC_RELOC, { 0 } }, { "ltv", PSEUDO_FUNC_RELOC, { 0 } }, { "", 0, { 0 } }, /* placeholder for FUNC_LT_FPTR_RELATIVE */ /* mbtype4 constants: */ { "alt", PSEUDO_FUNC_CONST, { 0xa } }, { "brcst", PSEUDO_FUNC_CONST, { 0x0 } }, { "mix", PSEUDO_FUNC_CONST, { 0x8 } }, { "rev", PSEUDO_FUNC_CONST, { 0xb } }, { "shuf", PSEUDO_FUNC_CONST, { 0x9 } }, /* fclass constants: */ { "nat", PSEUDO_FUNC_CONST, { 0x100 } }, { "qnan", PSEUDO_FUNC_CONST, { 0x080 } }, { "snan", PSEUDO_FUNC_CONST, { 0x040 } }, { "pos", PSEUDO_FUNC_CONST, { 0x001 } }, { "neg", PSEUDO_FUNC_CONST, { 0x002 } }, { "zero", PSEUDO_FUNC_CONST, { 0x004 } }, { "unorm", PSEUDO_FUNC_CONST, { 0x008 } }, { "norm", PSEUDO_FUNC_CONST, { 0x010 } }, { "inf", PSEUDO_FUNC_CONST, { 0x020 } }, { "natval", PSEUDO_FUNC_CONST, { 0x100 } }, /* old usage */ /* unwind-related constants: */ { "svr4", PSEUDO_FUNC_CONST, { 0 } }, { "hpux", PSEUDO_FUNC_CONST, { 1 } },
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -