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