📄 tc-i370.c
字号:
/* tc-i370.c -- Assembler for the IBM 360/370/390 instruction set. Loosely based on the ppc files by Linas Vepstas <linas@linas.org> 1998, 99 Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. Written by Ian Lance Taylor, Cygnus Support. 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. *//* This assembler implements a very hacked version of an elf-like thing * that gcc emits (when gcc is suitably hacked). To make it behave more * HLASM-like, try turning on the -M or --mri flag (as there are various * similarities between HLASM and the MRI assemblers, such as section * names, lack of leading . in pseudo-ops, DC and DS, etc ... */#include <stdio.h>#include <ctype.h>#include "as.h"#include "subsegs.h"#include "struc-symbol.h"#include "opcode/i370.h"#ifdef OBJ_ELF#include "elf/i370.h"#endif/* This is the assembler for the System/390 Architecture *//* Tell the main code what the endianness is. */extern int target_big_endian;/* Generic assembler global variables which must be defined by all targets. */#ifdef OBJ_ELF/* This string holds the chars that always start a comment. If the pre-processor is disabled, these aren't very useful. The macro tc_comment_chars points to this. We use this, rather than the usual comment_chars, so that we can switch for Solaris conventions. */static const char i370_eabi_comment_chars[] = "#";const char *i370_comment_chars = i370_eabi_comment_chars;#elseconst char comment_chars[] = "#";#endif/* 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";voidmd_show_usage (stream) FILE *stream;{ fprintf (stream, "\S/370 options: (these have not yet been tested and may not work) \n\-u ignored\n\-mregnames Allow symbolic names for registers\n\-mno-regnames Do not allow symbolic names for registers\n");#ifdef OBJ_ELF fprintf (stream, "\-mrelocatable support for GCC's -mrelocatble option\n\-mrelocatable-lib support for GCC's -mrelocatble-lib option\n\-V print assembler version number\n");#endif}static void i370_byte PARAMS ((int));static void i370_tc PARAMS ((int));static void i370_ebcdic PARAMS ((int));static void i370_dc PARAMS ((int));static void i370_ds PARAMS ((int));static void i370_rmode PARAMS ((int));static void i370_csect PARAMS ((int));static void i370_dsect PARAMS ((int));static void i370_ltorg PARAMS ((int));static void i370_using PARAMS ((int));static void i370_drop PARAMS ((int));static void i370_make_relative PARAMS ((expressionS *exp, expressionS *baseaddr));#ifdef OBJ_ELFstatic bfd_reloc_code_real_type i370_elf_suffix PARAMS ((char **, expressionS *));static void i370_elf_cons PARAMS ((int));static void i370_elf_rdata PARAMS ((int));static void i370_elf_lcomm PARAMS ((int));static void i370_elf_validate_fix PARAMS ((fixS *, segT));#endif/* The target specific pseudo-ops which we support. */const pseudo_typeS md_pseudo_table[] ={ /* Pseudo-ops which must be overridden. */ { "byte", i370_byte, 0 }, { "dc", i370_dc, 0 }, { "ds", i370_ds, 0 }, { "rmode", i370_rmode, 0 }, { "csect", i370_csect, 0 }, { "dsect", i370_dsect, 0 }, /* enable ebcdic strings e.g. for 3270 support */ { "ebcdic", i370_ebcdic, 0 },#ifdef OBJ_ELF { "long", i370_elf_cons, 4 }, { "word", i370_elf_cons, 4 }, { "short", i370_elf_cons, 2 }, { "rdata", i370_elf_rdata, 0 }, { "rodata", i370_elf_rdata, 0 }, { "lcomm", i370_elf_lcomm, 0 },#endif /* This pseudo-op is used even when not generating XCOFF output. */ { "tc", i370_tc, 0 }, /* dump the literal pool */ { "ltorg", i370_ltorg, 0 }, /* support the hlasm-style USING directive */ { "using", i370_using, 0 }, { "drop", i370_drop, 0 }, { NULL, NULL, 0 }};/* ***************************************************************** *//* Whether to use user friendly register names. */#define TARGET_REG_NAMES_P truestatic boolean reg_names_p = TARGET_REG_NAMES_P;static boolean register_name PARAMS ((expressionS *));static void i370_set_cpu PARAMS ((void));static i370_insn_t i370_insert_operand PARAMS ((i370_insn_t insn, const struct i370_operand *operand, offsetT val));static void i370_macro PARAMS ((char *str, const struct i370_macro *macro));/* Predefined register names if -mregnames *//* In general, there are lots of them, in an attempt to be compatible *//* with a number of assemblers. *//* Structure to hold information about predefined registers. */struct pd_reg { char *name; int value; };/* List of registers that are pre-defined: Each general register has predefined names of the form: 1. r<reg_num> which has the value <reg_num>. 2. r.<reg_num> which has the value <reg_num>. Each floating point register has predefined names of the form: 1. f<reg_num> which has the value <reg_num>. 2. f.<reg_num> which has the value <reg_num>. There are only four floating point registers, and these are commonly labelled 0,2,4 and 6. Thus, there is no f1, f3, etc. There are individual registers as well: rbase or r.base has the value 3 (base register) rpgt or r.pgt has the value 4 (page origin table pointer) rarg or r.arg has the value 11 (argument pointer) rtca or r.tca has the value 12 (table of contents pointer) rtoc or r.toc has the value 12 (table of contents pointer) sp or r.sp has the value 13 (stack pointer) dsa or r.dsa has the value 13 (stack pointer) lr has the value 14 (link reg) The table is sorted. Suitable for searching by a binary search. */static const struct pd_reg pre_defined_registers[] ={ { "arg", 11 }, /* Argument Pointer */ { "base", 3 }, /* Base Reg */ { "f.0", 0 }, /* Floating point registers */ { "f.2", 2 }, { "f.4", 4 }, { "f.6", 6 }, { "f0", 0 }, { "f2", 2 }, { "f4", 4 }, { "f6", 6 }, { "dsa",13 }, /* stack pointer */ { "lr", 14 }, /* Link Register */ { "pgt", 4 }, /* Page Origin Table Pointer */ { "r.0", 0 }, /* General Purpose Registers */ { "r.1", 1 }, { "r.10", 10 }, { "r.11", 11 }, { "r.12", 12 }, { "r.13", 13 }, { "r.14", 14 }, { "r.15", 15 }, { "r.2", 2 }, { "r.3", 3 }, { "r.4", 4 }, { "r.5", 5 }, { "r.6", 6 }, { "r.7", 7 }, { "r.8", 8 }, { "r.9", 9 }, { "r.arg", 11 }, /* Argument Pointer */ { "r.base", 3 }, /* Base Reg */ { "r.dsa", 13 }, /* Stack Pointer */ { "r.pgt", 4 }, /* Page Origin Table Pointer */ { "r.sp", 13 }, /* Stack Pointer */ { "r.tca", 12 }, /* Pointer to the table of contents */ { "r.toc", 12 }, /* Pointer to the table of contents */ { "r0", 0 }, /* More general purpose registers */ { "r1", 1 }, { "r10", 10 }, { "r11", 11 }, { "r12", 12 }, { "r13", 13 }, { "r14", 14 }, { "r15", 15 }, { "r2", 2 }, { "r3", 3 }, { "r4", 4 }, { "r5", 5 }, { "r6", 6 }, { "r7", 7 }, { "r8", 8 }, { "r9", 9 }, { "rbase", 3 }, /* Base Reg */ { "rtca", 12 }, /* Pointer to the table of contents */ { "rtoc", 12 }, /* Pointer to the table of contents */ { "sp", 13 }, /* Stack Pointer */};#define REG_NAME_CNT (sizeof (pre_defined_registers) / sizeof (struct pd_reg))/* Given NAME, find the register number associated with that name, return the integer value associated with the given name or -1 on failure. */static int reg_name_search PARAMS ((const struct pd_reg *, int, const char * name));static intreg_name_search (regs, regcount, name) const struct pd_reg *regs; int regcount; const char *name;{ int middle, low, high; int cmp; low = 0; high = regcount - 1; do { middle = (low + high) / 2; cmp = strcasecmp (name, regs[middle].name); if (cmp < 0) high = middle - 1; else if (cmp > 0) low = middle + 1; else return regs[middle].value; } while (low <= high); return -1;}/* * Summary of register_name(). * * in: Input_line_pointer points to 1st char of operand. * * out: A expressionS. * The operand may have been a register: in this case, X_op == O_register, * X_add_number is set to the register number, and truth is returned. * Input_line_pointer->(next non-blank) char after operand, or is in its * original state. */static booleanregister_name (expressionP) expressionS *expressionP;{ int reg_number; char *name; char *start; char c; /* Find the spelling of the operand */ start = name = input_line_pointer; if (name[0] == '%' && isalpha (name[1])) name = ++input_line_pointer; else if (!reg_names_p) return false; while (' ' == *name) name = ++input_line_pointer; /* if its a number, treat it as a number */ /* if its alpha, look to see if it's in the register table */ if (!isalpha (name[0])) { reg_number = get_single_number(); c = get_symbol_end (); } else { c = get_symbol_end (); reg_number = reg_name_search (pre_defined_registers, REG_NAME_CNT, name); } /* if numeric, make sure its not out of bounds */ if ((0 <= reg_number) && (16 >= reg_number)) { expressionP->X_op = O_register; expressionP->X_add_number = reg_number; /* make the rest nice */ expressionP->X_add_symbol = NULL; expressionP->X_op_symbol = NULL; *input_line_pointer = c; /* put back the delimiting char */ return true; } /* reset the line as if we had not done anything */ *input_line_pointer = c; /* put back the delimiting char */ input_line_pointer = start; /* reset input_line pointer */ return false;}/* Local variables. *//* The type of processor we are assembling for. This is one or more of the I370_OPCODE flags defined in opcode/i370.h. */static int i370_cpu = 0;/* The base register to use for opcode with optional operands. * We define two of these: "text" and "other". Normally, "text" * would get used in the .text section for branches, while "other" * gets used in the .data section for address constants. * * The idea of a second base register in a different section * is foreign to the usual HLASM-style semantics; however, it * allows us to provide support for dynamically loaded libraries, * by allowing us to place address constants in a section other * than the text section. The "other" section need not be the * .data section, it can be any section that isn't the .text section. * * Note that HLASM defines a multiple, concurrent .using semantic * that we do not: in calculating offsets, it uses either the most * recent .using directive, or the one with the smallest displacement. * This allows HLASM to support a quasi-block-scope-like behaviour. * Handy for people writing assembly by hand ... but not supported * by us. */static int i370_using_text_regno = -1;static int i370_using_other_regno = -1;/* The base address for address literals */static expressionS i370_using_text_baseaddr;static expressionS i370_using_other_baseaddr;/* the "other" section, used only for syntax error detection */static segT i370_other_section = undefined_section;/* Opcode hash table. */static struct hash_control *i370_hash;/* Macro hash table. */static struct hash_control *i370_macro_hash;#ifdef OBJ_ELF/* What type of shared library support to use */static enum { SHLIB_NONE, SHLIB_PIC, SHILB_MRELOCATABLE } shlib = SHLIB_NONE;#endif/* Flags to set in the elf header */static flagword i370_flags = 0;#ifndef WORKING_DOT_WORDconst int md_short_jump_size = 4;const int md_long_jump_size = 4;#endif#ifdef OBJ_ELFCONST char *md_shortopts = "l:um:K:VQ:";#elseCONST char *md_shortopts = "um:";#endifstruct option md_longopts[] ={ {NULL, no_argument, NULL, 0}};size_t md_longopts_size = sizeof (md_longopts);intmd_parse_option (c, arg) int c; char *arg;{ switch (c) { case 'u': /* -u means that any undefined symbols should be treated as external, which is the default for gas anyhow. */ break;#ifdef OBJ_ELF
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -