199461Sobrien/* tc-s390.c -- Assemble for the S390 2218822Sdim Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006 3218822Sdim Free Software Foundation, Inc. 499461Sobrien Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). 599461Sobrien 699461Sobrien This file is part of GAS, the GNU Assembler. 799461Sobrien 899461Sobrien GAS is free software; you can redistribute it and/or modify 999461Sobrien it under the terms of the GNU General Public License as published by 1099461Sobrien the Free Software Foundation; either version 2, or (at your option) 1199461Sobrien any later version. 1299461Sobrien 1399461Sobrien GAS is distributed in the hope that it will be useful, 1499461Sobrien but WITHOUT ANY WARRANTY; without even the implied warranty of 1599461Sobrien MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1699461Sobrien GNU General Public License for more details. 1799461Sobrien 1899461Sobrien You should have received a copy of the GNU General Public License 1999461Sobrien along with GAS; see the file COPYING. If not, write to the Free 20218822Sdim Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 21218822Sdim 02110-1301, USA. */ 2299461Sobrien 2399461Sobrien#include "as.h" 2499461Sobrien#include "safe-ctype.h" 2599461Sobrien#include "subsegs.h" 2699461Sobrien#include "struc-symbol.h" 27130561Sobrien#include "dwarf2dbg.h" 28130561Sobrien#include "dw2gencfi.h" 2999461Sobrien 3099461Sobrien#include "opcode/s390.h" 3199461Sobrien#include "elf/s390.h" 3299461Sobrien 3399461Sobrien/* The default architecture. */ 3499461Sobrien#ifndef DEFAULT_ARCH 3599461Sobrien#define DEFAULT_ARCH "s390" 3699461Sobrien#endif 3799461Sobrienstatic char *default_arch = DEFAULT_ARCH; 3899461Sobrien/* Either 32 or 64, selects file format. */ 39130561Sobrienstatic int s390_arch_size = 0; 4099461Sobrien 41130561Sobrienstatic unsigned int current_mode_mask = 0; 42130561Sobrienstatic unsigned int current_cpu = -1U; 43130561Sobrien 44130561Sobrien/* Whether to use user friendly register names. Default is TRUE. */ 4599461Sobrien#ifndef TARGET_REG_NAMES_P 46130561Sobrien#define TARGET_REG_NAMES_P TRUE 4799461Sobrien#endif 4899461Sobrien 49130561Sobrienstatic bfd_boolean reg_names_p = TARGET_REG_NAMES_P; 5099461Sobrien 5199461Sobrien/* Set to TRUE if we want to warn about zero base/index registers. */ 52130561Sobrienstatic bfd_boolean warn_areg_zero = FALSE; 5399461Sobrien 5499461Sobrien/* Generic assembler global variables which must be defined by all 5599461Sobrien targets. */ 5699461Sobrien 5799461Sobrienconst char comment_chars[] = "#"; 5899461Sobrien 5999461Sobrien/* Characters which start a comment at the beginning of a line. */ 6099461Sobrienconst char line_comment_chars[] = "#"; 6199461Sobrien 6299461Sobrien/* Characters which may be used to separate multiple commands on a 6399461Sobrien single line. */ 6499461Sobrienconst char line_separator_chars[] = ";"; 6599461Sobrien 6699461Sobrien/* Characters which are used to indicate an exponent in a floating 6799461Sobrien point number. */ 6899461Sobrienconst char EXP_CHARS[] = "eE"; 6999461Sobrien 7099461Sobrien/* Characters which mean that a number is a floating point constant, 7199461Sobrien as in 0d1.0. */ 7299461Sobrienconst char FLT_CHARS[] = "dD"; 7399461Sobrien 74130561Sobrien/* The dwarf2 data alignment, adjusted for 32 or 64 bit. */ 75130561Sobrienint s390_cie_data_alignment; 76130561Sobrien 7799461Sobrien/* The target specific pseudo-ops which we support. */ 7899461Sobrien 7999461Sobrien/* Define the prototypes for the pseudo-ops */ 8099461Sobrienstatic void s390_byte PARAMS ((int)); 8199461Sobrienstatic void s390_elf_cons PARAMS ((int)); 8299461Sobrienstatic void s390_bss PARAMS ((int)); 8399461Sobrienstatic void s390_insn PARAMS ((int)); 8499461Sobrienstatic void s390_literals PARAMS ((int)); 8599461Sobrien 8699461Sobrienconst pseudo_typeS md_pseudo_table[] = 8799461Sobrien{ 8899461Sobrien { "align", s_align_bytes, 0 }, 89107492Sobrien /* Pseudo-ops which must be defined. */ 9099461Sobrien { "bss", s390_bss, 0 }, 9199461Sobrien { "insn", s390_insn, 0 }, 9299461Sobrien /* Pseudo-ops which must be overridden. */ 9399461Sobrien { "byte", s390_byte, 0 }, 9499461Sobrien { "short", s390_elf_cons, 2 }, 9599461Sobrien { "long", s390_elf_cons, 4 }, 9699461Sobrien { "quad", s390_elf_cons, 8 }, 9799461Sobrien { "ltorg", s390_literals, 0 }, 9899461Sobrien { "string", stringer, 2 }, 9999461Sobrien { NULL, NULL, 0 } 10099461Sobrien}; 10199461Sobrien 10299461Sobrien 10399461Sobrien/* Structure to hold information about predefined registers. */ 10499461Sobrienstruct pd_reg 10599461Sobrien { 10699461Sobrien char *name; 10799461Sobrien int value; 10899461Sobrien }; 10999461Sobrien 11099461Sobrien/* List of registers that are pre-defined: 11199461Sobrien 11299461Sobrien Each access register has a predefined name of the form: 11399461Sobrien a<reg_num> which has the value <reg_num>. 11499461Sobrien 11599461Sobrien Each control register has a predefined name of the form: 11699461Sobrien c<reg_num> which has the value <reg_num>. 11799461Sobrien 11899461Sobrien Each general register has a predefined name of the form: 11999461Sobrien r<reg_num> which has the value <reg_num>. 12099461Sobrien 12199461Sobrien Each floating point register a has predefined name of the form: 12299461Sobrien f<reg_num> which has the value <reg_num>. 12399461Sobrien 12499461Sobrien There are individual registers as well: 12599461Sobrien sp has the value 15 12699461Sobrien lit has the value 12 12799461Sobrien 128107492Sobrien The table is sorted. Suitable for searching by a binary search. */ 12999461Sobrien 13099461Sobrienstatic const struct pd_reg pre_defined_registers[] = 13199461Sobrien{ 13299461Sobrien { "a0", 0 }, /* Access registers */ 13399461Sobrien { "a1", 1 }, 13499461Sobrien { "a10", 10 }, 13599461Sobrien { "a11", 11 }, 13699461Sobrien { "a12", 12 }, 13799461Sobrien { "a13", 13 }, 13899461Sobrien { "a14", 14 }, 13999461Sobrien { "a15", 15 }, 14099461Sobrien { "a2", 2 }, 14199461Sobrien { "a3", 3 }, 14299461Sobrien { "a4", 4 }, 14399461Sobrien { "a5", 5 }, 14499461Sobrien { "a6", 6 }, 14599461Sobrien { "a7", 7 }, 14699461Sobrien { "a8", 8 }, 14799461Sobrien { "a9", 9 }, 14899461Sobrien 14999461Sobrien { "c0", 0 }, /* Control registers */ 15099461Sobrien { "c1", 1 }, 15199461Sobrien { "c10", 10 }, 15299461Sobrien { "c11", 11 }, 15399461Sobrien { "c12", 12 }, 15499461Sobrien { "c13", 13 }, 15599461Sobrien { "c14", 14 }, 15699461Sobrien { "c15", 15 }, 15799461Sobrien { "c2", 2 }, 15899461Sobrien { "c3", 3 }, 15999461Sobrien { "c4", 4 }, 16099461Sobrien { "c5", 5 }, 16199461Sobrien { "c6", 6 }, 16299461Sobrien { "c7", 7 }, 16399461Sobrien { "c8", 8 }, 16499461Sobrien { "c9", 9 }, 16599461Sobrien 16699461Sobrien { "f0", 0 }, /* Floating point registers */ 16799461Sobrien { "f1", 1 }, 16899461Sobrien { "f10", 10 }, 16999461Sobrien { "f11", 11 }, 17099461Sobrien { "f12", 12 }, 17199461Sobrien { "f13", 13 }, 17299461Sobrien { "f14", 14 }, 17399461Sobrien { "f15", 15 }, 17499461Sobrien { "f2", 2 }, 17599461Sobrien { "f3", 3 }, 17699461Sobrien { "f4", 4 }, 17799461Sobrien { "f5", 5 }, 17899461Sobrien { "f6", 6 }, 17999461Sobrien { "f7", 7 }, 18099461Sobrien { "f8", 8 }, 18199461Sobrien { "f9", 9 }, 18299461Sobrien 18399461Sobrien { "lit", 13 }, /* Pointer to literal pool */ 18499461Sobrien 18599461Sobrien { "r0", 0 }, /* General purpose registers */ 18699461Sobrien { "r1", 1 }, 18799461Sobrien { "r10", 10 }, 18899461Sobrien { "r11", 11 }, 18999461Sobrien { "r12", 12 }, 19099461Sobrien { "r13", 13 }, 19199461Sobrien { "r14", 14 }, 19299461Sobrien { "r15", 15 }, 19399461Sobrien { "r2", 2 }, 19499461Sobrien { "r3", 3 }, 19599461Sobrien { "r4", 4 }, 19699461Sobrien { "r5", 5 }, 19799461Sobrien { "r6", 6 }, 19899461Sobrien { "r7", 7 }, 19999461Sobrien { "r8", 8 }, 20099461Sobrien { "r9", 9 }, 20199461Sobrien 20299461Sobrien { "sp", 15 }, /* Stack pointer */ 20399461Sobrien 20499461Sobrien}; 20599461Sobrien 20699461Sobrien#define REG_NAME_CNT (sizeof (pre_defined_registers) / sizeof (struct pd_reg)) 20799461Sobrien 20899461Sobrienstatic int reg_name_search 20999461Sobrien PARAMS ((const struct pd_reg *, int, const char *)); 210130561Sobrienstatic bfd_boolean register_name PARAMS ((expressionS *)); 21199461Sobrienstatic void init_default_arch PARAMS ((void)); 21299461Sobrienstatic void s390_insert_operand 21399461Sobrien PARAMS ((unsigned char *, const struct s390_operand *, offsetT, char *, 21499461Sobrien unsigned int)); 21599461Sobrienstatic char *md_gather_operands 21699461Sobrien PARAMS ((char *, unsigned char *, const struct s390_opcode *)); 21799461Sobrien 21899461Sobrien/* Given NAME, find the register number associated with that name, return 21999461Sobrien the integer value associated with the given name or -1 on failure. */ 22099461Sobrien 22199461Sobrienstatic int 22299461Sobrienreg_name_search (regs, regcount, name) 22399461Sobrien const struct pd_reg *regs; 22499461Sobrien int regcount; 22599461Sobrien const char *name; 22699461Sobrien{ 22799461Sobrien int middle, low, high; 22899461Sobrien int cmp; 22999461Sobrien 23099461Sobrien low = 0; 23199461Sobrien high = regcount - 1; 23299461Sobrien 23399461Sobrien do 23499461Sobrien { 23599461Sobrien middle = (low + high) / 2; 23699461Sobrien cmp = strcasecmp (name, regs[middle].name); 23799461Sobrien if (cmp < 0) 23899461Sobrien high = middle - 1; 23999461Sobrien else if (cmp > 0) 24099461Sobrien low = middle + 1; 24199461Sobrien else 24299461Sobrien return regs[middle].value; 24399461Sobrien } 24499461Sobrien while (low <= high); 24599461Sobrien 24699461Sobrien return -1; 24799461Sobrien} 24899461Sobrien 24999461Sobrien 25099461Sobrien/* 25199461Sobrien * Summary of register_name(). 25299461Sobrien * 25399461Sobrien * in: Input_line_pointer points to 1st char of operand. 25499461Sobrien * 25599461Sobrien * out: A expressionS. 25699461Sobrien * The operand may have been a register: in this case, X_op == O_register, 25799461Sobrien * X_add_number is set to the register number, and truth is returned. 25899461Sobrien * Input_line_pointer->(next non-blank) char after operand, or is in its 25999461Sobrien * original state. 26099461Sobrien */ 26199461Sobrien 262130561Sobrienstatic bfd_boolean 26399461Sobrienregister_name (expressionP) 26499461Sobrien expressionS *expressionP; 26599461Sobrien{ 26699461Sobrien int reg_number; 26799461Sobrien char *name; 26899461Sobrien char *start; 26999461Sobrien char c; 27099461Sobrien 27199461Sobrien /* Find the spelling of the operand. */ 27299461Sobrien start = name = input_line_pointer; 27399461Sobrien if (name[0] == '%' && ISALPHA (name[1])) 27499461Sobrien name = ++input_line_pointer; 27599461Sobrien else 276130561Sobrien return FALSE; 27799461Sobrien 27899461Sobrien c = get_symbol_end (); 27999461Sobrien reg_number = reg_name_search (pre_defined_registers, REG_NAME_CNT, name); 28099461Sobrien 28199461Sobrien /* Put back the delimiting char. */ 28299461Sobrien *input_line_pointer = c; 28399461Sobrien 28499461Sobrien /* Look to see if it's in the register table. */ 28599461Sobrien if (reg_number >= 0) 28699461Sobrien { 28799461Sobrien expressionP->X_op = O_register; 28899461Sobrien expressionP->X_add_number = reg_number; 28999461Sobrien 29099461Sobrien /* Make the rest nice. */ 29199461Sobrien expressionP->X_add_symbol = NULL; 29299461Sobrien expressionP->X_op_symbol = NULL; 293130561Sobrien return TRUE; 29499461Sobrien } 29599461Sobrien 29699461Sobrien /* Reset the line as if we had not done anything. */ 29799461Sobrien input_line_pointer = start; 298130561Sobrien return FALSE; 29999461Sobrien} 30099461Sobrien 30199461Sobrien/* Local variables. */ 30299461Sobrien 30399461Sobrien/* Opformat hash table. */ 30499461Sobrienstatic struct hash_control *s390_opformat_hash; 30599461Sobrien 30699461Sobrien/* Opcode hash table. */ 30799461Sobrienstatic struct hash_control *s390_opcode_hash; 30899461Sobrien 30999461Sobrien/* Flags to set in the elf header */ 31099461Sobrienstatic flagword s390_flags = 0; 31199461Sobrien 31299461SobriensymbolS *GOT_symbol; /* Pre-defined "_GLOBAL_OFFSET_TABLE_" */ 31399461Sobrien 31499461Sobrien#ifndef WORKING_DOT_WORD 315218822Sdimint md_short_jump_size = 4; 316218822Sdimint md_long_jump_size = 4; 31799461Sobrien#endif 31899461Sobrien 319107492Sobrienconst char *md_shortopts = "A:m:kVQ:"; 32099461Sobrienstruct option md_longopts[] = { 32199461Sobrien {NULL, no_argument, NULL, 0} 32299461Sobrien}; 32399461Sobriensize_t md_longopts_size = sizeof (md_longopts); 32499461Sobrien 32599461Sobrien/* Initialize the default opcode arch and word size from the default 326130561Sobrien architecture name if not specified by an option. */ 32799461Sobrienstatic void 32899461Sobrieninit_default_arch () 32999461Sobrien{ 33099461Sobrien if (strcmp (default_arch, "s390") == 0) 33199461Sobrien { 332130561Sobrien if (s390_arch_size == 0) 333130561Sobrien s390_arch_size = 32; 33499461Sobrien } 33599461Sobrien else if (strcmp (default_arch, "s390x") == 0) 33699461Sobrien { 337130561Sobrien if (s390_arch_size == 0) 338130561Sobrien s390_arch_size = 64; 33999461Sobrien } 34099461Sobrien else 34199461Sobrien as_fatal ("Invalid default architecture, broken assembler."); 342130561Sobrien 343130561Sobrien if (current_mode_mask == 0) 344130561Sobrien { 345130561Sobrien if (s390_arch_size == 32) 346130561Sobrien current_mode_mask = 1 << S390_OPCODE_ESA; 347130561Sobrien else 348130561Sobrien current_mode_mask = 1 << S390_OPCODE_ZARCH; 349130561Sobrien } 350130561Sobrien if (current_cpu == -1U) 351130561Sobrien { 352130561Sobrien if (current_mode_mask == (1 << S390_OPCODE_ESA)) 353130561Sobrien current_cpu = S390_OPCODE_G5; 354130561Sobrien else 355130561Sobrien current_cpu = S390_OPCODE_Z900; 356130561Sobrien } 35799461Sobrien} 35899461Sobrien 35999461Sobrien/* Called by TARGET_FORMAT. */ 36099461Sobrienconst char * 36199461Sobriens390_target_format () 36299461Sobrien{ 36399461Sobrien /* We don't get a chance to initialize anything before we're called, 36499461Sobrien so handle that now. */ 365130561Sobrien init_default_arch (); 36699461Sobrien 36799461Sobrien return s390_arch_size == 64 ? "elf64-s390" : "elf32-s390"; 36899461Sobrien} 36999461Sobrien 37099461Sobrienint 37199461Sobrienmd_parse_option (c, arg) 37299461Sobrien int c; 37399461Sobrien char *arg; 37499461Sobrien{ 37599461Sobrien switch (c) 37699461Sobrien { 37799461Sobrien /* -k: Ignore for FreeBSD compatibility. */ 37899461Sobrien case 'k': 37999461Sobrien break; 38099461Sobrien case 'm': 38199461Sobrien if (arg != NULL && strcmp (arg, "regnames") == 0) 382130561Sobrien reg_names_p = TRUE; 38399461Sobrien 38499461Sobrien else if (arg != NULL && strcmp (arg, "no-regnames") == 0) 385130561Sobrien reg_names_p = FALSE; 38699461Sobrien 38799461Sobrien else if (arg != NULL && strcmp (arg, "warn-areg-zero") == 0) 38899461Sobrien warn_areg_zero = TRUE; 38999461Sobrien 39099461Sobrien else if (arg != NULL && strcmp (arg, "31") == 0) 391130561Sobrien s390_arch_size = 32; 39299461Sobrien 39399461Sobrien else if (arg != NULL && strcmp (arg, "64") == 0) 39499461Sobrien s390_arch_size = 64; 39599461Sobrien 396130561Sobrien else if (arg != NULL && strcmp (arg, "esa") == 0) 397130561Sobrien current_mode_mask = 1 << S390_OPCODE_ESA; 398130561Sobrien 399130561Sobrien else if (arg != NULL && strcmp (arg, "zarch") == 0) 400130561Sobrien current_mode_mask = 1 << S390_OPCODE_ZARCH; 401130561Sobrien 402130561Sobrien else if (arg != NULL && strncmp (arg, "arch=", 5) == 0) 403130561Sobrien { 404130561Sobrien if (strcmp (arg + 5, "g5") == 0) 405130561Sobrien current_cpu = S390_OPCODE_G5; 406130561Sobrien else if (strcmp (arg + 5, "g6") == 0) 407130561Sobrien current_cpu = S390_OPCODE_G6; 408130561Sobrien else if (strcmp (arg + 5, "z900") == 0) 409130561Sobrien current_cpu = S390_OPCODE_Z900; 410130561Sobrien else if (strcmp (arg + 5, "z990") == 0) 411130561Sobrien current_cpu = S390_OPCODE_Z990; 412218822Sdim else if (strcmp (arg + 5, "z9-109") == 0) 413218822Sdim current_cpu = S390_OPCODE_Z9_109; 414218822Sdim else if (strcmp (arg + 5, "z9-ec") == 0) 415218822Sdim current_cpu = S390_OPCODE_Z9_EC; 416130561Sobrien else 417130561Sobrien { 418130561Sobrien as_bad (_("invalid switch -m%s"), arg); 419130561Sobrien return 0; 420130561Sobrien } 421130561Sobrien } 422130561Sobrien 42399461Sobrien else 42499461Sobrien { 42599461Sobrien as_bad (_("invalid switch -m%s"), arg); 42699461Sobrien return 0; 42799461Sobrien } 42899461Sobrien break; 42999461Sobrien 43099461Sobrien case 'A': 431130561Sobrien /* Option -A is deprecated. Still available for compatibility. */ 43299461Sobrien if (arg != NULL && strcmp (arg, "esa") == 0) 433130561Sobrien current_cpu = S390_OPCODE_G5; 43499461Sobrien else if (arg != NULL && strcmp (arg, "esame") == 0) 435130561Sobrien current_cpu = S390_OPCODE_Z900; 43699461Sobrien else 43799461Sobrien as_bad ("invalid architecture -A%s", arg); 43899461Sobrien break; 43999461Sobrien 44099461Sobrien /* -V: SVR4 argument to print version ID. */ 44199461Sobrien case 'V': 44299461Sobrien print_version_id (); 44399461Sobrien break; 44499461Sobrien 44599461Sobrien /* -Qy, -Qn: SVR4 arguments controlling whether a .comment section 44699461Sobrien should be emitted or not. FIXME: Not implemented. */ 44799461Sobrien case 'Q': 44899461Sobrien break; 44999461Sobrien 45099461Sobrien default: 45199461Sobrien return 0; 45299461Sobrien } 45399461Sobrien 45499461Sobrien return 1; 45599461Sobrien} 45699461Sobrien 45799461Sobrienvoid 45899461Sobrienmd_show_usage (stream) 45999461Sobrien FILE *stream; 46099461Sobrien{ 46199461Sobrien fprintf (stream, _("\ 46299461Sobrien S390 options:\n\ 46399461Sobrien -mregnames Allow symbolic names for registers\n\ 46499461Sobrien -mwarn-areg-zero Warn about zero base/index registers\n\ 46599461Sobrien -mno-regnames Do not allow symbolic names for registers\n\ 46699461Sobrien -m31 Set file format to 31 bit format\n\ 46799461Sobrien -m64 Set file format to 64 bit format\n")); 46899461Sobrien fprintf (stream, _("\ 46999461Sobrien -V print assembler version number\n\ 47099461Sobrien -Qy, -Qn ignored\n")); 47199461Sobrien} 47299461Sobrien 47399461Sobrien/* This function is called when the assembler starts up. It is called 47499461Sobrien after the options have been parsed and the output file has been 47599461Sobrien opened. */ 47699461Sobrien 47799461Sobrienvoid 47899461Sobrienmd_begin () 47999461Sobrien{ 48099461Sobrien register const struct s390_opcode *op; 48199461Sobrien const struct s390_opcode *op_end; 482130561Sobrien bfd_boolean dup_insn = FALSE; 48399461Sobrien const char *retval; 48499461Sobrien 48599461Sobrien /* Give a warning if the combination -m64-bit and -Aesa is used. */ 486130561Sobrien if (s390_arch_size == 64 && current_cpu < S390_OPCODE_Z900) 48799461Sobrien as_warn ("The 64 bit file format is used without esame instructions."); 48899461Sobrien 489130561Sobrien s390_cie_data_alignment = -s390_arch_size / 8; 490130561Sobrien 49199461Sobrien /* Set the ELF flags if desired. */ 49299461Sobrien if (s390_flags) 49399461Sobrien bfd_set_private_flags (stdoutput, s390_flags); 49499461Sobrien 49599461Sobrien /* Insert the opcode formats into a hash table. */ 49699461Sobrien s390_opformat_hash = hash_new (); 49799461Sobrien 49899461Sobrien op_end = s390_opformats + s390_num_opformats; 49999461Sobrien for (op = s390_opformats; op < op_end; op++) 50099461Sobrien { 50199461Sobrien retval = hash_insert (s390_opformat_hash, op->name, (PTR) op); 50299461Sobrien if (retval != (const char *) NULL) 50399461Sobrien { 50499461Sobrien as_bad (_("Internal assembler error for instruction format %s"), 50599461Sobrien op->name); 506130561Sobrien dup_insn = TRUE; 50799461Sobrien } 50899461Sobrien } 50999461Sobrien 51099461Sobrien /* Insert the opcodes into a hash table. */ 51199461Sobrien s390_opcode_hash = hash_new (); 51299461Sobrien 51399461Sobrien op_end = s390_opcodes + s390_num_opcodes; 51499461Sobrien for (op = s390_opcodes; op < op_end; op++) 515130561Sobrien if (op->min_cpu <= current_cpu) 516130561Sobrien { 517130561Sobrien retval = hash_insert (s390_opcode_hash, op->name, (PTR) op); 518130561Sobrien if (retval != (const char *) NULL) 519130561Sobrien { 520130561Sobrien as_bad (_("Internal assembler error for instruction %s"), 521130561Sobrien op->name); 522130561Sobrien dup_insn = TRUE; 523130561Sobrien } 524130561Sobrien while (op < op_end - 1 && strcmp (op->name, op[1].name) == 0) 525130561Sobrien op++; 526130561Sobrien } 52799461Sobrien 52899461Sobrien if (dup_insn) 52999461Sobrien abort (); 53099461Sobrien 53199461Sobrien record_alignment (text_section, 2); 53299461Sobrien record_alignment (data_section, 2); 53399461Sobrien record_alignment (bss_section, 2); 53499461Sobrien 53599461Sobrien} 53699461Sobrien 53799461Sobrien/* Called after all assembly has been done. */ 53899461Sobrienvoid 53999461Sobriens390_md_end () 54099461Sobrien{ 54199461Sobrien if (s390_arch_size == 64) 54299461Sobrien bfd_set_arch_mach (stdoutput, bfd_arch_s390, bfd_mach_s390_64); 54399461Sobrien else 54499461Sobrien bfd_set_arch_mach (stdoutput, bfd_arch_s390, bfd_mach_s390_31); 54599461Sobrien} 54699461Sobrien 54799461Sobrien/* Insert an operand value into an instruction. */ 54899461Sobrien 54999461Sobrienstatic void 55099461Sobriens390_insert_operand (insn, operand, val, file, line) 55199461Sobrien unsigned char *insn; 55299461Sobrien const struct s390_operand *operand; 55399461Sobrien offsetT val; 55499461Sobrien char *file; 55599461Sobrien unsigned int line; 55699461Sobrien{ 55799461Sobrien addressT uval; 55899461Sobrien int offset; 55999461Sobrien 56099461Sobrien if (operand->flags & (S390_OPERAND_SIGNED|S390_OPERAND_PCREL)) 56199461Sobrien { 56299461Sobrien offsetT min, max; 56399461Sobrien 56499461Sobrien max = ((offsetT) 1 << (operand->bits - 1)) - 1; 56599461Sobrien min = - ((offsetT) 1 << (operand->bits - 1)); 56699461Sobrien /* Halve PCREL operands. */ 56799461Sobrien if (operand->flags & S390_OPERAND_PCREL) 56899461Sobrien val >>= 1; 56999461Sobrien /* Check for underflow / overflow. */ 57099461Sobrien if (val < min || val > max) 57199461Sobrien { 57299461Sobrien const char *err = 57399461Sobrien "operand out of range (%s not between %ld and %ld)"; 57499461Sobrien char buf[100]; 57599461Sobrien 57699461Sobrien if (operand->flags & S390_OPERAND_PCREL) 57799461Sobrien { 57899461Sobrien val <<= 1; 57999461Sobrien min <<= 1; 58099461Sobrien max <<= 1; 58199461Sobrien } 58299461Sobrien sprint_value (buf, val); 58399461Sobrien if (file == (char *) NULL) 58499461Sobrien as_bad (err, buf, (int) min, (int) max); 58599461Sobrien else 58699461Sobrien as_bad_where (file, line, err, buf, (int) min, (int) max); 58799461Sobrien return; 58899461Sobrien } 58999461Sobrien /* val is ok, now restrict it to operand->bits bits. */ 59099461Sobrien uval = (addressT) val & ((((addressT) 1 << (operand->bits-1)) << 1) - 1); 591130561Sobrien /* val is restrict, now check for special case. */ 592130561Sobrien if (operand->bits == 20 && operand->shift == 20) 593130561Sobrien uval = (uval >> 12) | ((uval & 0xfff) << 8); 59499461Sobrien } 59599461Sobrien else 59699461Sobrien { 59799461Sobrien addressT min, max; 59899461Sobrien 599107492Sobrien max = (((addressT) 1 << (operand->bits - 1)) << 1) - 1; 60099461Sobrien min = (offsetT) 0; 60199461Sobrien uval = (addressT) val; 60299461Sobrien /* Length x in an instructions has real length x+1. */ 60399461Sobrien if (operand->flags & S390_OPERAND_LENGTH) 60499461Sobrien uval--; 60599461Sobrien /* Check for underflow / overflow. */ 60699461Sobrien if (uval < min || uval > max) 60799461Sobrien { 60899461Sobrien if (operand->flags & S390_OPERAND_LENGTH) 60999461Sobrien { 61099461Sobrien uval++; 61199461Sobrien min++; 61299461Sobrien max++; 61399461Sobrien } 614218822Sdim 615218822Sdim as_bad_value_out_of_range (_("operand"), uval, (offsetT) min, (offsetT) max, file, line); 616218822Sdim 61799461Sobrien return; 61899461Sobrien } 61999461Sobrien } 62099461Sobrien 62199461Sobrien /* Insert fragments of the operand byte for byte. */ 62299461Sobrien offset = operand->shift + operand->bits; 62399461Sobrien uval <<= (-offset) & 7; 624107492Sobrien insn += (offset - 1) / 8; 62599461Sobrien while (uval != 0) 62699461Sobrien { 62799461Sobrien *insn-- |= uval; 62899461Sobrien uval >>= 8; 62999461Sobrien } 63099461Sobrien} 63199461Sobrien 632130561Sobrienstruct map_tls 633130561Sobrien { 634130561Sobrien char *string; 635130561Sobrien int length; 636130561Sobrien bfd_reloc_code_real_type reloc; 637130561Sobrien }; 638130561Sobrien 639130561Sobrienstatic bfd_reloc_code_real_type s390_tls_suffix 640130561Sobrien PARAMS ((char **, expressionS *)); 641130561Sobrien 642130561Sobrien/* Parse tls marker and return the desired relocation. */ 643130561Sobrienstatic bfd_reloc_code_real_type 644130561Sobriens390_tls_suffix (str_p, exp_p) 645130561Sobrien char **str_p; 646130561Sobrien expressionS *exp_p; 647130561Sobrien{ 648130561Sobrien static struct map_tls mapping[] = 649130561Sobrien { 650130561Sobrien { "tls_load", 8, BFD_RELOC_390_TLS_LOAD }, 651130561Sobrien { "tls_gdcall", 10, BFD_RELOC_390_TLS_GDCALL }, 652130561Sobrien { "tls_ldcall", 10, BFD_RELOC_390_TLS_LDCALL }, 653130561Sobrien { NULL, 0, BFD_RELOC_UNUSED } 654130561Sobrien }; 655130561Sobrien struct map_tls *ptr; 656130561Sobrien char *orig_line; 657130561Sobrien char *str; 658130561Sobrien char *ident; 659130561Sobrien int len; 660130561Sobrien 661130561Sobrien str = *str_p; 662130561Sobrien if (*str++ != ':') 663130561Sobrien return BFD_RELOC_UNUSED; 664130561Sobrien 665130561Sobrien ident = str; 666130561Sobrien while (ISIDNUM (*str)) 667130561Sobrien str++; 668130561Sobrien len = str - ident; 669130561Sobrien if (*str++ != ':') 670130561Sobrien return BFD_RELOC_UNUSED; 671130561Sobrien 672130561Sobrien orig_line = input_line_pointer; 673130561Sobrien input_line_pointer = str; 674130561Sobrien expression (exp_p); 675130561Sobrien str = input_line_pointer; 676130561Sobrien if (&input_line_pointer != str_p) 677130561Sobrien input_line_pointer = orig_line; 678130561Sobrien 679130561Sobrien if (exp_p->X_op != O_symbol) 680130561Sobrien return BFD_RELOC_UNUSED; 681130561Sobrien 682130561Sobrien for (ptr = &mapping[0]; ptr->length > 0; ptr++) 683130561Sobrien if (len == ptr->length 684130561Sobrien && strncasecmp (ident, ptr->string, ptr->length) == 0) 685130561Sobrien { 686130561Sobrien /* Found a matching tls suffix. */ 687130561Sobrien *str_p = str; 688130561Sobrien return ptr->reloc; 689130561Sobrien } 690130561Sobrien return BFD_RELOC_UNUSED; 691130561Sobrien} 692130561Sobrien 69399461Sobrien/* Structure used to hold suffixes. */ 69499461Sobrientypedef enum 69599461Sobrien { 69699461Sobrien ELF_SUFFIX_NONE = 0, 69799461Sobrien ELF_SUFFIX_GOT, 69899461Sobrien ELF_SUFFIX_PLT, 699130561Sobrien ELF_SUFFIX_GOTENT, 700130561Sobrien ELF_SUFFIX_GOTOFF, 701130561Sobrien ELF_SUFFIX_GOTPLT, 702130561Sobrien ELF_SUFFIX_PLTOFF, 703130561Sobrien ELF_SUFFIX_TLS_GD, 704130561Sobrien ELF_SUFFIX_TLS_GOTIE, 705130561Sobrien ELF_SUFFIX_TLS_IE, 706130561Sobrien ELF_SUFFIX_TLS_LDM, 707130561Sobrien ELF_SUFFIX_TLS_LDO, 708130561Sobrien ELF_SUFFIX_TLS_LE 70999461Sobrien } 71099461Sobrienelf_suffix_type; 71199461Sobrien 71299461Sobrienstruct map_bfd 71399461Sobrien { 71499461Sobrien char *string; 71599461Sobrien int length; 71699461Sobrien elf_suffix_type suffix; 71799461Sobrien }; 71899461Sobrien 71999461Sobrienstatic elf_suffix_type s390_elf_suffix PARAMS ((char **, expressionS *)); 72099461Sobrienstatic int s390_exp_compare PARAMS ((expressionS *exp1, expressionS *exp2)); 72199461Sobrienstatic elf_suffix_type s390_lit_suffix 72299461Sobrien PARAMS ((char **, expressionS *, elf_suffix_type)); 72399461Sobrien 72499461Sobrien 72599461Sobrien/* Parse @got/@plt/@gotoff. and return the desired relocation. */ 72699461Sobrienstatic elf_suffix_type 72799461Sobriens390_elf_suffix (str_p, exp_p) 72899461Sobrien char **str_p; 72999461Sobrien expressionS *exp_p; 73099461Sobrien{ 73199461Sobrien static struct map_bfd mapping[] = 73299461Sobrien { 73399461Sobrien { "got", 3, ELF_SUFFIX_GOT }, 73499461Sobrien { "got12", 5, ELF_SUFFIX_GOT }, 73599461Sobrien { "plt", 3, ELF_SUFFIX_PLT }, 73699461Sobrien { "gotent", 6, ELF_SUFFIX_GOTENT }, 737130561Sobrien { "gotoff", 6, ELF_SUFFIX_GOTOFF }, 738130561Sobrien { "gotplt", 6, ELF_SUFFIX_GOTPLT }, 739130561Sobrien { "pltoff", 6, ELF_SUFFIX_PLTOFF }, 740130561Sobrien { "tlsgd", 5, ELF_SUFFIX_TLS_GD }, 741130561Sobrien { "gotntpoff", 9, ELF_SUFFIX_TLS_GOTIE }, 742130561Sobrien { "indntpoff", 9, ELF_SUFFIX_TLS_IE }, 743130561Sobrien { "tlsldm", 6, ELF_SUFFIX_TLS_LDM }, 744130561Sobrien { "dtpoff", 6, ELF_SUFFIX_TLS_LDO }, 745130561Sobrien { "ntpoff", 6, ELF_SUFFIX_TLS_LE }, 74699461Sobrien { NULL, 0, ELF_SUFFIX_NONE } 74799461Sobrien }; 74899461Sobrien 74999461Sobrien struct map_bfd *ptr; 75099461Sobrien char *str = *str_p; 75199461Sobrien char *ident; 75299461Sobrien int len; 75399461Sobrien 75499461Sobrien if (*str++ != '@') 75599461Sobrien return ELF_SUFFIX_NONE; 75699461Sobrien 75799461Sobrien ident = str; 75899461Sobrien while (ISALNUM (*str)) 75999461Sobrien str++; 76099461Sobrien len = str - ident; 76199461Sobrien 76299461Sobrien for (ptr = &mapping[0]; ptr->length > 0; ptr++) 76399461Sobrien if (len == ptr->length 76499461Sobrien && strncasecmp (ident, ptr->string, ptr->length) == 0) 76599461Sobrien { 76699461Sobrien if (exp_p->X_add_number != 0) 76799461Sobrien as_warn (_("identifier+constant@%s means identifier@%s+constant"), 76899461Sobrien ptr->string, ptr->string); 76999461Sobrien /* Now check for identifier@suffix+constant. */ 77099461Sobrien if (*str == '-' || *str == '+') 77199461Sobrien { 77299461Sobrien char *orig_line = input_line_pointer; 77399461Sobrien expressionS new_exp; 77499461Sobrien 77599461Sobrien input_line_pointer = str; 77699461Sobrien expression (&new_exp); 77799461Sobrien 77899461Sobrien switch (new_exp.X_op) 77999461Sobrien { 78099461Sobrien case O_constant: /* X_add_number (a constant expression). */ 78199461Sobrien exp_p->X_add_number += new_exp.X_add_number; 78299461Sobrien str = input_line_pointer; 78399461Sobrien break; 78499461Sobrien case O_symbol: /* X_add_symbol + X_add_number. */ 78599461Sobrien /* this case is used for e.g. xyz@PLT+.Label. */ 78699461Sobrien exp_p->X_add_number += new_exp.X_add_number; 78799461Sobrien exp_p->X_op_symbol = new_exp.X_add_symbol; 78899461Sobrien exp_p->X_op = O_add; 78999461Sobrien str = input_line_pointer; 79099461Sobrien break; 79199461Sobrien case O_uminus: /* (- X_add_symbol) + X_add_number. */ 79299461Sobrien /* this case is used for e.g. xyz@PLT-.Label. */ 79399461Sobrien exp_p->X_add_number += new_exp.X_add_number; 79499461Sobrien exp_p->X_op_symbol = new_exp.X_add_symbol; 79599461Sobrien exp_p->X_op = O_subtract; 79699461Sobrien str = input_line_pointer; 79799461Sobrien break; 79899461Sobrien default: 79999461Sobrien break; 80099461Sobrien } 80199461Sobrien 80299461Sobrien /* If s390_elf_suffix has not been called with 80399461Sobrien &input_line_pointer as first parameter, we have 80499461Sobrien clobbered the input_line_pointer. We have to 80599461Sobrien undo that. */ 80699461Sobrien if (&input_line_pointer != str_p) 80799461Sobrien input_line_pointer = orig_line; 80899461Sobrien } 80999461Sobrien *str_p = str; 81099461Sobrien return ptr->suffix; 81199461Sobrien } 81299461Sobrien 81399461Sobrien return BFD_RELOC_UNUSED; 81499461Sobrien} 81599461Sobrien 81699461Sobrien/* Structure used to hold a literal pool entry. */ 81799461Sobrienstruct s390_lpe 81899461Sobrien { 81999461Sobrien struct s390_lpe *next; 82099461Sobrien expressionS ex; 82199461Sobrien FLONUM_TYPE floatnum; /* used if X_op == O_big && X_add_number <= 0 */ 82299461Sobrien LITTLENUM_TYPE bignum[4]; /* used if X_op == O_big && X_add_number > 0 */ 82399461Sobrien int nbytes; 82499461Sobrien bfd_reloc_code_real_type reloc; 82599461Sobrien symbolS *sym; 82699461Sobrien }; 82799461Sobrien 82899461Sobrienstatic struct s390_lpe *lpe_free_list = NULL; 82999461Sobrienstatic struct s390_lpe *lpe_list = NULL; 83099461Sobrienstatic struct s390_lpe *lpe_list_tail = NULL; 83199461Sobrienstatic symbolS *lp_sym = NULL; 83299461Sobrienstatic int lp_count = 0; 83399461Sobrienstatic int lpe_count = 0; 83499461Sobrien 83599461Sobrienstatic int 836107492Sobriens390_exp_compare (exp1, exp2) 83799461Sobrien expressionS *exp1; 83899461Sobrien expressionS *exp2; 83999461Sobrien{ 84099461Sobrien if (exp1->X_op != exp2->X_op) 84199461Sobrien return 0; 84299461Sobrien 84399461Sobrien switch (exp1->X_op) 84499461Sobrien { 84599461Sobrien case O_constant: /* X_add_number must be equal. */ 84699461Sobrien case O_register: 84799461Sobrien return exp1->X_add_number == exp2->X_add_number; 84899461Sobrien 84999461Sobrien case O_big: 85099461Sobrien as_bad (_("Can't handle O_big in s390_exp_compare")); 85199461Sobrien 85299461Sobrien case O_symbol: /* X_add_symbol & X_add_number must be equal. */ 85399461Sobrien case O_symbol_rva: 85499461Sobrien case O_uminus: 85599461Sobrien case O_bit_not: 85699461Sobrien case O_logical_not: 85799461Sobrien return (exp1->X_add_symbol == exp2->X_add_symbol) 85899461Sobrien && (exp1->X_add_number == exp2->X_add_number); 85999461Sobrien 86099461Sobrien case O_multiply: /* X_add_symbol,X_op_symbol&X_add_number must be equal. */ 86199461Sobrien case O_divide: 86299461Sobrien case O_modulus: 86399461Sobrien case O_left_shift: 86499461Sobrien case O_right_shift: 86599461Sobrien case O_bit_inclusive_or: 86699461Sobrien case O_bit_or_not: 86799461Sobrien case O_bit_exclusive_or: 86899461Sobrien case O_bit_and: 86999461Sobrien case O_add: 87099461Sobrien case O_subtract: 87199461Sobrien case O_eq: 87299461Sobrien case O_ne: 87399461Sobrien case O_lt: 87499461Sobrien case O_le: 87599461Sobrien case O_ge: 87699461Sobrien case O_gt: 87799461Sobrien case O_logical_and: 87899461Sobrien case O_logical_or: 87999461Sobrien return (exp1->X_add_symbol == exp2->X_add_symbol) 88099461Sobrien && (exp1->X_op_symbol == exp2->X_op_symbol) 88199461Sobrien && (exp1->X_add_number == exp2->X_add_number); 88299461Sobrien default: 883107492Sobrien return 0; 884107492Sobrien } 88599461Sobrien} 88699461Sobrien 88799461Sobrien/* Test for @lit and if its present make an entry in the literal pool and 88899461Sobrien modify the current expression to be an offset into the literal pool. */ 88999461Sobrienstatic elf_suffix_type 89099461Sobriens390_lit_suffix (str_p, exp_p, suffix) 89199461Sobrien char **str_p; 89299461Sobrien expressionS *exp_p; 89399461Sobrien elf_suffix_type suffix; 89499461Sobrien{ 89599461Sobrien bfd_reloc_code_real_type reloc; 89699461Sobrien char tmp_name[64]; 89799461Sobrien char *str = *str_p; 89899461Sobrien char *ident; 89999461Sobrien struct s390_lpe *lpe; 90099461Sobrien int nbytes, len; 90199461Sobrien 90299461Sobrien if (*str++ != ':') 90399461Sobrien return suffix; /* No modification. */ 90499461Sobrien 90599461Sobrien /* We look for a suffix of the form "@lit1", "@lit2", "@lit4" or "@lit8". */ 90699461Sobrien ident = str; 90799461Sobrien while (ISALNUM (*str)) 90899461Sobrien str++; 90999461Sobrien len = str - ident; 91099461Sobrien if (len != 4 || strncasecmp (ident, "lit", 3) != 0 91199461Sobrien || (ident[3]!='1' && ident[3]!='2' && ident[3]!='4' && ident[3]!='8')) 91299461Sobrien return suffix; /* no modification */ 91399461Sobrien nbytes = ident[3] - '0'; 91499461Sobrien 91599461Sobrien reloc = BFD_RELOC_UNUSED; 91699461Sobrien if (suffix == ELF_SUFFIX_GOT) 91799461Sobrien { 91899461Sobrien if (nbytes == 2) 91999461Sobrien reloc = BFD_RELOC_390_GOT16; 92099461Sobrien else if (nbytes == 4) 92199461Sobrien reloc = BFD_RELOC_32_GOT_PCREL; 92299461Sobrien else if (nbytes == 8) 92399461Sobrien reloc = BFD_RELOC_390_GOT64; 92499461Sobrien } 92599461Sobrien else if (suffix == ELF_SUFFIX_PLT) 92699461Sobrien { 92799461Sobrien if (nbytes == 4) 92899461Sobrien reloc = BFD_RELOC_390_PLT32; 92999461Sobrien else if (nbytes == 8) 93099461Sobrien reloc = BFD_RELOC_390_PLT64; 93199461Sobrien } 93299461Sobrien 93399461Sobrien if (suffix != ELF_SUFFIX_NONE && reloc == BFD_RELOC_UNUSED) 93499461Sobrien as_bad (_("Invalid suffix for literal pool entry")); 93599461Sobrien 93699461Sobrien /* Search the pool if the new entry is a duplicate. */ 93799461Sobrien if (exp_p->X_op == O_big) 93899461Sobrien { 93999461Sobrien /* Special processing for big numbers. */ 94099461Sobrien for (lpe = lpe_list; lpe != NULL; lpe = lpe->next) 94199461Sobrien { 94299461Sobrien if (lpe->ex.X_op == O_big) 94399461Sobrien { 94499461Sobrien if (exp_p->X_add_number <= 0 && lpe->ex.X_add_number <= 0) 94599461Sobrien { 94699461Sobrien if (memcmp (&generic_floating_point_number, &lpe->floatnum, 94799461Sobrien sizeof (FLONUM_TYPE)) == 0) 94899461Sobrien break; 94999461Sobrien } 95099461Sobrien else if (exp_p->X_add_number == lpe->ex.X_add_number) 95199461Sobrien { 95299461Sobrien if (memcmp (generic_bignum, lpe->bignum, 95399461Sobrien sizeof (LITTLENUM_TYPE)*exp_p->X_add_number) == 0) 95499461Sobrien break; 95599461Sobrien } 95699461Sobrien } 95799461Sobrien } 95899461Sobrien } 95999461Sobrien else 96099461Sobrien { 96199461Sobrien /* Processing for 'normal' data types. */ 96299461Sobrien for (lpe = lpe_list; lpe != NULL; lpe = lpe->next) 96399461Sobrien if (lpe->nbytes == nbytes && lpe->reloc == reloc 964107492Sobrien && s390_exp_compare (exp_p, &lpe->ex) != 0) 96599461Sobrien break; 96699461Sobrien } 96799461Sobrien 96899461Sobrien if (lpe == NULL) 96999461Sobrien { 97099461Sobrien /* A new literal. */ 97199461Sobrien if (lpe_free_list != NULL) 97299461Sobrien { 97399461Sobrien lpe = lpe_free_list; 97499461Sobrien lpe_free_list = lpe_free_list->next; 97599461Sobrien } 97699461Sobrien else 97799461Sobrien { 978107492Sobrien lpe = (struct s390_lpe *) xmalloc (sizeof (struct s390_lpe)); 97999461Sobrien } 98099461Sobrien 98199461Sobrien lpe->ex = *exp_p; 98299461Sobrien 98399461Sobrien if (exp_p->X_op == O_big) 98499461Sobrien { 98599461Sobrien if (exp_p->X_add_number <= 0) 98699461Sobrien lpe->floatnum = generic_floating_point_number; 98799461Sobrien else if (exp_p->X_add_number <= 4) 98899461Sobrien memcpy (lpe->bignum, generic_bignum, 989107492Sobrien exp_p->X_add_number * sizeof (LITTLENUM_TYPE)); 99099461Sobrien else 99199461Sobrien as_bad (_("Big number is too big")); 99299461Sobrien } 99399461Sobrien 99499461Sobrien lpe->nbytes = nbytes; 99599461Sobrien lpe->reloc = reloc; 99699461Sobrien /* Literal pool name defined ? */ 99799461Sobrien if (lp_sym == NULL) 99899461Sobrien { 99999461Sobrien sprintf (tmp_name, ".L\001%i", lp_count); 1000107492Sobrien lp_sym = symbol_make (tmp_name); 100199461Sobrien } 100299461Sobrien 100399461Sobrien /* Make name for literal pool entry. */ 100499461Sobrien sprintf (tmp_name, ".L\001%i\002%i", lp_count, lpe_count); 100599461Sobrien lpe_count++; 1006107492Sobrien lpe->sym = symbol_make (tmp_name); 100799461Sobrien 100899461Sobrien /* Add to literal pool list. */ 100999461Sobrien lpe->next = NULL; 101099461Sobrien if (lpe_list_tail != NULL) 101199461Sobrien { 101299461Sobrien lpe_list_tail->next = lpe; 101399461Sobrien lpe_list_tail = lpe; 101499461Sobrien } 101599461Sobrien else 101699461Sobrien lpe_list = lpe_list_tail = lpe; 101799461Sobrien } 101899461Sobrien 101999461Sobrien /* Now change exp_p to the offset into the literal pool. 102099461Sobrien Thats the expression: .L^Ax^By-.L^Ax */ 102199461Sobrien exp_p->X_add_symbol = lpe->sym; 102299461Sobrien exp_p->X_op_symbol = lp_sym; 102399461Sobrien exp_p->X_op = O_subtract; 102499461Sobrien exp_p->X_add_number = 0; 102599461Sobrien 102699461Sobrien *str_p = str; 102799461Sobrien 102899461Sobrien /* We change the suffix type to ELF_SUFFIX_NONE, because 102999461Sobrien the difference of two local labels is just a number. */ 103099461Sobrien return ELF_SUFFIX_NONE; 103199461Sobrien} 103299461Sobrien 103399461Sobrien/* Like normal .long/.short/.word, except support @got, etc. 103499461Sobrien clobbers input_line_pointer, checks end-of-line. */ 103599461Sobrienstatic void 103699461Sobriens390_elf_cons (nbytes) 103799461Sobrien register int nbytes; /* 1=.byte, 2=.word, 4=.long */ 103899461Sobrien{ 103999461Sobrien expressionS exp; 104099461Sobrien elf_suffix_type suffix; 104199461Sobrien 104299461Sobrien if (is_it_end_of_statement ()) 104399461Sobrien { 104499461Sobrien demand_empty_rest_of_line (); 104599461Sobrien return; 104699461Sobrien } 104799461Sobrien 104899461Sobrien do 104999461Sobrien { 105099461Sobrien expression (&exp); 105199461Sobrien 105299461Sobrien if (exp.X_op == O_symbol 105399461Sobrien && *input_line_pointer == '@' 105499461Sobrien && (suffix = s390_elf_suffix (&input_line_pointer, &exp)) != ELF_SUFFIX_NONE) 105599461Sobrien { 105699461Sobrien bfd_reloc_code_real_type reloc; 105799461Sobrien reloc_howto_type *reloc_howto; 105899461Sobrien int size; 105999461Sobrien char *where; 106099461Sobrien 1061130561Sobrien if (nbytes == 2) 1062130561Sobrien { 1063130561Sobrien static bfd_reloc_code_real_type tab2[] = 1064130561Sobrien { 1065130561Sobrien BFD_RELOC_UNUSED, /* ELF_SUFFIX_NONE */ 1066130561Sobrien BFD_RELOC_390_GOT16, /* ELF_SUFFIX_GOT */ 1067130561Sobrien BFD_RELOC_UNUSED, /* ELF_SUFFIX_PLT */ 1068130561Sobrien BFD_RELOC_UNUSED, /* ELF_SUFFIX_GOTENT */ 1069130561Sobrien BFD_RELOC_16_GOTOFF, /* ELF_SUFFIX_GOTOFF */ 1070130561Sobrien BFD_RELOC_UNUSED, /* ELF_SUFFIX_GOTPLT */ 1071130561Sobrien BFD_RELOC_390_PLTOFF16, /* ELF_SUFFIX_PLTOFF */ 1072130561Sobrien BFD_RELOC_UNUSED, /* ELF_SUFFIX_TLS_GD */ 1073130561Sobrien BFD_RELOC_UNUSED, /* ELF_SUFFIX_TLS_GOTIE */ 1074130561Sobrien BFD_RELOC_UNUSED, /* ELF_SUFFIX_TLS_IE */ 1075130561Sobrien BFD_RELOC_UNUSED, /* ELF_SUFFIX_TLS_LDM */ 1076130561Sobrien BFD_RELOC_UNUSED, /* ELF_SUFFIX_TLS_LDO */ 1077130561Sobrien BFD_RELOC_UNUSED /* ELF_SUFFIX_TLS_LE */ 1078130561Sobrien }; 1079130561Sobrien reloc = tab2[suffix]; 1080130561Sobrien } 1081130561Sobrien else if (nbytes == 4) 1082130561Sobrien { 1083130561Sobrien static bfd_reloc_code_real_type tab4[] = 1084130561Sobrien { 1085130561Sobrien BFD_RELOC_UNUSED, /* ELF_SUFFIX_NONE */ 1086130561Sobrien BFD_RELOC_32_GOT_PCREL, /* ELF_SUFFIX_GOT */ 1087130561Sobrien BFD_RELOC_390_PLT32, /* ELF_SUFFIX_PLT */ 1088130561Sobrien BFD_RELOC_UNUSED, /* ELF_SUFFIX_GOTENT */ 1089130561Sobrien BFD_RELOC_32_GOTOFF, /* ELF_SUFFIX_GOTOFF */ 1090130561Sobrien BFD_RELOC_390_GOTPLT32, /* ELF_SUFFIX_GOTPLT */ 1091130561Sobrien BFD_RELOC_390_PLTOFF32, /* ELF_SUFFIX_PLTOFF */ 1092130561Sobrien BFD_RELOC_390_TLS_GD32, /* ELF_SUFFIX_TLS_GD */ 1093130561Sobrien BFD_RELOC_390_TLS_GOTIE32, /* ELF_SUFFIX_TLS_GOTIE */ 1094130561Sobrien BFD_RELOC_390_TLS_IE32, /* ELF_SUFFIX_TLS_IE */ 1095130561Sobrien BFD_RELOC_390_TLS_LDM32, /* ELF_SUFFIX_TLS_LDM */ 1096130561Sobrien BFD_RELOC_390_TLS_LDO32, /* ELF_SUFFIX_TLS_LDO */ 1097130561Sobrien BFD_RELOC_390_TLS_LE32 /* ELF_SUFFIX_TLS_LE */ 1098130561Sobrien }; 1099130561Sobrien reloc = tab4[suffix]; 1100130561Sobrien } 1101130561Sobrien else if (nbytes == 8) 1102130561Sobrien { 1103130561Sobrien static bfd_reloc_code_real_type tab8[] = 1104130561Sobrien { 1105130561Sobrien BFD_RELOC_UNUSED, /* ELF_SUFFIX_NONE */ 1106130561Sobrien BFD_RELOC_390_GOT64, /* ELF_SUFFIX_GOT */ 1107130561Sobrien BFD_RELOC_390_PLT64, /* ELF_SUFFIX_PLT */ 1108130561Sobrien BFD_RELOC_UNUSED, /* ELF_SUFFIX_GOTENT */ 1109130561Sobrien BFD_RELOC_390_GOTOFF64, /* ELF_SUFFIX_GOTOFF */ 1110130561Sobrien BFD_RELOC_390_GOTPLT64, /* ELF_SUFFIX_GOTPLT */ 1111130561Sobrien BFD_RELOC_390_PLTOFF64, /* ELF_SUFFIX_PLTOFF */ 1112130561Sobrien BFD_RELOC_390_TLS_GD64, /* ELF_SUFFIX_TLS_GD */ 1113130561Sobrien BFD_RELOC_390_TLS_GOTIE64, /* ELF_SUFFIX_TLS_GOTIE */ 1114130561Sobrien BFD_RELOC_390_TLS_IE64, /* ELF_SUFFIX_TLS_IE */ 1115130561Sobrien BFD_RELOC_390_TLS_LDM64, /* ELF_SUFFIX_TLS_LDM */ 1116130561Sobrien BFD_RELOC_390_TLS_LDO64, /* ELF_SUFFIX_TLS_LDO */ 1117130561Sobrien BFD_RELOC_390_TLS_LE64 /* ELF_SUFFIX_TLS_LE */ 1118130561Sobrien }; 1119130561Sobrien reloc = tab8[suffix]; 1120130561Sobrien } 112199461Sobrien else 112299461Sobrien reloc = BFD_RELOC_UNUSED; 112399461Sobrien 1124130561Sobrien if (reloc != BFD_RELOC_UNUSED 1125130561Sobrien && (reloc_howto = bfd_reloc_type_lookup (stdoutput, reloc))) 112699461Sobrien { 112799461Sobrien size = bfd_get_reloc_size (reloc_howto); 112899461Sobrien if (size > nbytes) 112999461Sobrien as_bad (_("%s relocations do not fit in %d bytes"), 113099461Sobrien reloc_howto->name, nbytes); 113199461Sobrien where = frag_more (nbytes); 113299461Sobrien md_number_to_chars (where, 0, size); 113399461Sobrien /* To make fixup_segment do the pc relative conversion the 1134130561Sobrien pcrel parameter on the fix_new_exp call needs to be FALSE. */ 113599461Sobrien fix_new_exp (frag_now, where - frag_now->fr_literal, 1136130561Sobrien size, &exp, FALSE, reloc); 113799461Sobrien } 113899461Sobrien else 113999461Sobrien as_bad (_("relocation not applicable")); 114099461Sobrien } 114199461Sobrien else 114299461Sobrien emit_expr (&exp, (unsigned int) nbytes); 114399461Sobrien } 114499461Sobrien while (*input_line_pointer++ == ','); 114599461Sobrien 1146107492Sobrien input_line_pointer--; /* Put terminator back into stream. */ 114799461Sobrien demand_empty_rest_of_line (); 114899461Sobrien} 114999461Sobrien 115099461Sobrien/* We need to keep a list of fixups. We can't simply generate them as 115199461Sobrien we go, because that would require us to first create the frag, and 115299461Sobrien that would screw up references to ``.''. */ 115399461Sobrien 115499461Sobrienstruct s390_fixup 115599461Sobrien { 115699461Sobrien expressionS exp; 115799461Sobrien int opindex; 115899461Sobrien bfd_reloc_code_real_type reloc; 115999461Sobrien }; 116099461Sobrien 116199461Sobrien#define MAX_INSN_FIXUPS (4) 116299461Sobrien 116399461Sobrien/* This routine is called for each instruction to be assembled. */ 116499461Sobrien 116599461Sobrienstatic char * 116699461Sobrienmd_gather_operands (str, insn, opcode) 116799461Sobrien char *str; 116899461Sobrien unsigned char *insn; 116999461Sobrien const struct s390_opcode *opcode; 117099461Sobrien{ 117199461Sobrien struct s390_fixup fixups[MAX_INSN_FIXUPS]; 117299461Sobrien const struct s390_operand *operand; 117399461Sobrien const unsigned char *opindex_ptr; 1174130561Sobrien expressionS ex; 117599461Sobrien elf_suffix_type suffix; 117699461Sobrien bfd_reloc_code_real_type reloc; 117799461Sobrien int skip_optional; 117899461Sobrien int parentheses; 117999461Sobrien char *f; 118099461Sobrien int fc, i; 118199461Sobrien 1182107492Sobrien while (ISSPACE (*str)) 1183107492Sobrien str++; 118499461Sobrien 118599461Sobrien parentheses = 0; 118699461Sobrien skip_optional = 0; 118799461Sobrien 118899461Sobrien /* Gather the operands. */ 118999461Sobrien fc = 0; 119099461Sobrien for (opindex_ptr = opcode->operands; *opindex_ptr != 0; opindex_ptr++) 119199461Sobrien { 119299461Sobrien char *hold; 119399461Sobrien 119499461Sobrien operand = s390_operands + *opindex_ptr; 119599461Sobrien 119699461Sobrien if (skip_optional && (operand->flags & S390_OPERAND_INDEX)) 119799461Sobrien { 119899461Sobrien /* We do an early skip. For D(X,B) constructions the index 119999461Sobrien register is skipped (X is optional). For D(L,B) the base 120099461Sobrien register will be the skipped operand, because L is NOT 120199461Sobrien optional. */ 120299461Sobrien skip_optional = 0; 120399461Sobrien continue; 120499461Sobrien } 120599461Sobrien 120699461Sobrien /* Gather the operand. */ 120799461Sobrien hold = input_line_pointer; 120899461Sobrien input_line_pointer = str; 120999461Sobrien 1210107492Sobrien /* Parse the operand. */ 1211107492Sobrien if (! register_name (&ex)) 121299461Sobrien expression (&ex); 121399461Sobrien 121499461Sobrien str = input_line_pointer; 121599461Sobrien input_line_pointer = hold; 121699461Sobrien 121799461Sobrien /* Write the operand to the insn. */ 121899461Sobrien if (ex.X_op == O_illegal) 121999461Sobrien as_bad (_("illegal operand")); 122099461Sobrien else if (ex.X_op == O_absent) 122199461Sobrien as_bad (_("missing operand")); 122299461Sobrien else if (ex.X_op == O_register || ex.X_op == O_constant) 122399461Sobrien { 122499461Sobrien s390_lit_suffix (&str, &ex, ELF_SUFFIX_NONE); 122599461Sobrien 122699461Sobrien if (ex.X_op != O_register && ex.X_op != O_constant) 122799461Sobrien { 122899461Sobrien /* We need to generate a fixup for the 122999461Sobrien expression returned by s390_lit_suffix. */ 123099461Sobrien if (fc >= MAX_INSN_FIXUPS) 123199461Sobrien as_fatal (_("too many fixups")); 123299461Sobrien fixups[fc].exp = ex; 123399461Sobrien fixups[fc].opindex = *opindex_ptr; 123499461Sobrien fixups[fc].reloc = BFD_RELOC_UNUSED; 123599461Sobrien ++fc; 123699461Sobrien } 123799461Sobrien else 123899461Sobrien { 123999461Sobrien if ((operand->flags & S390_OPERAND_INDEX) 124099461Sobrien && ex.X_add_number == 0 1241130561Sobrien && warn_areg_zero) 124299461Sobrien as_warn ("index register specified but zero"); 124399461Sobrien if ((operand->flags & S390_OPERAND_BASE) 124499461Sobrien && ex.X_add_number == 0 1245130561Sobrien && warn_areg_zero) 124699461Sobrien as_warn ("base register specified but zero"); 124799461Sobrien s390_insert_operand (insn, operand, ex.X_add_number, NULL, 0); 124899461Sobrien } 124999461Sobrien } 125099461Sobrien else 125199461Sobrien { 125299461Sobrien suffix = s390_elf_suffix (&str, &ex); 125399461Sobrien suffix = s390_lit_suffix (&str, &ex, suffix); 125499461Sobrien reloc = BFD_RELOC_UNUSED; 125599461Sobrien 125699461Sobrien if (suffix == ELF_SUFFIX_GOT) 125799461Sobrien { 1258130561Sobrien if ((operand->flags & S390_OPERAND_DISP) && 1259130561Sobrien (operand->bits == 12)) 126099461Sobrien reloc = BFD_RELOC_390_GOT12; 1261130561Sobrien else if ((operand->flags & S390_OPERAND_DISP) && 1262130561Sobrien (operand->bits == 20)) 1263130561Sobrien reloc = BFD_RELOC_390_GOT20; 126499461Sobrien else if ((operand->flags & S390_OPERAND_SIGNED) 126599461Sobrien && (operand->bits == 16)) 126699461Sobrien reloc = BFD_RELOC_390_GOT16; 126799461Sobrien else if ((operand->flags & S390_OPERAND_PCREL) 126899461Sobrien && (operand->bits == 32)) 126999461Sobrien reloc = BFD_RELOC_390_GOTENT; 127099461Sobrien } 127199461Sobrien else if (suffix == ELF_SUFFIX_PLT) 127299461Sobrien { 127399461Sobrien if ((operand->flags & S390_OPERAND_PCREL) 127499461Sobrien && (operand->bits == 16)) 127599461Sobrien reloc = BFD_RELOC_390_PLT16DBL; 127699461Sobrien else if ((operand->flags & S390_OPERAND_PCREL) 127799461Sobrien && (operand->bits == 32)) 127899461Sobrien reloc = BFD_RELOC_390_PLT32DBL; 127999461Sobrien } 128099461Sobrien else if (suffix == ELF_SUFFIX_GOTENT) 128199461Sobrien { 128299461Sobrien if ((operand->flags & S390_OPERAND_PCREL) 128399461Sobrien && (operand->bits == 32)) 128499461Sobrien reloc = BFD_RELOC_390_GOTENT; 128599461Sobrien } 1286130561Sobrien else if (suffix == ELF_SUFFIX_GOTOFF) 1287130561Sobrien { 1288130561Sobrien if ((operand->flags & S390_OPERAND_SIGNED) 1289130561Sobrien && (operand->bits == 16)) 1290130561Sobrien reloc = BFD_RELOC_16_GOTOFF; 1291130561Sobrien } 1292130561Sobrien else if (suffix == ELF_SUFFIX_PLTOFF) 1293130561Sobrien { 1294130561Sobrien if ((operand->flags & S390_OPERAND_SIGNED) 1295130561Sobrien && (operand->bits == 16)) 1296130561Sobrien reloc = BFD_RELOC_390_PLTOFF16; 1297130561Sobrien } 1298130561Sobrien else if (suffix == ELF_SUFFIX_GOTPLT) 1299130561Sobrien { 1300130561Sobrien if ((operand->flags & S390_OPERAND_DISP) 1301130561Sobrien && (operand->bits == 12)) 1302130561Sobrien reloc = BFD_RELOC_390_GOTPLT12; 1303130561Sobrien else if ((operand->flags & S390_OPERAND_SIGNED) 1304130561Sobrien && (operand->bits == 16)) 1305130561Sobrien reloc = BFD_RELOC_390_GOTPLT16; 1306130561Sobrien else if ((operand->flags & S390_OPERAND_PCREL) 1307130561Sobrien && (operand->bits == 32)) 1308130561Sobrien reloc = BFD_RELOC_390_GOTPLTENT; 1309130561Sobrien } 1310130561Sobrien else if (suffix == ELF_SUFFIX_TLS_GOTIE) 1311130561Sobrien { 1312130561Sobrien if ((operand->flags & S390_OPERAND_DISP) 1313130561Sobrien && (operand->bits == 12)) 1314130561Sobrien reloc = BFD_RELOC_390_TLS_GOTIE12; 1315130561Sobrien else if ((operand->flags & S390_OPERAND_DISP) 1316130561Sobrien && (operand->bits == 20)) 1317130561Sobrien reloc = BFD_RELOC_390_TLS_GOTIE20; 1318130561Sobrien } 1319130561Sobrien else if (suffix == ELF_SUFFIX_TLS_IE) 1320130561Sobrien { 1321130561Sobrien if ((operand->flags & S390_OPERAND_PCREL) 1322130561Sobrien && (operand->bits == 32)) 1323130561Sobrien reloc = BFD_RELOC_390_TLS_IEENT; 1324130561Sobrien } 132599461Sobrien 132699461Sobrien if (suffix != ELF_SUFFIX_NONE && reloc == BFD_RELOC_UNUSED) 132799461Sobrien as_bad (_("invalid operand suffix")); 132899461Sobrien /* We need to generate a fixup of type 'reloc' for this 132999461Sobrien expression. */ 133099461Sobrien if (fc >= MAX_INSN_FIXUPS) 133199461Sobrien as_fatal (_("too many fixups")); 133299461Sobrien fixups[fc].exp = ex; 133399461Sobrien fixups[fc].opindex = *opindex_ptr; 133499461Sobrien fixups[fc].reloc = reloc; 133599461Sobrien ++fc; 133699461Sobrien } 133799461Sobrien 133899461Sobrien /* Check the next character. The call to expression has advanced 133999461Sobrien str past any whitespace. */ 134099461Sobrien if (operand->flags & S390_OPERAND_DISP) 134199461Sobrien { 134299461Sobrien /* After a displacement a block in parentheses can start. */ 134399461Sobrien if (*str != '(') 134499461Sobrien { 1345130561Sobrien /* Check if parenthesized block can be skipped. If the next 134699461Sobrien operand is neiter an optional operand nor a base register 134799461Sobrien then we have a syntax error. */ 134899461Sobrien operand = s390_operands + *(++opindex_ptr); 134999461Sobrien if (!(operand->flags & (S390_OPERAND_INDEX|S390_OPERAND_BASE))) 135099461Sobrien as_bad (_("syntax error; missing '(' after displacement")); 135199461Sobrien 135299461Sobrien /* Ok, skip all operands until S390_OPERAND_BASE. */ 135399461Sobrien while (!(operand->flags & S390_OPERAND_BASE)) 135499461Sobrien operand = s390_operands + *(++opindex_ptr); 135599461Sobrien 1356130561Sobrien /* If there is a next operand it must be separated by a comma. */ 135799461Sobrien if (opindex_ptr[1] != '\0') 135899461Sobrien { 1359218822Sdim if (*str != ',') 1360218822Sdim { 1361218822Sdim while (opindex_ptr[1] != '\0') 1362218822Sdim { 1363218822Sdim operand = s390_operands + *(++opindex_ptr); 1364218822Sdim if (operand->flags & S390_OPERAND_OPTIONAL) 1365218822Sdim continue; 1366218822Sdim as_bad (_("syntax error; expected ,")); 1367218822Sdim break; 1368218822Sdim } 1369218822Sdim } 1370218822Sdim else 1371218822Sdim str++; 137299461Sobrien } 137399461Sobrien } 137499461Sobrien else 137599461Sobrien { 137699461Sobrien /* We found an opening parentheses. */ 137799461Sobrien str++; 137899461Sobrien for (f = str; *f != '\0'; f++) 137999461Sobrien if (*f == ',' || *f == ')') 138099461Sobrien break; 138199461Sobrien /* If there is no comma until the closing parentheses OR 138299461Sobrien there is a comma right after the opening parentheses, 138399461Sobrien we have to skip optional operands. */ 138499461Sobrien if (*f == ',' && f == str) 138599461Sobrien { 138699461Sobrien /* comma directly after '(' ? */ 138799461Sobrien skip_optional = 1; 138899461Sobrien str++; 138999461Sobrien } 139099461Sobrien else 139199461Sobrien skip_optional = (*f != ','); 139299461Sobrien } 139399461Sobrien } 139499461Sobrien else if (operand->flags & S390_OPERAND_BASE) 139599461Sobrien { 139699461Sobrien /* After the base register the parenthesed block ends. */ 139799461Sobrien if (*str++ != ')') 139899461Sobrien as_bad (_("syntax error; missing ')' after base register")); 139999461Sobrien skip_optional = 0; 1400130561Sobrien /* If there is a next operand it must be separated by a comma. */ 140199461Sobrien if (opindex_ptr[1] != '\0') 140299461Sobrien { 1403218822Sdim if (*str != ',') 1404218822Sdim { 1405218822Sdim while (opindex_ptr[1] != '\0') 1406218822Sdim { 1407218822Sdim operand = s390_operands + *(++opindex_ptr); 1408218822Sdim if (operand->flags & S390_OPERAND_OPTIONAL) 1409218822Sdim continue; 1410218822Sdim as_bad (_("syntax error; expected ,")); 1411218822Sdim break; 1412218822Sdim } 1413218822Sdim } 1414218822Sdim else 1415218822Sdim str++; 141699461Sobrien } 141799461Sobrien } 141899461Sobrien else 141999461Sobrien { 142099461Sobrien /* We can find an 'early' closing parentheses in e.g. D(L) instead 142199461Sobrien of D(L,B). In this case the base register has to be skipped. */ 142299461Sobrien if (*str == ')') 142399461Sobrien { 142499461Sobrien operand = s390_operands + *(++opindex_ptr); 142599461Sobrien 142699461Sobrien if (!(operand->flags & S390_OPERAND_BASE)) 142799461Sobrien as_bad (_("syntax error; ')' not allowed here")); 142899461Sobrien str++; 142999461Sobrien } 1430130561Sobrien /* If there is a next operand it must be separated by a comma. */ 143199461Sobrien if (opindex_ptr[1] != '\0') 143299461Sobrien { 1433218822Sdim if (*str != ',') 1434218822Sdim { 1435218822Sdim while (opindex_ptr[1] != '\0') 1436218822Sdim { 1437218822Sdim operand = s390_operands + *(++opindex_ptr); 1438218822Sdim if (operand->flags & S390_OPERAND_OPTIONAL) 1439218822Sdim continue; 1440218822Sdim as_bad (_("syntax error; expected ,")); 1441218822Sdim break; 1442218822Sdim } 1443218822Sdim } 1444218822Sdim else 1445218822Sdim str++; 144699461Sobrien } 144799461Sobrien } 144899461Sobrien } 144999461Sobrien 145099461Sobrien while (ISSPACE (*str)) 145199461Sobrien ++str; 145299461Sobrien 1453130561Sobrien /* Check for tls instruction marker. */ 1454130561Sobrien reloc = s390_tls_suffix (&str, &ex); 1455130561Sobrien if (reloc != BFD_RELOC_UNUSED) 1456130561Sobrien { 1457130561Sobrien /* We need to generate a fixup of type 'reloc' for this 1458130561Sobrien instruction. */ 1459130561Sobrien if (fc >= MAX_INSN_FIXUPS) 1460130561Sobrien as_fatal (_("too many fixups")); 1461130561Sobrien fixups[fc].exp = ex; 1462130561Sobrien fixups[fc].opindex = -1; 1463130561Sobrien fixups[fc].reloc = reloc; 1464130561Sobrien ++fc; 1465130561Sobrien } 1466130561Sobrien 146799461Sobrien if (*str != '\0') 146899461Sobrien { 146999461Sobrien char *linefeed; 147099461Sobrien 147199461Sobrien if ((linefeed = strchr (str, '\n')) != NULL) 147299461Sobrien *linefeed = '\0'; 147399461Sobrien as_bad (_("junk at end of line: `%s'"), str); 147499461Sobrien if (linefeed != NULL) 147599461Sobrien *linefeed = '\n'; 147699461Sobrien } 147799461Sobrien 147899461Sobrien /* Write out the instruction. */ 147999461Sobrien f = frag_more (opcode->oplen); 148099461Sobrien memcpy (f, insn, opcode->oplen); 148199461Sobrien dwarf2_emit_insn (opcode->oplen); 148299461Sobrien 148399461Sobrien /* Create any fixups. At this point we do not use a 148499461Sobrien bfd_reloc_code_real_type, but instead just use the 148599461Sobrien BFD_RELOC_UNUSED plus the operand index. This lets us easily 148699461Sobrien handle fixups for any operand type, although that is admittedly 148799461Sobrien not a very exciting feature. We pick a BFD reloc type in 1488218822Sdim md_apply_fix. */ 148999461Sobrien for (i = 0; i < fc; i++) 149099461Sobrien { 1491130561Sobrien 1492130561Sobrien if (fixups[i].opindex < 0) 1493130561Sobrien { 1494130561Sobrien /* Create tls instruction marker relocation. */ 1495130561Sobrien fix_new_exp (frag_now, f - frag_now->fr_literal, opcode->oplen, 1496130561Sobrien &fixups[i].exp, 0, fixups[i].reloc); 1497130561Sobrien continue; 1498130561Sobrien } 1499130561Sobrien 150099461Sobrien operand = s390_operands + fixups[i].opindex; 150199461Sobrien 150299461Sobrien if (fixups[i].reloc != BFD_RELOC_UNUSED) 150399461Sobrien { 150499461Sobrien reloc_howto_type *reloc_howto; 150599461Sobrien fixS *fixP; 150699461Sobrien int size; 150799461Sobrien 150899461Sobrien reloc_howto = bfd_reloc_type_lookup (stdoutput, fixups[i].reloc); 150999461Sobrien if (!reloc_howto) 151099461Sobrien abort (); 151199461Sobrien 151299461Sobrien size = bfd_get_reloc_size (reloc_howto); 151399461Sobrien 151499461Sobrien if (size < 1 || size > 4) 151599461Sobrien abort (); 151699461Sobrien 151799461Sobrien fixP = fix_new_exp (frag_now, 151899461Sobrien f - frag_now->fr_literal + (operand->shift/8), 151999461Sobrien size, &fixups[i].exp, reloc_howto->pc_relative, 152099461Sobrien fixups[i].reloc); 152199461Sobrien /* Turn off overflow checking in fixup_segment. This is necessary 152299461Sobrien because fixup_segment will signal an overflow for large 4 byte 152399461Sobrien quantities for GOT12 relocations. */ 152499461Sobrien if ( fixups[i].reloc == BFD_RELOC_390_GOT12 1525130561Sobrien || fixups[i].reloc == BFD_RELOC_390_GOT20 152699461Sobrien || fixups[i].reloc == BFD_RELOC_390_GOT16) 152799461Sobrien fixP->fx_no_overflow = 1; 152899461Sobrien } 152999461Sobrien else 153099461Sobrien fix_new_exp (frag_now, f - frag_now->fr_literal, 4, &fixups[i].exp, 153199461Sobrien (operand->flags & S390_OPERAND_PCREL) != 0, 153299461Sobrien ((bfd_reloc_code_real_type) 153399461Sobrien (fixups[i].opindex + (int) BFD_RELOC_UNUSED))); 153499461Sobrien } 153599461Sobrien return str; 153699461Sobrien} 153799461Sobrien 153899461Sobrien/* This routine is called for each instruction to be assembled. */ 153999461Sobrien 154099461Sobrienvoid 154199461Sobrienmd_assemble (str) 154299461Sobrien char *str; 154399461Sobrien{ 154499461Sobrien const struct s390_opcode *opcode; 154599461Sobrien unsigned char insn[6]; 154699461Sobrien char *s; 154799461Sobrien 154899461Sobrien /* Get the opcode. */ 154999461Sobrien for (s = str; *s != '\0' && ! ISSPACE (*s); s++) 155099461Sobrien ; 155199461Sobrien if (*s != '\0') 155299461Sobrien *s++ = '\0'; 155399461Sobrien 155499461Sobrien /* Look up the opcode in the hash table. */ 155599461Sobrien opcode = (struct s390_opcode *) hash_find (s390_opcode_hash, str); 155699461Sobrien if (opcode == (const struct s390_opcode *) NULL) 155799461Sobrien { 155899461Sobrien as_bad (_("Unrecognized opcode: `%s'"), str); 155999461Sobrien return; 156099461Sobrien } 1561130561Sobrien else if (!(opcode->modes & current_mode_mask)) 156299461Sobrien { 1563130561Sobrien as_bad ("Opcode %s not available in this mode", str); 156499461Sobrien return; 156599461Sobrien } 156699461Sobrien memcpy (insn, opcode->opcode, sizeof (insn)); 156799461Sobrien md_gather_operands (s, insn, opcode); 156899461Sobrien} 156999461Sobrien 157099461Sobrien#ifndef WORKING_DOT_WORD 157199461Sobrien/* Handle long and short jumps. We don't support these */ 157299461Sobrienvoid 157399461Sobrienmd_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol) 157499461Sobrien char *ptr; 157599461Sobrien addressT from_addr, to_addr; 157699461Sobrien fragS *frag; 157799461Sobrien symbolS *to_symbol; 157899461Sobrien{ 157999461Sobrien abort (); 158099461Sobrien} 158199461Sobrien 158299461Sobrienvoid 158399461Sobrienmd_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol) 158499461Sobrien char *ptr; 158599461Sobrien addressT from_addr, to_addr; 158699461Sobrien fragS *frag; 158799461Sobrien symbolS *to_symbol; 158899461Sobrien{ 158999461Sobrien abort (); 159099461Sobrien} 159199461Sobrien#endif 159299461Sobrien 159399461Sobrienvoid 159499461Sobriens390_bss (ignore) 159599461Sobrien int ignore ATTRIBUTE_UNUSED; 159699461Sobrien{ 159799461Sobrien /* We don't support putting frags in the BSS segment, we fake it 159899461Sobrien by marking in_bss, then looking at s_skip for clues. */ 159999461Sobrien 160099461Sobrien subseg_set (bss_section, 0); 160199461Sobrien demand_empty_rest_of_line (); 160299461Sobrien} 160399461Sobrien 160499461Sobrien/* Pseudo-op handling. */ 160599461Sobrien 160699461Sobrienvoid 160799461Sobriens390_insn (ignore) 160899461Sobrien int ignore ATTRIBUTE_UNUSED; 160999461Sobrien{ 161099461Sobrien expressionS exp; 161199461Sobrien const struct s390_opcode *opformat; 161299461Sobrien unsigned char insn[6]; 161399461Sobrien char *s; 161499461Sobrien 161599461Sobrien /* Get the opcode format. */ 161699461Sobrien s = input_line_pointer; 161799461Sobrien while (*s != '\0' && *s != ',' && ! ISSPACE (*s)) 161899461Sobrien s++; 161999461Sobrien if (*s != ',') 162099461Sobrien as_bad (_("Invalid .insn format\n")); 162199461Sobrien *s++ = '\0'; 162299461Sobrien 162399461Sobrien /* Look up the opcode in the hash table. */ 162499461Sobrien opformat = (struct s390_opcode *) 162599461Sobrien hash_find (s390_opformat_hash, input_line_pointer); 162699461Sobrien if (opformat == (const struct s390_opcode *) NULL) 162799461Sobrien { 162899461Sobrien as_bad (_("Unrecognized opcode format: `%s'"), input_line_pointer); 162999461Sobrien return; 163099461Sobrien } 163199461Sobrien input_line_pointer = s; 163299461Sobrien expression (&exp); 163399461Sobrien if (exp.X_op == O_constant) 163499461Sobrien { 1635130561Sobrien if ( ( opformat->oplen == 6 1636130561Sobrien && (addressT) exp.X_add_number < (1ULL << 48)) 1637130561Sobrien || ( opformat->oplen == 4 1638130561Sobrien && (addressT) exp.X_add_number < (1ULL << 32)) 1639130561Sobrien || ( opformat->oplen == 2 1640130561Sobrien && (addressT) exp.X_add_number < (1ULL << 16))) 1641218822Sdim md_number_to_chars ((char *) insn, exp.X_add_number, opformat->oplen); 164299461Sobrien else 164399461Sobrien as_bad (_("Invalid .insn format\n")); 164499461Sobrien } 164599461Sobrien else if (exp.X_op == O_big) 164699461Sobrien { 164799461Sobrien if (exp.X_add_number > 0 164899461Sobrien && opformat->oplen == 6 164999461Sobrien && generic_bignum[3] == 0) 165099461Sobrien { 1651218822Sdim md_number_to_chars ((char *) insn, generic_bignum[2], 2); 1652218822Sdim md_number_to_chars ((char *) &insn[2], generic_bignum[1], 2); 1653218822Sdim md_number_to_chars ((char *) &insn[4], generic_bignum[0], 2); 165499461Sobrien } 165599461Sobrien else 165699461Sobrien as_bad (_("Invalid .insn format\n")); 165799461Sobrien } 165899461Sobrien else 165999461Sobrien as_bad (_("second operand of .insn not a constant\n")); 166099461Sobrien 166199461Sobrien if (strcmp (opformat->name, "e") != 0 && *input_line_pointer++ != ',') 166299461Sobrien as_bad (_("missing comma after insn constant\n")); 1663107492Sobrien 166499461Sobrien if ((s = strchr (input_line_pointer, '\n')) != NULL) 166599461Sobrien *s = '\0'; 166699461Sobrien input_line_pointer = md_gather_operands (input_line_pointer, insn, 166799461Sobrien opformat); 166899461Sobrien if (s != NULL) 166999461Sobrien *s = '\n'; 167099461Sobrien demand_empty_rest_of_line (); 167199461Sobrien} 167299461Sobrien 167399461Sobrien/* The .byte pseudo-op. This is similar to the normal .byte 167499461Sobrien pseudo-op, but it can also take a single ASCII string. */ 167599461Sobrien 167699461Sobrienstatic void 167799461Sobriens390_byte (ignore) 167899461Sobrien int ignore ATTRIBUTE_UNUSED; 167999461Sobrien{ 168099461Sobrien if (*input_line_pointer != '\"') 168199461Sobrien { 168299461Sobrien cons (1); 168399461Sobrien return; 168499461Sobrien } 168599461Sobrien 168699461Sobrien /* Gather characters. A real double quote is doubled. Unusual 168799461Sobrien characters are not permitted. */ 168899461Sobrien ++input_line_pointer; 168999461Sobrien while (1) 169099461Sobrien { 169199461Sobrien char c; 169299461Sobrien 169399461Sobrien c = *input_line_pointer++; 169499461Sobrien 169599461Sobrien if (c == '\"') 169699461Sobrien { 169799461Sobrien if (*input_line_pointer != '\"') 169899461Sobrien break; 169999461Sobrien ++input_line_pointer; 170099461Sobrien } 170199461Sobrien 170299461Sobrien FRAG_APPEND_1_CHAR (c); 170399461Sobrien } 170499461Sobrien 170599461Sobrien demand_empty_rest_of_line (); 170699461Sobrien} 170799461Sobrien 170899461Sobrien/* The .ltorg pseudo-op.This emits all literals defined since the last 170999461Sobrien .ltorg or the invocation of gas. Literals are defined with the 171099461Sobrien @lit suffix. */ 171199461Sobrien 171299461Sobrienstatic void 171399461Sobriens390_literals (ignore) 171499461Sobrien int ignore ATTRIBUTE_UNUSED; 171599461Sobrien{ 171699461Sobrien struct s390_lpe *lpe; 171799461Sobrien 171899461Sobrien if (lp_sym == NULL || lpe_count == 0) 1719107492Sobrien return; /* Nothing to be done. */ 172099461Sobrien 172199461Sobrien /* Emit symbol for start of literal pool. */ 172299461Sobrien S_SET_SEGMENT (lp_sym, now_seg); 172399461Sobrien S_SET_VALUE (lp_sym, (valueT) frag_now_fix ()); 172499461Sobrien lp_sym->sy_frag = frag_now; 172599461Sobrien 172699461Sobrien while (lpe_list) 172799461Sobrien { 172899461Sobrien lpe = lpe_list; 172999461Sobrien lpe_list = lpe_list->next; 173099461Sobrien S_SET_SEGMENT (lpe->sym, now_seg); 173199461Sobrien S_SET_VALUE (lpe->sym, (valueT) frag_now_fix ()); 173299461Sobrien lpe->sym->sy_frag = frag_now; 173399461Sobrien 173499461Sobrien /* Emit literal pool entry. */ 173599461Sobrien if (lpe->reloc != BFD_RELOC_UNUSED) 173699461Sobrien { 173799461Sobrien reloc_howto_type *reloc_howto = 173899461Sobrien bfd_reloc_type_lookup (stdoutput, lpe->reloc); 173999461Sobrien int size = bfd_get_reloc_size (reloc_howto); 174099461Sobrien char *where; 174199461Sobrien 174299461Sobrien if (size > lpe->nbytes) 174399461Sobrien as_bad (_("%s relocations do not fit in %d bytes"), 174499461Sobrien reloc_howto->name, lpe->nbytes); 174599461Sobrien where = frag_more (lpe->nbytes); 174699461Sobrien md_number_to_chars (where, 0, size); 174799461Sobrien fix_new_exp (frag_now, where - frag_now->fr_literal, 174899461Sobrien size, &lpe->ex, reloc_howto->pc_relative, lpe->reloc); 174999461Sobrien } 175099461Sobrien else 175199461Sobrien { 175299461Sobrien if (lpe->ex.X_op == O_big) 175399461Sobrien { 175499461Sobrien if (lpe->ex.X_add_number <= 0) 175599461Sobrien generic_floating_point_number = lpe->floatnum; 175699461Sobrien else 175799461Sobrien memcpy (generic_bignum, lpe->bignum, 1758107492Sobrien lpe->ex.X_add_number * sizeof (LITTLENUM_TYPE)); 175999461Sobrien } 176099461Sobrien emit_expr (&lpe->ex, lpe->nbytes); 176199461Sobrien } 176299461Sobrien 176399461Sobrien lpe->next = lpe_free_list; 176499461Sobrien lpe_free_list = lpe; 176599461Sobrien } 176699461Sobrien lpe_list_tail = NULL; 176799461Sobrien lp_sym = NULL; 176899461Sobrien lp_count++; 176999461Sobrien lpe_count = 0; 177099461Sobrien} 177199461Sobrien 177299461Sobrien/* Turn a string in input_line_pointer into a floating point constant 177399461Sobrien of type type, and store the appropriate bytes in *litp. The number 177499461Sobrien of LITTLENUMS emitted is stored in *sizep . An error message is 177599461Sobrien returned, or NULL on OK. */ 177699461Sobrien 177799461Sobrienchar * 177899461Sobrienmd_atof (type, litp, sizep) 177999461Sobrien int type; 178099461Sobrien char *litp; 178199461Sobrien int *sizep; 178299461Sobrien{ 178399461Sobrien int prec; 178499461Sobrien LITTLENUM_TYPE words[4]; 178599461Sobrien char *t; 178699461Sobrien int i; 178799461Sobrien 178899461Sobrien switch (type) 178999461Sobrien { 179099461Sobrien case 'f': 179199461Sobrien prec = 2; 179299461Sobrien break; 179399461Sobrien 179499461Sobrien case 'd': 179599461Sobrien prec = 4; 179699461Sobrien break; 179799461Sobrien 179899461Sobrien default: 179999461Sobrien *sizep = 0; 180099461Sobrien return "bad call to md_atof"; 180199461Sobrien } 180299461Sobrien 180399461Sobrien t = atof_ieee (input_line_pointer, type, words); 180499461Sobrien if (t) 180599461Sobrien input_line_pointer = t; 180699461Sobrien 180799461Sobrien *sizep = prec * 2; 180899461Sobrien 180999461Sobrien for (i = 0; i < prec; i++) 181099461Sobrien { 181199461Sobrien md_number_to_chars (litp, (valueT) words[i], 2); 181299461Sobrien litp += 2; 181399461Sobrien } 181499461Sobrien 181599461Sobrien return NULL; 181699461Sobrien} 181799461Sobrien 181899461Sobrien/* Align a section (I don't know why this is machine dependent). */ 181999461Sobrien 182099461SobrienvalueT 182199461Sobrienmd_section_align (seg, addr) 182299461Sobrien asection *seg; 182399461Sobrien valueT addr; 182499461Sobrien{ 182599461Sobrien int align = bfd_get_section_alignment (stdoutput, seg); 182699461Sobrien 182799461Sobrien return ((addr + (1 << align) - 1) & (-1 << align)); 182899461Sobrien} 182999461Sobrien 183099461Sobrien/* We don't have any form of relaxing. */ 183199461Sobrien 183299461Sobrienint 183399461Sobrienmd_estimate_size_before_relax (fragp, seg) 183499461Sobrien fragS *fragp ATTRIBUTE_UNUSED; 183599461Sobrien asection *seg ATTRIBUTE_UNUSED; 183699461Sobrien{ 183799461Sobrien abort (); 183899461Sobrien return 0; 183999461Sobrien} 184099461Sobrien 184199461Sobrien/* Convert a machine dependent frag. We never generate these. */ 184299461Sobrien 184399461Sobrienvoid 184499461Sobrienmd_convert_frag (abfd, sec, fragp) 184599461Sobrien bfd *abfd ATTRIBUTE_UNUSED; 184699461Sobrien asection *sec ATTRIBUTE_UNUSED; 184799461Sobrien fragS *fragp ATTRIBUTE_UNUSED; 184899461Sobrien{ 184999461Sobrien abort (); 185099461Sobrien} 185199461Sobrien 185299461SobriensymbolS * 185399461Sobrienmd_undefined_symbol (name) 185499461Sobrien char *name; 185599461Sobrien{ 1856107492Sobrien if (*name == '_' && *(name + 1) == 'G' 185799461Sobrien && strcmp (name, "_GLOBAL_OFFSET_TABLE_") == 0) 1858107492Sobrien { 1859107492Sobrien if (!GOT_symbol) 1860107492Sobrien { 1861107492Sobrien if (symbol_find (name)) 1862107492Sobrien as_bad (_("GOT already in symbol table")); 1863107492Sobrien GOT_symbol = symbol_new (name, undefined_section, 1864107492Sobrien (valueT) 0, &zero_address_frag); 1865107492Sobrien } 1866107492Sobrien return GOT_symbol; 1867107492Sobrien } 186899461Sobrien return 0; 186999461Sobrien} 187099461Sobrien 187199461Sobrien/* Functions concerning relocs. */ 187299461Sobrien 187399461Sobrien/* The location from which a PC relative jump should be calculated, 187499461Sobrien given a PC relative reloc. */ 187599461Sobrien 187699461Sobrienlong 187799461Sobrienmd_pcrel_from_section (fixp, sec) 187899461Sobrien fixS *fixp; 187999461Sobrien segT sec ATTRIBUTE_UNUSED; 188099461Sobrien{ 188199461Sobrien return fixp->fx_frag->fr_address + fixp->fx_where; 188299461Sobrien} 188399461Sobrien 188499461Sobrien/* Here we decide which fixups can be adjusted to make them relative to 188599461Sobrien the beginning of the section instead of the symbol. Basically we need 188699461Sobrien to make sure that the dynamic relocations are done correctly, so in 188799461Sobrien some cases we force the original symbol to be used. */ 188899461Sobrienint 1889107492Sobrientc_s390_fix_adjustable (fixP) 1890107492Sobrien fixS *fixP; 189199461Sobrien{ 1892107492Sobrien /* Don't adjust references to merge sections. */ 1893107492Sobrien if ((S_GET_SEGMENT (fixP->fx_addsy)->flags & SEC_MERGE) != 0) 189499461Sobrien return 0; 189599461Sobrien /* adjust_reloc_syms doesn't know about the GOT. */ 1896130561Sobrien if ( fixP->fx_r_type == BFD_RELOC_16_GOTOFF 1897130561Sobrien || fixP->fx_r_type == BFD_RELOC_32_GOTOFF 1898130561Sobrien || fixP->fx_r_type == BFD_RELOC_390_GOTOFF64 1899130561Sobrien || fixP->fx_r_type == BFD_RELOC_390_PLTOFF16 1900130561Sobrien || fixP->fx_r_type == BFD_RELOC_390_PLTOFF32 1901130561Sobrien || fixP->fx_r_type == BFD_RELOC_390_PLTOFF64 190299461Sobrien || fixP->fx_r_type == BFD_RELOC_390_PLT16DBL 190399461Sobrien || fixP->fx_r_type == BFD_RELOC_390_PLT32 190499461Sobrien || fixP->fx_r_type == BFD_RELOC_390_PLT32DBL 190599461Sobrien || fixP->fx_r_type == BFD_RELOC_390_PLT64 190699461Sobrien || fixP->fx_r_type == BFD_RELOC_390_GOT12 1907130561Sobrien || fixP->fx_r_type == BFD_RELOC_390_GOT20 190899461Sobrien || fixP->fx_r_type == BFD_RELOC_390_GOT16 190999461Sobrien || fixP->fx_r_type == BFD_RELOC_32_GOT_PCREL 191099461Sobrien || fixP->fx_r_type == BFD_RELOC_390_GOT64 191199461Sobrien || fixP->fx_r_type == BFD_RELOC_390_GOTENT 1912130561Sobrien || fixP->fx_r_type == BFD_RELOC_390_GOTPLT12 1913130561Sobrien || fixP->fx_r_type == BFD_RELOC_390_GOTPLT16 1914130561Sobrien || fixP->fx_r_type == BFD_RELOC_390_GOTPLT20 1915130561Sobrien || fixP->fx_r_type == BFD_RELOC_390_GOTPLT32 1916130561Sobrien || fixP->fx_r_type == BFD_RELOC_390_GOTPLT64 1917130561Sobrien || fixP->fx_r_type == BFD_RELOC_390_GOTPLTENT 1918130561Sobrien || fixP->fx_r_type == BFD_RELOC_390_TLS_LOAD 1919130561Sobrien || fixP->fx_r_type == BFD_RELOC_390_TLS_GDCALL 1920130561Sobrien || fixP->fx_r_type == BFD_RELOC_390_TLS_LDCALL 1921130561Sobrien || fixP->fx_r_type == BFD_RELOC_390_TLS_GD32 1922130561Sobrien || fixP->fx_r_type == BFD_RELOC_390_TLS_GD64 1923130561Sobrien || fixP->fx_r_type == BFD_RELOC_390_TLS_GOTIE12 1924130561Sobrien || fixP->fx_r_type == BFD_RELOC_390_TLS_GOTIE20 1925130561Sobrien || fixP->fx_r_type == BFD_RELOC_390_TLS_GOTIE32 1926130561Sobrien || fixP->fx_r_type == BFD_RELOC_390_TLS_GOTIE64 1927130561Sobrien || fixP->fx_r_type == BFD_RELOC_390_TLS_LDM32 1928130561Sobrien || fixP->fx_r_type == BFD_RELOC_390_TLS_LDM64 1929130561Sobrien || fixP->fx_r_type == BFD_RELOC_390_TLS_IE32 1930130561Sobrien || fixP->fx_r_type == BFD_RELOC_390_TLS_IE64 1931130561Sobrien || fixP->fx_r_type == BFD_RELOC_390_TLS_IEENT 1932130561Sobrien || fixP->fx_r_type == BFD_RELOC_390_TLS_LE32 1933130561Sobrien || fixP->fx_r_type == BFD_RELOC_390_TLS_LE64 1934130561Sobrien || fixP->fx_r_type == BFD_RELOC_390_TLS_LDO32 1935130561Sobrien || fixP->fx_r_type == BFD_RELOC_390_TLS_LDO64 1936130561Sobrien || fixP->fx_r_type == BFD_RELOC_390_TLS_DTPMOD 1937130561Sobrien || fixP->fx_r_type == BFD_RELOC_390_TLS_DTPOFF 1938130561Sobrien || fixP->fx_r_type == BFD_RELOC_390_TLS_TPOFF 193999461Sobrien || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT 194099461Sobrien || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY) 194199461Sobrien return 0; 194299461Sobrien return 1; 194399461Sobrien} 194499461Sobrien 194599461Sobrien/* Return true if we must always emit a reloc for a type and false if 1946130561Sobrien there is some hope of resolving it at assembly time. */ 194799461Sobrienint 194899461Sobrientc_s390_force_relocation (fixp) 194999461Sobrien struct fix *fixp; 195099461Sobrien{ 195199461Sobrien /* Ensure we emit a relocation for every reference to the global 195299461Sobrien offset table or to the procedure link table. */ 195399461Sobrien switch (fixp->fx_r_type) 195499461Sobrien { 195599461Sobrien case BFD_RELOC_390_GOT12: 1956130561Sobrien case BFD_RELOC_390_GOT20: 195799461Sobrien case BFD_RELOC_32_GOT_PCREL: 195899461Sobrien case BFD_RELOC_32_GOTOFF: 1959130561Sobrien case BFD_RELOC_390_GOTOFF64: 1960130561Sobrien case BFD_RELOC_390_PLTOFF16: 1961130561Sobrien case BFD_RELOC_390_PLTOFF32: 1962130561Sobrien case BFD_RELOC_390_PLTOFF64: 196399461Sobrien case BFD_RELOC_390_GOTPC: 196499461Sobrien case BFD_RELOC_390_GOT16: 196599461Sobrien case BFD_RELOC_390_GOTPCDBL: 196699461Sobrien case BFD_RELOC_390_GOT64: 196799461Sobrien case BFD_RELOC_390_GOTENT: 196899461Sobrien case BFD_RELOC_390_PLT32: 196999461Sobrien case BFD_RELOC_390_PLT16DBL: 197099461Sobrien case BFD_RELOC_390_PLT32DBL: 197199461Sobrien case BFD_RELOC_390_PLT64: 1972130561Sobrien case BFD_RELOC_390_GOTPLT12: 1973130561Sobrien case BFD_RELOC_390_GOTPLT16: 1974130561Sobrien case BFD_RELOC_390_GOTPLT20: 1975130561Sobrien case BFD_RELOC_390_GOTPLT32: 1976130561Sobrien case BFD_RELOC_390_GOTPLT64: 1977130561Sobrien case BFD_RELOC_390_GOTPLTENT: 197899461Sobrien return 1; 197999461Sobrien default: 1980130561Sobrien break;; 198199461Sobrien } 1982130561Sobrien 1983130561Sobrien return generic_force_reloc (fixp); 198499461Sobrien} 198599461Sobrien 198699461Sobrien/* Apply a fixup to the object code. This is called for all the 198799461Sobrien fixups we generated by the call to fix_new_exp, above. In the call 198899461Sobrien above we used a reloc code which was the largest legal reloc code 198999461Sobrien plus the operand index. Here we undo that to recover the operand 199099461Sobrien index. At this point all symbol values should be fully resolved, 199199461Sobrien and we attempt to completely resolve the reloc. If we can not do 199299461Sobrien that, we determine the correct reloc code and put it back in the 199399461Sobrien fixup. */ 199499461Sobrien 199599461Sobrienvoid 1996218822Sdimmd_apply_fix (fixP, valP, seg) 199799461Sobrien fixS *fixP; 199899461Sobrien valueT *valP; 1999130561Sobrien segT seg ATTRIBUTE_UNUSED; 200099461Sobrien{ 200199461Sobrien char *where; 2002107492Sobrien valueT value = *valP; 200399461Sobrien 200499461Sobrien where = fixP->fx_frag->fr_literal + fixP->fx_where; 200599461Sobrien 2006107492Sobrien if (fixP->fx_subsy != NULL) 2007130561Sobrien as_bad_where (fixP->fx_file, fixP->fx_line, 2008130561Sobrien "cannot emit relocation %s against subsy symbol %s", 2009130561Sobrien bfd_get_reloc_code_name (fixP->fx_r_type), 2010130561Sobrien S_GET_NAME (fixP->fx_subsy)); 201199461Sobrien 2012107492Sobrien if (fixP->fx_addsy != NULL) 201399461Sobrien { 201499461Sobrien if (fixP->fx_pcrel) 201599461Sobrien value += fixP->fx_frag->fr_address + fixP->fx_where; 201699461Sobrien } 201799461Sobrien else 201899461Sobrien fixP->fx_done = 1; 201999461Sobrien 202099461Sobrien if ((int) fixP->fx_r_type >= (int) BFD_RELOC_UNUSED) 202199461Sobrien { 202299461Sobrien const struct s390_operand *operand; 202399461Sobrien int opindex; 202499461Sobrien 202599461Sobrien opindex = (int) fixP->fx_r_type - (int) BFD_RELOC_UNUSED; 202699461Sobrien operand = &s390_operands[opindex]; 202799461Sobrien 202899461Sobrien if (fixP->fx_done) 202999461Sobrien { 203099461Sobrien /* Insert the fully resolved operand value. */ 2031218822Sdim s390_insert_operand ((unsigned char *) where, operand, 2032218822Sdim (offsetT) value, fixP->fx_file, fixP->fx_line); 203399461Sobrien return; 203499461Sobrien } 203599461Sobrien 203699461Sobrien /* Determine a BFD reloc value based on the operand information. 203799461Sobrien We are only prepared to turn a few of the operands into 203899461Sobrien relocs. */ 203999461Sobrien fixP->fx_offset = value; 204099461Sobrien if (operand->bits == 12 && operand->shift == 20) 204199461Sobrien { 204299461Sobrien fixP->fx_size = 2; 204399461Sobrien fixP->fx_where += 2; 204499461Sobrien fixP->fx_r_type = BFD_RELOC_390_12; 204599461Sobrien } 204699461Sobrien else if (operand->bits == 12 && operand->shift == 36) 204799461Sobrien { 204899461Sobrien fixP->fx_size = 2; 204999461Sobrien fixP->fx_where += 4; 205099461Sobrien fixP->fx_r_type = BFD_RELOC_390_12; 205199461Sobrien } 2052130561Sobrien else if (operand->bits == 20 && operand->shift == 20) 2053130561Sobrien { 2054130561Sobrien fixP->fx_size = 2; 2055130561Sobrien fixP->fx_where += 2; 2056130561Sobrien fixP->fx_r_type = BFD_RELOC_390_20; 2057130561Sobrien } 205899461Sobrien else if (operand->bits == 8 && operand->shift == 8) 205999461Sobrien { 206099461Sobrien fixP->fx_size = 1; 206199461Sobrien fixP->fx_where += 1; 206299461Sobrien fixP->fx_r_type = BFD_RELOC_8; 206399461Sobrien } 206499461Sobrien else if (operand->bits == 16 && operand->shift == 16) 206599461Sobrien { 206699461Sobrien fixP->fx_size = 2; 206799461Sobrien fixP->fx_where += 2; 206899461Sobrien if (operand->flags & S390_OPERAND_PCREL) 206999461Sobrien { 207099461Sobrien fixP->fx_r_type = BFD_RELOC_390_PC16DBL; 207199461Sobrien fixP->fx_offset += 2; 207299461Sobrien } 207399461Sobrien else 207499461Sobrien fixP->fx_r_type = BFD_RELOC_16; 207599461Sobrien } 207699461Sobrien else if (operand->bits == 32 && operand->shift == 16 207799461Sobrien && (operand->flags & S390_OPERAND_PCREL)) 207899461Sobrien { 207999461Sobrien fixP->fx_size = 4; 208099461Sobrien fixP->fx_where += 2; 208199461Sobrien fixP->fx_offset += 2; 208299461Sobrien fixP->fx_r_type = BFD_RELOC_390_PC32DBL; 208399461Sobrien } 208499461Sobrien else 208599461Sobrien { 208699461Sobrien char *sfile; 208799461Sobrien unsigned int sline; 208899461Sobrien 208999461Sobrien /* Use expr_symbol_where to see if this is an expression 209099461Sobrien symbol. */ 209199461Sobrien if (expr_symbol_where (fixP->fx_addsy, &sfile, &sline)) 209299461Sobrien as_bad_where (fixP->fx_file, fixP->fx_line, 209399461Sobrien _("unresolved expression that must be resolved")); 209499461Sobrien else 209599461Sobrien as_bad_where (fixP->fx_file, fixP->fx_line, 209699461Sobrien _("unsupported relocation type")); 209799461Sobrien fixP->fx_done = 1; 209899461Sobrien return; 209999461Sobrien } 210099461Sobrien } 210199461Sobrien else 210299461Sobrien { 210399461Sobrien switch (fixP->fx_r_type) 210499461Sobrien { 210599461Sobrien case BFD_RELOC_8: 210699461Sobrien if (fixP->fx_pcrel) 210799461Sobrien abort (); 210899461Sobrien if (fixP->fx_done) 210999461Sobrien md_number_to_chars (where, value, 1); 211099461Sobrien break; 211199461Sobrien case BFD_RELOC_390_12: 211299461Sobrien case BFD_RELOC_390_GOT12: 2113130561Sobrien case BFD_RELOC_390_GOTPLT12: 211499461Sobrien if (fixP->fx_done) 211599461Sobrien { 211699461Sobrien unsigned short mop; 211799461Sobrien 211899461Sobrien mop = bfd_getb16 ((unsigned char *) where); 211999461Sobrien mop |= (unsigned short) (value & 0xfff); 212099461Sobrien bfd_putb16 ((bfd_vma) mop, (unsigned char *) where); 212199461Sobrien } 212299461Sobrien break; 212399461Sobrien 2124130561Sobrien case BFD_RELOC_390_20: 2125130561Sobrien case BFD_RELOC_390_GOT20: 2126130561Sobrien case BFD_RELOC_390_GOTPLT20: 2127130561Sobrien if (fixP->fx_done) 2128130561Sobrien { 2129130561Sobrien unsigned int mop; 2130130561Sobrien mop = bfd_getb32 ((unsigned char *) where); 2131130561Sobrien mop |= (unsigned int) ((value & 0xfff) << 8 | 2132130561Sobrien (value & 0xff000) >> 12); 2133130561Sobrien bfd_putb32 ((bfd_vma) mop, (unsigned char *) where); 2134130561Sobrien } 2135130561Sobrien break; 2136130561Sobrien 213799461Sobrien case BFD_RELOC_16: 213899461Sobrien case BFD_RELOC_GPREL16: 213999461Sobrien case BFD_RELOC_16_GOT_PCREL: 214099461Sobrien case BFD_RELOC_16_GOTOFF: 214199461Sobrien if (fixP->fx_pcrel) 214299461Sobrien as_bad_where (fixP->fx_file, fixP->fx_line, 214399461Sobrien "cannot emit PC relative %s relocation%s%s", 214499461Sobrien bfd_get_reloc_code_name (fixP->fx_r_type), 214599461Sobrien fixP->fx_addsy != NULL ? " against " : "", 214699461Sobrien (fixP->fx_addsy != NULL 214799461Sobrien ? S_GET_NAME (fixP->fx_addsy) 214899461Sobrien : "")); 214999461Sobrien if (fixP->fx_done) 215099461Sobrien md_number_to_chars (where, value, 2); 215199461Sobrien break; 215299461Sobrien case BFD_RELOC_390_GOT16: 2153130561Sobrien case BFD_RELOC_390_PLTOFF16: 2154130561Sobrien case BFD_RELOC_390_GOTPLT16: 215599461Sobrien if (fixP->fx_done) 215699461Sobrien md_number_to_chars (where, value, 2); 215799461Sobrien break; 215899461Sobrien case BFD_RELOC_390_PC16DBL: 215999461Sobrien case BFD_RELOC_390_PLT16DBL: 216099461Sobrien value += 2; 216199461Sobrien if (fixP->fx_done) 216299461Sobrien md_number_to_chars (where, (offsetT) value >> 1, 2); 216399461Sobrien break; 216499461Sobrien 216599461Sobrien case BFD_RELOC_32: 216699461Sobrien if (fixP->fx_pcrel) 216799461Sobrien fixP->fx_r_type = BFD_RELOC_32_PCREL; 216899461Sobrien else 216999461Sobrien fixP->fx_r_type = BFD_RELOC_32; 217099461Sobrien if (fixP->fx_done) 217199461Sobrien md_number_to_chars (where, value, 4); 217299461Sobrien break; 217399461Sobrien case BFD_RELOC_32_PCREL: 217499461Sobrien case BFD_RELOC_32_BASEREL: 217599461Sobrien fixP->fx_r_type = BFD_RELOC_32_PCREL; 217699461Sobrien if (fixP->fx_done) 217799461Sobrien md_number_to_chars (where, value, 4); 217899461Sobrien break; 217999461Sobrien case BFD_RELOC_32_GOT_PCREL: 2180130561Sobrien case BFD_RELOC_390_PLTOFF32: 218199461Sobrien case BFD_RELOC_390_PLT32: 2182130561Sobrien case BFD_RELOC_390_GOTPLT32: 218399461Sobrien if (fixP->fx_done) 218499461Sobrien md_number_to_chars (where, value, 4); 218599461Sobrien break; 218699461Sobrien case BFD_RELOC_390_PC32DBL: 218799461Sobrien case BFD_RELOC_390_PLT32DBL: 218899461Sobrien case BFD_RELOC_390_GOTPCDBL: 218999461Sobrien case BFD_RELOC_390_GOTENT: 2190130561Sobrien case BFD_RELOC_390_GOTPLTENT: 219199461Sobrien value += 2; 219299461Sobrien if (fixP->fx_done) 219399461Sobrien md_number_to_chars (where, (offsetT) value >> 1, 4); 219499461Sobrien break; 219599461Sobrien 219699461Sobrien case BFD_RELOC_32_GOTOFF: 219799461Sobrien if (fixP->fx_done) 219899461Sobrien md_number_to_chars (where, value, sizeof (int)); 219999461Sobrien break; 220099461Sobrien 2201130561Sobrien case BFD_RELOC_390_GOTOFF64: 2202130561Sobrien if (fixP->fx_done) 2203130561Sobrien md_number_to_chars (where, value, 8); 2204130561Sobrien break; 2205130561Sobrien 220699461Sobrien case BFD_RELOC_390_GOT64: 2207130561Sobrien case BFD_RELOC_390_PLTOFF64: 220899461Sobrien case BFD_RELOC_390_PLT64: 2209130561Sobrien case BFD_RELOC_390_GOTPLT64: 221099461Sobrien if (fixP->fx_done) 221199461Sobrien md_number_to_chars (where, value, 8); 221299461Sobrien break; 221399461Sobrien 221499461Sobrien case BFD_RELOC_64: 221599461Sobrien if (fixP->fx_pcrel) 221699461Sobrien fixP->fx_r_type = BFD_RELOC_64_PCREL; 221799461Sobrien else 221899461Sobrien fixP->fx_r_type = BFD_RELOC_64; 221999461Sobrien if (fixP->fx_done) 222099461Sobrien md_number_to_chars (where, value, 8); 222199461Sobrien break; 222299461Sobrien 222399461Sobrien case BFD_RELOC_64_PCREL: 222499461Sobrien fixP->fx_r_type = BFD_RELOC_64_PCREL; 222599461Sobrien if (fixP->fx_done) 222699461Sobrien md_number_to_chars (where, value, 8); 222799461Sobrien break; 222899461Sobrien 222999461Sobrien case BFD_RELOC_VTABLE_INHERIT: 223099461Sobrien case BFD_RELOC_VTABLE_ENTRY: 223199461Sobrien fixP->fx_done = 0; 223299461Sobrien return; 223399461Sobrien 2234130561Sobrien case BFD_RELOC_390_TLS_LOAD: 2235130561Sobrien case BFD_RELOC_390_TLS_GDCALL: 2236130561Sobrien case BFD_RELOC_390_TLS_LDCALL: 2237130561Sobrien case BFD_RELOC_390_TLS_GD32: 2238130561Sobrien case BFD_RELOC_390_TLS_GD64: 2239130561Sobrien case BFD_RELOC_390_TLS_GOTIE12: 2240130561Sobrien case BFD_RELOC_390_TLS_GOTIE20: 2241130561Sobrien case BFD_RELOC_390_TLS_GOTIE32: 2242130561Sobrien case BFD_RELOC_390_TLS_GOTIE64: 2243130561Sobrien case BFD_RELOC_390_TLS_LDM32: 2244130561Sobrien case BFD_RELOC_390_TLS_LDM64: 2245130561Sobrien case BFD_RELOC_390_TLS_IE32: 2246130561Sobrien case BFD_RELOC_390_TLS_IE64: 2247130561Sobrien case BFD_RELOC_390_TLS_LE32: 2248130561Sobrien case BFD_RELOC_390_TLS_LE64: 2249130561Sobrien case BFD_RELOC_390_TLS_LDO32: 2250130561Sobrien case BFD_RELOC_390_TLS_LDO64: 2251130561Sobrien case BFD_RELOC_390_TLS_DTPMOD: 2252130561Sobrien case BFD_RELOC_390_TLS_DTPOFF: 2253130561Sobrien case BFD_RELOC_390_TLS_TPOFF: 2254218822Sdim S_SET_THREAD_LOCAL (fixP->fx_addsy); 2255130561Sobrien /* Fully resolved at link time. */ 2256130561Sobrien break; 2257130561Sobrien case BFD_RELOC_390_TLS_IEENT: 2258130561Sobrien /* Fully resolved at link time. */ 2259218822Sdim S_SET_THREAD_LOCAL (fixP->fx_addsy); 2260130561Sobrien value += 2; 2261130561Sobrien break; 2262130561Sobrien 226399461Sobrien default: 226499461Sobrien { 226599461Sobrien const char *reloc_name = bfd_get_reloc_code_name (fixP->fx_r_type); 226699461Sobrien 226799461Sobrien if (reloc_name != NULL) 226899461Sobrien fprintf (stderr, "Gas failure, reloc type %s\n", reloc_name); 226999461Sobrien else 227099461Sobrien fprintf (stderr, "Gas failure, reloc type #%i\n", fixP->fx_r_type); 227199461Sobrien fflush (stderr); 227299461Sobrien abort (); 227399461Sobrien } 227499461Sobrien } 227599461Sobrien 227699461Sobrien fixP->fx_offset = value; 227799461Sobrien } 227899461Sobrien} 227999461Sobrien 228099461Sobrien/* Generate a reloc for a fixup. */ 228199461Sobrien 228299461Sobrienarelent * 228399461Sobrientc_gen_reloc (seg, fixp) 228499461Sobrien asection *seg ATTRIBUTE_UNUSED; 228599461Sobrien fixS *fixp; 228699461Sobrien{ 228799461Sobrien bfd_reloc_code_real_type code; 228899461Sobrien arelent *reloc; 228999461Sobrien 229099461Sobrien code = fixp->fx_r_type; 229199461Sobrien if (GOT_symbol && fixp->fx_addsy == GOT_symbol) 229299461Sobrien { 229399461Sobrien if ( (s390_arch_size == 32 && code == BFD_RELOC_32_PCREL) 229499461Sobrien || (s390_arch_size == 64 && code == BFD_RELOC_64_PCREL)) 229599461Sobrien code = BFD_RELOC_390_GOTPC; 229699461Sobrien if (code == BFD_RELOC_390_PC32DBL) 229799461Sobrien code = BFD_RELOC_390_GOTPCDBL; 229899461Sobrien } 229999461Sobrien 230099461Sobrien reloc = (arelent *) xmalloc (sizeof (arelent)); 230199461Sobrien reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); 230299461Sobrien *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); 230399461Sobrien reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; 230499461Sobrien reloc->howto = bfd_reloc_type_lookup (stdoutput, code); 230599461Sobrien if (reloc->howto == NULL) 230699461Sobrien { 230799461Sobrien as_bad_where (fixp->fx_file, fixp->fx_line, 2308107492Sobrien _("cannot represent relocation type %s"), 2309107492Sobrien bfd_get_reloc_code_name (code)); 231099461Sobrien /* Set howto to a garbage value so that we can keep going. */ 231199461Sobrien reloc->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32); 231299461Sobrien assert (reloc->howto != NULL); 231399461Sobrien } 231499461Sobrien reloc->addend = fixp->fx_offset; 231599461Sobrien 231699461Sobrien return reloc; 231799461Sobrien} 2318130561Sobrien 2319130561Sobrienvoid 2320130561Sobriens390_cfi_frame_initial_instructions () 2321130561Sobrien{ 2322130561Sobrien cfi_add_CFA_def_cfa (15, s390_arch_size == 64 ? 160 : 96); 2323130561Sobrien} 2324130561Sobrien 2325130561Sobrienint 2326218822Sdimtc_s390_regname_to_dw2regnum (char *regname) 2327130561Sobrien{ 2328130561Sobrien int regnum = -1; 2329130561Sobrien 2330130561Sobrien if (regname[0] != 'c' && regname[0] != 'a') 2331130561Sobrien { 2332130561Sobrien regnum = reg_name_search (pre_defined_registers, REG_NAME_CNT, regname); 2333130561Sobrien if (regname[0] == 'f' && regnum != -1) 2334130561Sobrien regnum += 16; 2335130561Sobrien } 2336130561Sobrien else if (strcmp (regname, "ap") == 0) 2337130561Sobrien regnum = 32; 2338130561Sobrien else if (strcmp (regname, "cc") == 0) 2339130561Sobrien regnum = 33; 2340130561Sobrien return regnum; 2341130561Sobrien} 2342