199461Sobrien/* IBM S/390-specific support for 64-bit ELF
2218822Sdim   Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
3218822Sdim   Free Software Foundation, Inc.
499461Sobrien   Contributed Martin Schwidefsky (schwidefsky@de.ibm.com).
599461Sobrien
699461Sobrien   This file is part of BFD, the Binary File Descriptor library.
799461Sobrien
899461Sobrien   This program 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 of the License, or
1199461Sobrien   (at your option) any later version.
1299461Sobrien
1399461Sobrien   This program 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 this program; if not, write to the Free Software
20218822Sdim   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
21218822Sdim   02110-1301, USA.  */
2299461Sobrien
23218822Sdim#include "sysdep.h"
2499461Sobrien#include "bfd.h"
2599461Sobrien#include "bfdlink.h"
2699461Sobrien#include "libbfd.h"
2799461Sobrien#include "elf-bfd.h"
2899461Sobrien
2999461Sobrienstatic reloc_howto_type *elf_s390_reloc_type_lookup
3099461Sobrien  PARAMS ((bfd *, bfd_reloc_code_real_type));
3199461Sobrienstatic void elf_s390_info_to_howto
3299461Sobrien  PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
33130561Sobrienstatic bfd_boolean elf_s390_is_local_label_name
3499461Sobrien  PARAMS ((bfd *, const char *));
3599461Sobrienstatic struct bfd_hash_entry *link_hash_newfunc
3699461Sobrien  PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
3799461Sobrienstatic struct bfd_link_hash_table *elf_s390_link_hash_table_create
3899461Sobrien  PARAMS ((bfd *));
39130561Sobrienstatic bfd_boolean create_got_section
4099461Sobrien  PARAMS((bfd *, struct bfd_link_info *));
41130561Sobrienstatic bfd_boolean elf_s390_create_dynamic_sections
4299461Sobrien  PARAMS((bfd *, struct bfd_link_info *));
4399461Sobrienstatic void elf_s390_copy_indirect_symbol
44218822Sdim  PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *,
45107492Sobrien	   struct elf_link_hash_entry *));
46130561Sobrienstatic bfd_boolean elf_s390_check_relocs
4799461Sobrien  PARAMS ((bfd *, struct bfd_link_info *, asection *,
4899461Sobrien	   const Elf_Internal_Rela *));
49130561Sobrienstruct elf_s390_link_hash_entry;
50130561Sobrienstatic void elf_s390_adjust_gotplt
51130561Sobrien  PARAMS ((struct elf_s390_link_hash_entry *));
52130561Sobrienstatic bfd_boolean elf_s390_adjust_dynamic_symbol
5399461Sobrien  PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
54130561Sobrienstatic bfd_boolean allocate_dynrelocs
5599461Sobrien  PARAMS ((struct elf_link_hash_entry *, PTR));
56130561Sobrienstatic bfd_boolean readonly_dynrelocs
5799461Sobrien  PARAMS ((struct elf_link_hash_entry *, PTR));
58130561Sobrienstatic bfd_boolean elf_s390_size_dynamic_sections
5999461Sobrien  PARAMS ((bfd *, struct bfd_link_info *));
60130561Sobrienstatic bfd_boolean elf_s390_relocate_section
6199461Sobrien  PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
6299461Sobrien	   Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
63130561Sobrienstatic bfd_boolean elf_s390_finish_dynamic_symbol
6499461Sobrien  PARAMS ((bfd *, struct bfd_link_info *, struct elf_link_hash_entry *,
6599461Sobrien	   Elf_Internal_Sym *));
6699461Sobrienstatic enum elf_reloc_type_class elf_s390_reloc_type_class
6799461Sobrien  PARAMS ((const Elf_Internal_Rela *));
68130561Sobrienstatic bfd_boolean elf_s390_finish_dynamic_sections
6999461Sobrien  PARAMS ((bfd *, struct bfd_link_info *));
70130561Sobrienstatic bfd_boolean elf_s390_object_p
71130561Sobrien  PARAMS ((bfd *));
72130561Sobrienstatic int elf_s390_tls_transition
73130561Sobrien  PARAMS ((struct bfd_link_info *, int, int));
74130561Sobrienstatic bfd_reloc_status_type s390_tls_reloc
75130561Sobrien  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
76130561Sobrienstatic bfd_vma dtpoff_base
77130561Sobrien  PARAMS ((struct bfd_link_info *));
78130561Sobrienstatic bfd_vma tpoff
79130561Sobrien  PARAMS ((struct bfd_link_info *, bfd_vma));
80130561Sobrienstatic void invalid_tls_insn
81130561Sobrien  PARAMS ((bfd *, asection *, Elf_Internal_Rela *));
82130561Sobrienstatic bfd_reloc_status_type s390_elf_ldisp_reloc
83130561Sobrien  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
8499461Sobrien
8599461Sobrien#include "elf/s390.h"
8699461Sobrien
8799461Sobrien/* In case we're on a 32-bit machine, construct a 64-bit "-1" value
8899461Sobrien   from smaller values.  Start with zero, widen, *then* decrement.  */
8999461Sobrien#define MINUS_ONE      (((bfd_vma)0) - 1)
9099461Sobrien
9199461Sobrien/* The relocation "howto" table.  */
9299461Sobrienstatic reloc_howto_type elf_howto_table[] =
9399461Sobrien{
9499461Sobrien  HOWTO (R_390_NONE,		/* type */
9599461Sobrien	 0,			/* rightshift */
9699461Sobrien	 0,			/* size (0 = byte, 1 = short, 2 = long) */
9799461Sobrien	 0,			/* bitsize */
98130561Sobrien	 FALSE,			/* pc_relative */
9999461Sobrien	 0,			/* bitpos */
10099461Sobrien	 complain_overflow_dont, /* complain_on_overflow */
10199461Sobrien	 bfd_elf_generic_reloc, /* special_function */
10299461Sobrien	 "R_390_NONE",		/* name */
103130561Sobrien	 FALSE,			/* partial_inplace */
10499461Sobrien	 0,			/* src_mask */
10599461Sobrien	 0,			/* dst_mask */
106130561Sobrien	 FALSE),		/* pcrel_offset */
10799461Sobrien
108130561Sobrien  HOWTO(R_390_8,         0, 0,  8, FALSE, 0, complain_overflow_bitfield,
109130561Sobrien	bfd_elf_generic_reloc, "R_390_8",        FALSE, 0,0x000000ff, FALSE),
110130561Sobrien  HOWTO(R_390_12,        0, 1, 12, FALSE, 0, complain_overflow_dont,
111130561Sobrien	bfd_elf_generic_reloc, "R_390_12",       FALSE, 0,0x00000fff, FALSE),
112130561Sobrien  HOWTO(R_390_16,        0, 1, 16, FALSE, 0, complain_overflow_bitfield,
113130561Sobrien	bfd_elf_generic_reloc, "R_390_16",       FALSE, 0,0x0000ffff, FALSE),
114130561Sobrien  HOWTO(R_390_32,        0, 2, 32, FALSE, 0, complain_overflow_bitfield,
115130561Sobrien	bfd_elf_generic_reloc, "R_390_32",       FALSE, 0,0xffffffff, FALSE),
116130561Sobrien  HOWTO(R_390_PC32,	 0, 2, 32,  TRUE, 0, complain_overflow_bitfield,
117130561Sobrien	bfd_elf_generic_reloc, "R_390_PC32",     FALSE, 0,0xffffffff, TRUE),
118130561Sobrien  HOWTO(R_390_GOT12,	 0, 1, 12, FALSE, 0, complain_overflow_bitfield,
119130561Sobrien	bfd_elf_generic_reloc, "R_390_GOT12",    FALSE, 0,0x00000fff, FALSE),
120130561Sobrien  HOWTO(R_390_GOT32,	 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
121130561Sobrien	bfd_elf_generic_reloc, "R_390_GOT32",    FALSE, 0,0xffffffff, FALSE),
122130561Sobrien  HOWTO(R_390_PLT32,	 0, 2, 32,  TRUE, 0, complain_overflow_bitfield,
123130561Sobrien	bfd_elf_generic_reloc, "R_390_PLT32",    FALSE, 0,0xffffffff, TRUE),
124130561Sobrien  HOWTO(R_390_COPY,      0, 4, 64, FALSE, 0, complain_overflow_bitfield,
125130561Sobrien	bfd_elf_generic_reloc, "R_390_COPY",     FALSE, 0,MINUS_ONE,  FALSE),
126130561Sobrien  HOWTO(R_390_GLOB_DAT,  0, 4, 64, FALSE, 0, complain_overflow_bitfield,
127130561Sobrien	bfd_elf_generic_reloc, "R_390_GLOB_DAT", FALSE, 0,MINUS_ONE,  FALSE),
128130561Sobrien  HOWTO(R_390_JMP_SLOT,  0, 4, 64, FALSE, 0, complain_overflow_bitfield,
129130561Sobrien	bfd_elf_generic_reloc, "R_390_JMP_SLOT", FALSE, 0,MINUS_ONE,  FALSE),
130130561Sobrien  HOWTO(R_390_RELATIVE,  0, 4, 64,  TRUE, 0, complain_overflow_bitfield,
131130561Sobrien	bfd_elf_generic_reloc, "R_390_RELATIVE", FALSE, 0,MINUS_ONE,  FALSE),
132130561Sobrien  HOWTO(R_390_GOTOFF32,  0, 2, 32, FALSE, 0, complain_overflow_bitfield,
133130561Sobrien	bfd_elf_generic_reloc, "R_390_GOTOFF32", FALSE, 0,MINUS_ONE,  FALSE),
134130561Sobrien  HOWTO(R_390_GOTPC,     0, 4, 64,  TRUE, 0, complain_overflow_bitfield,
135130561Sobrien	bfd_elf_generic_reloc, "R_390_GOTPC",    FALSE, 0,MINUS_ONE,  TRUE),
136130561Sobrien  HOWTO(R_390_GOT16,     0, 1, 16, FALSE, 0, complain_overflow_bitfield,
137130561Sobrien	bfd_elf_generic_reloc, "R_390_GOT16",    FALSE, 0,0x0000ffff, FALSE),
138130561Sobrien  HOWTO(R_390_PC16,      0, 1, 16,  TRUE, 0, complain_overflow_bitfield,
139130561Sobrien	bfd_elf_generic_reloc, "R_390_PC16",     FALSE, 0,0x0000ffff, TRUE),
140130561Sobrien  HOWTO(R_390_PC16DBL,   1, 1, 16,  TRUE, 0, complain_overflow_bitfield,
141130561Sobrien	bfd_elf_generic_reloc, "R_390_PC16DBL",  FALSE, 0,0x0000ffff, TRUE),
142130561Sobrien  HOWTO(R_390_PLT16DBL,  1, 1, 16,  TRUE, 0, complain_overflow_bitfield,
143130561Sobrien	bfd_elf_generic_reloc, "R_390_PLT16DBL", FALSE, 0,0x0000ffff, TRUE),
144130561Sobrien  HOWTO(R_390_PC32DBL,	 1, 2, 32,  TRUE, 0, complain_overflow_bitfield,
145130561Sobrien	bfd_elf_generic_reloc, "R_390_PC32DBL",  FALSE, 0,0xffffffff, TRUE),
146130561Sobrien  HOWTO(R_390_PLT32DBL,	 1, 2, 32,  TRUE, 0, complain_overflow_bitfield,
147130561Sobrien	bfd_elf_generic_reloc, "R_390_PLT32DBL", FALSE, 0,0xffffffff, TRUE),
148130561Sobrien  HOWTO(R_390_GOTPCDBL,  1, 2, 32,  TRUE, 0, complain_overflow_bitfield,
149130561Sobrien	bfd_elf_generic_reloc, "R_390_GOTPCDBL", FALSE, 0,MINUS_ONE,  TRUE),
150130561Sobrien  HOWTO(R_390_64,        0, 4, 64, FALSE, 0, complain_overflow_bitfield,
151130561Sobrien	bfd_elf_generic_reloc, "R_390_64",       FALSE, 0,MINUS_ONE,  FALSE),
152130561Sobrien  HOWTO(R_390_PC64,	 0, 4, 64,  TRUE, 0, complain_overflow_bitfield,
153130561Sobrien	bfd_elf_generic_reloc, "R_390_PC64",     FALSE, 0,MINUS_ONE,  TRUE),
154130561Sobrien  HOWTO(R_390_GOT64,	 0, 4, 64, FALSE, 0, complain_overflow_bitfield,
155130561Sobrien	bfd_elf_generic_reloc, "R_390_GOT64",    FALSE, 0,MINUS_ONE,  FALSE),
156130561Sobrien  HOWTO(R_390_PLT64,	 0, 4, 64,  TRUE, 0, complain_overflow_bitfield,
157130561Sobrien	bfd_elf_generic_reloc, "R_390_PLT64",    FALSE, 0,MINUS_ONE,  TRUE),
158130561Sobrien  HOWTO(R_390_GOTENT,	 1, 2, 32,  TRUE, 0, complain_overflow_bitfield,
159130561Sobrien	bfd_elf_generic_reloc, "R_390_GOTENT",   FALSE, 0,MINUS_ONE,  TRUE),
160130561Sobrien  HOWTO(R_390_GOTOFF16,  0, 1, 16, FALSE, 0, complain_overflow_bitfield,
161130561Sobrien	bfd_elf_generic_reloc, "R_390_GOTOFF16", FALSE, 0,0x0000ffff, FALSE),
162130561Sobrien  HOWTO(R_390_GOTOFF64,  0, 4, 64, FALSE, 0, complain_overflow_bitfield,
163130561Sobrien	bfd_elf_generic_reloc, "R_390_GOTOFF64", FALSE, 0,MINUS_ONE,  FALSE),
164130561Sobrien  HOWTO(R_390_GOTPLT12,	 0, 1, 12, FALSE, 0, complain_overflow_dont,
165130561Sobrien	bfd_elf_generic_reloc, "R_390_GOTPLT12", FALSE, 0,0x00000fff, FALSE),
166130561Sobrien  HOWTO(R_390_GOTPLT16,  0, 1, 16, FALSE, 0, complain_overflow_bitfield,
167130561Sobrien	bfd_elf_generic_reloc, "R_390_GOTPLT16", FALSE, 0,0x0000ffff, FALSE),
168130561Sobrien  HOWTO(R_390_GOTPLT32,	 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
169130561Sobrien	bfd_elf_generic_reloc, "R_390_GOTPLT32", FALSE, 0,0xffffffff, FALSE),
170130561Sobrien  HOWTO(R_390_GOTPLT64,	 0, 4, 64, FALSE, 0, complain_overflow_bitfield,
171130561Sobrien	bfd_elf_generic_reloc, "R_390_GOTPLT64", FALSE, 0,MINUS_ONE,  FALSE),
172130561Sobrien  HOWTO(R_390_GOTPLTENT, 1, 2, 32,  TRUE, 0, complain_overflow_bitfield,
173130561Sobrien	bfd_elf_generic_reloc, "R_390_GOTPLTENT",FALSE, 0,MINUS_ONE,  TRUE),
174130561Sobrien  HOWTO(R_390_PLTOFF16,  0, 1, 16, FALSE, 0, complain_overflow_bitfield,
175130561Sobrien	bfd_elf_generic_reloc, "R_390_PLTOFF16", FALSE, 0,0x0000ffff, FALSE),
176130561Sobrien  HOWTO(R_390_PLTOFF32,  0, 2, 32, FALSE, 0, complain_overflow_bitfield,
177130561Sobrien	bfd_elf_generic_reloc, "R_390_PLTOFF32", FALSE, 0,0xffffffff, FALSE),
178130561Sobrien  HOWTO(R_390_PLTOFF64,  0, 4, 64, FALSE, 0, complain_overflow_bitfield,
179130561Sobrien	bfd_elf_generic_reloc, "R_390_PLTOFF64", FALSE, 0,MINUS_ONE,  FALSE),
180130561Sobrien  HOWTO(R_390_TLS_LOAD, 0, 0, 0, FALSE, 0, complain_overflow_dont,
181130561Sobrien	s390_tls_reloc, "R_390_TLS_LOAD", FALSE, 0, 0, FALSE),
182130561Sobrien  HOWTO(R_390_TLS_GDCALL, 0, 0, 0, FALSE, 0, complain_overflow_dont,
183130561Sobrien	s390_tls_reloc, "R_390_TLS_GDCALL", FALSE, 0, 0, FALSE),
184130561Sobrien  HOWTO(R_390_TLS_LDCALL, 0, 0, 0, FALSE, 0, complain_overflow_dont,
185130561Sobrien	s390_tls_reloc, "R_390_TLS_LDCALL", FALSE, 0, 0, FALSE),
186130561Sobrien  EMPTY_HOWTO (R_390_TLS_GD32),	/* Empty entry for R_390_TLS_GD32.  */
187130561Sobrien  HOWTO(R_390_TLS_GD64,  0, 4, 64, FALSE, 0, complain_overflow_bitfield,
188130561Sobrien	bfd_elf_generic_reloc, "R_390_TLS_GD64", FALSE, 0, MINUS_ONE, FALSE),
189130561Sobrien  HOWTO(R_390_TLS_GOTIE12, 0, 1, 12, FALSE, 0, complain_overflow_dont,
190130561Sobrien	bfd_elf_generic_reloc, "R_390_TLS_GOTIE12", FALSE, 0, 0x00000fff, FALSE),
191130561Sobrien  EMPTY_HOWTO (R_390_TLS_GOTIE32),	/* Empty entry for R_390_TLS_GOTIE32.  */
192130561Sobrien  HOWTO(R_390_TLS_GOTIE64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield,
193130561Sobrien	bfd_elf_generic_reloc, "R_390_TLS_GOTIE64", FALSE, 0, MINUS_ONE, FALSE),
194130561Sobrien  EMPTY_HOWTO (R_390_TLS_LDM32),	/* Empty entry for R_390_TLS_LDM32.  */
195130561Sobrien  HOWTO(R_390_TLS_LDM64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield,
196130561Sobrien	bfd_elf_generic_reloc, "R_390_TLS_LDM64", FALSE, 0, MINUS_ONE, FALSE),
197130561Sobrien  EMPTY_HOWTO (R_390_TLS_IE32),	/* Empty entry for R_390_TLS_IE32.  */
198130561Sobrien  HOWTO(R_390_TLS_IE64,  0, 4, 64, FALSE, 0, complain_overflow_bitfield,
199130561Sobrien	bfd_elf_generic_reloc, "R_390_TLS_IE64", FALSE, 0, MINUS_ONE, FALSE),
200130561Sobrien  HOWTO(R_390_TLS_IEENT, 1, 2, 32, TRUE, 0, complain_overflow_bitfield,
201130561Sobrien	bfd_elf_generic_reloc, "R_390_TLS_IEENT", FALSE, 0, MINUS_ONE, TRUE),
202130561Sobrien  EMPTY_HOWTO (R_390_TLS_LE32),	/* Empty entry for R_390_TLS_LE32.  */
203130561Sobrien  HOWTO(R_390_TLS_LE64,  0, 2, 32, FALSE, 0, complain_overflow_bitfield,
204130561Sobrien	bfd_elf_generic_reloc, "R_390_TLS_LE64", FALSE, 0, MINUS_ONE, FALSE),
205130561Sobrien  EMPTY_HOWTO (R_390_TLS_LDO32),	/* Empty entry for R_390_TLS_LDO32.  */
206130561Sobrien  HOWTO(R_390_TLS_LDO64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield,
207130561Sobrien	bfd_elf_generic_reloc, "R_390_TLS_LDO64", FALSE, 0, MINUS_ONE, FALSE),
208130561Sobrien  HOWTO(R_390_TLS_DTPMOD, 0, 4, 64, FALSE, 0, complain_overflow_bitfield,
209130561Sobrien	bfd_elf_generic_reloc, "R_390_TLS_DTPMOD", FALSE, 0, MINUS_ONE, FALSE),
210130561Sobrien  HOWTO(R_390_TLS_DTPOFF, 0, 4, 64, FALSE, 0, complain_overflow_bitfield,
211130561Sobrien	bfd_elf_generic_reloc, "R_390_TLS_DTPOFF", FALSE, 0, MINUS_ONE, FALSE),
212130561Sobrien  HOWTO(R_390_TLS_TPOFF, 0, 4, 64, FALSE, 0, complain_overflow_bitfield,
213130561Sobrien	bfd_elf_generic_reloc, "R_390_TLS_TPOFF", FALSE, 0, MINUS_ONE, FALSE),
214130561Sobrien  HOWTO(R_390_20,        0, 2, 20, FALSE, 8, complain_overflow_dont,
215130561Sobrien	s390_elf_ldisp_reloc, "R_390_20",      FALSE, 0,0x0fffff00, FALSE),
216130561Sobrien  HOWTO(R_390_GOT20,	 0, 2, 20, FALSE, 8, complain_overflow_dont,
217130561Sobrien	s390_elf_ldisp_reloc, "R_390_GOT20",   FALSE, 0,0x0fffff00, FALSE),
218130561Sobrien  HOWTO(R_390_GOTPLT20,  0, 2, 20, FALSE, 8, complain_overflow_dont,
219130561Sobrien	s390_elf_ldisp_reloc, "R_390_GOTPLT20", FALSE, 0,0x0fffff00, FALSE),
220130561Sobrien  HOWTO(R_390_TLS_GOTIE20, 0, 2, 20, FALSE, 8, complain_overflow_dont,
221130561Sobrien	s390_elf_ldisp_reloc, "R_390_TLS_GOTIE20", FALSE, 0,0x0fffff00, FALSE),
22299461Sobrien};
22399461Sobrien
22499461Sobrien/* GNU extension to record C++ vtable hierarchy.  */
22599461Sobrienstatic reloc_howto_type elf64_s390_vtinherit_howto =
226130561Sobrien  HOWTO (R_390_GNU_VTINHERIT, 0,4,0,FALSE,0,complain_overflow_dont, NULL, "R_390_GNU_VTINHERIT", FALSE,0, 0, FALSE);
22799461Sobrienstatic reloc_howto_type elf64_s390_vtentry_howto =
228130561Sobrien  HOWTO (R_390_GNU_VTENTRY, 0,4,0,FALSE,0,complain_overflow_dont, _bfd_elf_rel_vtable_reloc_fn,"R_390_GNU_VTENTRY", FALSE,0,0, FALSE);
22999461Sobrien
23099461Sobrienstatic reloc_howto_type *
23199461Sobrienelf_s390_reloc_type_lookup (abfd, code)
23299461Sobrien     bfd *abfd ATTRIBUTE_UNUSED;
23399461Sobrien     bfd_reloc_code_real_type code;
23499461Sobrien{
23599461Sobrien  switch (code)
23699461Sobrien    {
23799461Sobrien    case BFD_RELOC_NONE:
23899461Sobrien      return &elf_howto_table[(int) R_390_NONE];
23999461Sobrien    case BFD_RELOC_8:
24099461Sobrien      return &elf_howto_table[(int) R_390_8];
24199461Sobrien    case BFD_RELOC_390_12:
24299461Sobrien      return &elf_howto_table[(int) R_390_12];
24399461Sobrien    case BFD_RELOC_16:
24499461Sobrien      return &elf_howto_table[(int) R_390_16];
24599461Sobrien    case BFD_RELOC_32:
24699461Sobrien      return &elf_howto_table[(int) R_390_32];
24799461Sobrien    case BFD_RELOC_CTOR:
24899461Sobrien      return &elf_howto_table[(int) R_390_32];
24999461Sobrien    case BFD_RELOC_32_PCREL:
25099461Sobrien      return &elf_howto_table[(int) R_390_PC32];
25199461Sobrien    case BFD_RELOC_390_GOT12:
25299461Sobrien      return &elf_howto_table[(int) R_390_GOT12];
25399461Sobrien    case BFD_RELOC_32_GOT_PCREL:
25499461Sobrien      return &elf_howto_table[(int) R_390_GOT32];
25599461Sobrien    case BFD_RELOC_390_PLT32:
25699461Sobrien      return &elf_howto_table[(int) R_390_PLT32];
25799461Sobrien    case BFD_RELOC_390_COPY:
25899461Sobrien      return &elf_howto_table[(int) R_390_COPY];
25999461Sobrien    case BFD_RELOC_390_GLOB_DAT:
26099461Sobrien      return &elf_howto_table[(int) R_390_GLOB_DAT];
26199461Sobrien    case BFD_RELOC_390_JMP_SLOT:
26299461Sobrien      return &elf_howto_table[(int) R_390_JMP_SLOT];
26399461Sobrien    case BFD_RELOC_390_RELATIVE:
26499461Sobrien      return &elf_howto_table[(int) R_390_RELATIVE];
26599461Sobrien    case BFD_RELOC_32_GOTOFF:
266130561Sobrien      return &elf_howto_table[(int) R_390_GOTOFF32];
26799461Sobrien    case BFD_RELOC_390_GOTPC:
26899461Sobrien      return &elf_howto_table[(int) R_390_GOTPC];
26999461Sobrien    case BFD_RELOC_390_GOT16:
27099461Sobrien      return &elf_howto_table[(int) R_390_GOT16];
27199461Sobrien    case BFD_RELOC_16_PCREL:
27299461Sobrien      return &elf_howto_table[(int) R_390_PC16];
27399461Sobrien    case BFD_RELOC_390_PC16DBL:
27499461Sobrien      return &elf_howto_table[(int) R_390_PC16DBL];
27599461Sobrien    case BFD_RELOC_390_PLT16DBL:
27699461Sobrien      return &elf_howto_table[(int) R_390_PLT16DBL];
27799461Sobrien    case BFD_RELOC_390_PC32DBL:
27899461Sobrien      return &elf_howto_table[(int) R_390_PC32DBL];
27999461Sobrien    case BFD_RELOC_390_PLT32DBL:
28099461Sobrien      return &elf_howto_table[(int) R_390_PLT32DBL];
28199461Sobrien    case BFD_RELOC_390_GOTPCDBL:
28299461Sobrien      return &elf_howto_table[(int) R_390_GOTPCDBL];
28399461Sobrien    case BFD_RELOC_64:
28499461Sobrien      return &elf_howto_table[(int) R_390_64];
28599461Sobrien    case BFD_RELOC_64_PCREL:
28699461Sobrien      return &elf_howto_table[(int) R_390_PC64];
28799461Sobrien    case BFD_RELOC_390_GOT64:
28899461Sobrien      return &elf_howto_table[(int) R_390_GOT64];
28999461Sobrien    case BFD_RELOC_390_PLT64:
29099461Sobrien      return &elf_howto_table[(int) R_390_PLT64];
29199461Sobrien    case BFD_RELOC_390_GOTENT:
29299461Sobrien      return &elf_howto_table[(int) R_390_GOTENT];
293130561Sobrien    case BFD_RELOC_16_GOTOFF:
294130561Sobrien      return &elf_howto_table[(int) R_390_GOTOFF16];
295130561Sobrien    case BFD_RELOC_390_GOTOFF64:
296130561Sobrien      return &elf_howto_table[(int) R_390_GOTOFF64];
297130561Sobrien    case BFD_RELOC_390_GOTPLT12:
298130561Sobrien      return &elf_howto_table[(int) R_390_GOTPLT12];
299130561Sobrien    case BFD_RELOC_390_GOTPLT16:
300130561Sobrien      return &elf_howto_table[(int) R_390_GOTPLT16];
301130561Sobrien    case BFD_RELOC_390_GOTPLT32:
302130561Sobrien      return &elf_howto_table[(int) R_390_GOTPLT32];
303130561Sobrien    case BFD_RELOC_390_GOTPLT64:
304130561Sobrien      return &elf_howto_table[(int) R_390_GOTPLT64];
305130561Sobrien    case BFD_RELOC_390_GOTPLTENT:
306130561Sobrien      return &elf_howto_table[(int) R_390_GOTPLTENT];
307130561Sobrien    case BFD_RELOC_390_PLTOFF16:
308130561Sobrien      return &elf_howto_table[(int) R_390_PLTOFF16];
309130561Sobrien    case BFD_RELOC_390_PLTOFF32:
310130561Sobrien      return &elf_howto_table[(int) R_390_PLTOFF32];
311130561Sobrien    case BFD_RELOC_390_PLTOFF64:
312130561Sobrien      return &elf_howto_table[(int) R_390_PLTOFF64];
313130561Sobrien    case BFD_RELOC_390_TLS_LOAD:
314130561Sobrien      return &elf_howto_table[(int) R_390_TLS_LOAD];
315130561Sobrien    case BFD_RELOC_390_TLS_GDCALL:
316130561Sobrien      return &elf_howto_table[(int) R_390_TLS_GDCALL];
317130561Sobrien    case BFD_RELOC_390_TLS_LDCALL:
318130561Sobrien      return &elf_howto_table[(int) R_390_TLS_LDCALL];
319130561Sobrien    case BFD_RELOC_390_TLS_GD64:
320130561Sobrien      return &elf_howto_table[(int) R_390_TLS_GD64];
321130561Sobrien    case BFD_RELOC_390_TLS_GOTIE12:
322130561Sobrien      return &elf_howto_table[(int) R_390_TLS_GOTIE12];
323130561Sobrien    case BFD_RELOC_390_TLS_GOTIE64:
324130561Sobrien      return &elf_howto_table[(int) R_390_TLS_GOTIE64];
325130561Sobrien    case BFD_RELOC_390_TLS_LDM64:
326130561Sobrien      return &elf_howto_table[(int) R_390_TLS_LDM64];
327130561Sobrien    case BFD_RELOC_390_TLS_IE64:
328130561Sobrien      return &elf_howto_table[(int) R_390_TLS_IE64];
329130561Sobrien    case BFD_RELOC_390_TLS_IEENT:
330130561Sobrien      return &elf_howto_table[(int) R_390_TLS_IEENT];
331130561Sobrien    case BFD_RELOC_390_TLS_LE64:
332130561Sobrien      return &elf_howto_table[(int) R_390_TLS_LE64];
333130561Sobrien    case BFD_RELOC_390_TLS_LDO64:
334130561Sobrien      return &elf_howto_table[(int) R_390_TLS_LDO64];
335130561Sobrien    case BFD_RELOC_390_TLS_DTPMOD:
336130561Sobrien      return &elf_howto_table[(int) R_390_TLS_DTPMOD];
337130561Sobrien    case BFD_RELOC_390_TLS_DTPOFF:
338130561Sobrien      return &elf_howto_table[(int) R_390_TLS_DTPOFF];
339130561Sobrien    case BFD_RELOC_390_TLS_TPOFF:
340130561Sobrien      return &elf_howto_table[(int) R_390_TLS_TPOFF];
341130561Sobrien    case BFD_RELOC_390_20:
342130561Sobrien      return &elf_howto_table[(int) R_390_20];
343130561Sobrien    case BFD_RELOC_390_GOT20:
344130561Sobrien      return &elf_howto_table[(int) R_390_GOT20];
345130561Sobrien    case BFD_RELOC_390_GOTPLT20:
346130561Sobrien      return &elf_howto_table[(int) R_390_GOTPLT20];
347130561Sobrien    case BFD_RELOC_390_TLS_GOTIE20:
348130561Sobrien      return &elf_howto_table[(int) R_390_TLS_GOTIE20];
349130561Sobrien    case BFD_RELOC_VTABLE_INHERIT:
350130561Sobrien      return &elf64_s390_vtinherit_howto;
351130561Sobrien    case BFD_RELOC_VTABLE_ENTRY:
352130561Sobrien      return &elf64_s390_vtentry_howto;
35399461Sobrien    default:
35499461Sobrien      break;
35599461Sobrien    }
35699461Sobrien  return 0;
35799461Sobrien}
35899461Sobrien
359218822Sdimstatic reloc_howto_type *
360218822Sdimelf_s390_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
361218822Sdim			    const char *r_name)
362218822Sdim{
363218822Sdim  unsigned int i;
364218822Sdim
365218822Sdim  for (i = 0;
366218822Sdim       i < sizeof (elf_howto_table) / sizeof (elf_howto_table[0]);
367218822Sdim       i++)
368218822Sdim    if (elf_howto_table[i].name != NULL
369218822Sdim	&& strcasecmp (elf_howto_table[i].name, r_name) == 0)
370218822Sdim      return &elf_howto_table[i];
371218822Sdim
372218822Sdim    if (strcasecmp (elf64_s390_vtinherit_howto.name, r_name) == 0)
373218822Sdim      return &elf64_s390_vtinherit_howto;
374218822Sdim    if (strcasecmp (elf64_s390_vtentry_howto.name, r_name) == 0)
375218822Sdim      return &elf64_s390_vtentry_howto;
376218822Sdim
377218822Sdim  return NULL;
378218822Sdim}
379218822Sdim
38099461Sobrien/* We need to use ELF64_R_TYPE so we have our own copy of this function,
38199461Sobrien   and elf64-s390.c has its own copy.  */
38299461Sobrien
38399461Sobrienstatic void
38499461Sobrienelf_s390_info_to_howto (abfd, cache_ptr, dst)
38599461Sobrien     bfd *abfd ATTRIBUTE_UNUSED;
38699461Sobrien     arelent *cache_ptr;
38799461Sobrien     Elf_Internal_Rela *dst;
38899461Sobrien{
389218822Sdim  unsigned int r_type = ELF64_R_TYPE(dst->r_info);
390218822Sdim  switch (r_type)
39199461Sobrien    {
39299461Sobrien    case R_390_GNU_VTINHERIT:
39399461Sobrien      cache_ptr->howto = &elf64_s390_vtinherit_howto;
39499461Sobrien      break;
39599461Sobrien
39699461Sobrien    case R_390_GNU_VTENTRY:
39799461Sobrien      cache_ptr->howto = &elf64_s390_vtentry_howto;
39899461Sobrien      break;
39999461Sobrien
40099461Sobrien    default:
401218822Sdim      if (r_type >= sizeof (elf_howto_table) / sizeof (elf_howto_table[0]))
402218822Sdim	{
403218822Sdim	  (*_bfd_error_handler) (_("%B: invalid relocation type %d"),
404218822Sdim				 abfd, (int) r_type);
405218822Sdim	  r_type = R_390_NONE;
406218822Sdim	}
407218822Sdim      cache_ptr->howto = &elf_howto_table[r_type];
40899461Sobrien    }
40999461Sobrien}
41099461Sobrien
411130561Sobrien/* A relocation function which doesn't do anything.  */
412130561Sobrienstatic bfd_reloc_status_type
413130561Sobriens390_tls_reloc (abfd, reloc_entry, symbol, data, input_section,
414130561Sobrien		output_bfd, error_message)
415130561Sobrien     bfd *abfd ATTRIBUTE_UNUSED;
416130561Sobrien     arelent *reloc_entry;
417130561Sobrien     asymbol *symbol ATTRIBUTE_UNUSED;
418130561Sobrien     PTR data ATTRIBUTE_UNUSED;
419130561Sobrien     asection *input_section;
420130561Sobrien     bfd *output_bfd;
421130561Sobrien     char **error_message ATTRIBUTE_UNUSED;
422130561Sobrien{
423130561Sobrien  if (output_bfd)
424130561Sobrien    reloc_entry->address += input_section->output_offset;
425130561Sobrien  return bfd_reloc_ok;
426130561Sobrien}
427130561Sobrien
428130561Sobrien/* Handle the large displacement relocs.  */
429130561Sobrienstatic bfd_reloc_status_type
430130561Sobriens390_elf_ldisp_reloc (abfd, reloc_entry, symbol, data, input_section,
431130561Sobrien                      output_bfd, error_message)
432130561Sobrien     bfd *abfd;
433130561Sobrien     arelent *reloc_entry;
434130561Sobrien     asymbol *symbol;
435130561Sobrien     PTR data;
436130561Sobrien     asection *input_section;
437130561Sobrien     bfd *output_bfd;
438130561Sobrien     char **error_message ATTRIBUTE_UNUSED;
439130561Sobrien{
440130561Sobrien  reloc_howto_type *howto = reloc_entry->howto;
441130561Sobrien  bfd_vma relocation;
442130561Sobrien  bfd_vma insn;
443130561Sobrien
444130561Sobrien  if (output_bfd != (bfd *) NULL
445130561Sobrien      && (symbol->flags & BSF_SECTION_SYM) == 0
446130561Sobrien      && (! howto->partial_inplace
447130561Sobrien	  || reloc_entry->addend == 0))
448130561Sobrien    {
449130561Sobrien      reloc_entry->address += input_section->output_offset;
450130561Sobrien      return bfd_reloc_ok;
451130561Sobrien    }
452130561Sobrien  if (output_bfd != NULL)
453130561Sobrien    return bfd_reloc_continue;
454130561Sobrien
455218822Sdim  if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
456130561Sobrien    return bfd_reloc_outofrange;
457130561Sobrien
458130561Sobrien  relocation = (symbol->value
459130561Sobrien		+ symbol->section->output_section->vma
460130561Sobrien		+ symbol->section->output_offset);
461130561Sobrien  relocation += reloc_entry->addend;
462130561Sobrien  if (howto->pc_relative)
463130561Sobrien    {
464130561Sobrien      relocation -= (input_section->output_section->vma
465130561Sobrien		     + input_section->output_offset);
466130561Sobrien      relocation -= reloc_entry->address;
467130561Sobrien    }
468130561Sobrien
469130561Sobrien  insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
470130561Sobrien  insn |= (relocation & 0xfff) << 16 | (relocation & 0xff000) >> 4;
471130561Sobrien  bfd_put_32 (abfd, insn, (bfd_byte *) data + reloc_entry->address);
472130561Sobrien
473130561Sobrien  if ((bfd_signed_vma) relocation < - 0x80000
474130561Sobrien      || (bfd_signed_vma) relocation > 0x7ffff)
475130561Sobrien    return bfd_reloc_overflow;
476130561Sobrien  else
477130561Sobrien    return bfd_reloc_ok;
478130561Sobrien}
479130561Sobrien
480130561Sobrienstatic bfd_boolean
48199461Sobrienelf_s390_is_local_label_name (abfd, name)
48299461Sobrien     bfd *abfd;
48399461Sobrien     const char *name;
48499461Sobrien{
48599461Sobrien  if (name[0] == '.' && (name[1] == 'X' || name[1] == 'L'))
486130561Sobrien    return TRUE;
48799461Sobrien
48899461Sobrien  return _bfd_elf_is_local_label_name (abfd, name);
48999461Sobrien}
49099461Sobrien
49199461Sobrien/* Functions for the 390 ELF linker.  */
49299461Sobrien
49399461Sobrien/* The name of the dynamic interpreter.  This is put in the .interp
49499461Sobrien   section.  */
49599461Sobrien
49699461Sobrien#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1"
49799461Sobrien
498130561Sobrien/* If ELIMINATE_COPY_RELOCS is non-zero, the linker will try to avoid
499130561Sobrien   copying dynamic variables from a shared lib into an app's dynbss
500130561Sobrien   section, and instead use a dynamic relocation to point into the
501130561Sobrien   shared lib.  */
502130561Sobrien#define ELIMINATE_COPY_RELOCS 1
503130561Sobrien
50499461Sobrien/* The size in bytes of the first entry in the procedure linkage table.  */
50599461Sobrien#define PLT_FIRST_ENTRY_SIZE 32
50699461Sobrien/* The size in bytes of an entry in the procedure linkage table.  */
50799461Sobrien#define PLT_ENTRY_SIZE 32
50899461Sobrien
50999461Sobrien#define GOT_ENTRY_SIZE 8
51099461Sobrien
51199461Sobrien/* The first three entries in a procedure linkage table are reserved,
51299461Sobrien   and the initial contents are unimportant (we zero them out).
51399461Sobrien   Subsequent entries look like this.  See the SVR4 ABI 386
51499461Sobrien   supplement to see how this works.  */
51599461Sobrien
51699461Sobrien/* For the s390, simple addr offset can only be 0 - 4096.
51799461Sobrien   To use the full 16777216 TB address space, several instructions
51899461Sobrien   are needed to load an address in a register and execute
51999461Sobrien   a branch( or just saving the address)
52099461Sobrien
52199461Sobrien   Furthermore, only r 0 and 1 are free to use!!!  */
52299461Sobrien
52399461Sobrien/* The first 3 words in the GOT are then reserved.
52499461Sobrien   Word 0 is the address of the dynamic table.
52599461Sobrien   Word 1 is a pointer to a structure describing the object
52699461Sobrien   Word 2 is used to point to the loader entry address.
52799461Sobrien
52899461Sobrien   The code for PLT entries looks like this:
52999461Sobrien
53099461Sobrien   The GOT holds the address in the PLT to be executed.
53199461Sobrien   The loader then gets:
53299461Sobrien   24(15) =  Pointer to the structure describing the object.
53399461Sobrien   28(15) =  Offset in symbol table
53499461Sobrien   The loader  must  then find the module where the function is
53599461Sobrien   and insert the address in the GOT.
53699461Sobrien
53799461Sobrien   PLT1: LARL 1,<fn>@GOTENT # 6 bytes  Load address of GOT entry in r1
53899461Sobrien         LG   1,0(1)      # 6 bytes  Load address from GOT in r1
53999461Sobrien         BCR  15,1        # 2 bytes  Jump to address
54099461Sobrien   RET1: BASR 1,0         # 2 bytes  Return from GOT 1st time
54199461Sobrien         LGF  1,12(1)     # 6 bytes  Load offset in symbl table in r1
54299461Sobrien         BRCL 15,-x       # 6 bytes  Jump to start of PLT
54399461Sobrien         .long ?          # 4 bytes  offset into symbol table
54499461Sobrien
54599461Sobrien   Total = 32 bytes per PLT entry
54699461Sobrien   Fixup at offset 2: relative address to GOT entry
54799461Sobrien   Fixup at offset 22: relative branch to PLT0
54899461Sobrien   Fixup at offset 28: 32 bit offset into symbol table
54999461Sobrien
55099461Sobrien   A 32 bit offset into the symbol table is enough. It allows for symbol
55199461Sobrien   tables up to a size of 2 gigabyte. A single dynamic object (the main
55299461Sobrien   program, any shared library) is limited to 4GB in size and I want to see
55399461Sobrien   the program that manages to have a symbol table of more than 2 GB with a
55499461Sobrien   total size of at max 4 GB.  */
55599461Sobrien
55699461Sobrien#define PLT_ENTRY_WORD0     (bfd_vma) 0xc0100000
55799461Sobrien#define PLT_ENTRY_WORD1     (bfd_vma) 0x0000e310
55899461Sobrien#define PLT_ENTRY_WORD2     (bfd_vma) 0x10000004
55999461Sobrien#define PLT_ENTRY_WORD3     (bfd_vma) 0x07f10d10
56099461Sobrien#define PLT_ENTRY_WORD4     (bfd_vma) 0xe310100c
56199461Sobrien#define PLT_ENTRY_WORD5     (bfd_vma) 0x0014c0f4
56299461Sobrien#define PLT_ENTRY_WORD6     (bfd_vma) 0x00000000
56399461Sobrien#define PLT_ENTRY_WORD7     (bfd_vma) 0x00000000
56499461Sobrien
56599461Sobrien/* The first PLT entry pushes the offset into the symbol table
56699461Sobrien   from R1 onto the stack at 8(15) and the loader object info
56799461Sobrien   at 12(15), loads the loader address in R1 and jumps to it.  */
56899461Sobrien
56999461Sobrien/* The first entry in the PLT:
57099461Sobrien
57199461Sobrien  PLT0:
57299461Sobrien     STG  1,56(15)  # r1 contains the offset into the symbol table
57399461Sobrien     LARL 1,_GLOBAL_OFFSET_TABLE # load address of global offset table
57499461Sobrien     MVC  48(8,15),8(1) # move loader ino (object struct address) to stack
57599461Sobrien     LG   1,16(1)   # get entry address of loader
57699461Sobrien     BCR  15,1      # jump to loader
57799461Sobrien
57899461Sobrien     Fixup at offset 8: relative address to start of GOT.  */
57999461Sobrien
58099461Sobrien#define PLT_FIRST_ENTRY_WORD0     (bfd_vma) 0xe310f038
58199461Sobrien#define PLT_FIRST_ENTRY_WORD1     (bfd_vma) 0x0024c010
58299461Sobrien#define PLT_FIRST_ENTRY_WORD2     (bfd_vma) 0x00000000
58399461Sobrien#define PLT_FIRST_ENTRY_WORD3     (bfd_vma) 0xd207f030
58499461Sobrien#define PLT_FIRST_ENTRY_WORD4     (bfd_vma) 0x1008e310
58599461Sobrien#define PLT_FIRST_ENTRY_WORD5     (bfd_vma) 0x10100004
58699461Sobrien#define PLT_FIRST_ENTRY_WORD6     (bfd_vma) 0x07f10700
58799461Sobrien#define PLT_FIRST_ENTRY_WORD7     (bfd_vma) 0x07000700
58899461Sobrien
58999461Sobrien/* The s390 linker needs to keep track of the number of relocs that it
59099461Sobrien   decides to copy as dynamic relocs in check_relocs for each symbol.
59199461Sobrien   This is so that it can later discard them if they are found to be
59299461Sobrien   unnecessary.  We store the information in a field extending the
59399461Sobrien   regular ELF linker hash table.  */
59499461Sobrien
59599461Sobrienstruct elf_s390_dyn_relocs
59699461Sobrien{
59799461Sobrien  struct elf_s390_dyn_relocs *next;
59899461Sobrien
59999461Sobrien  /* The input section of the reloc.  */
60099461Sobrien  asection *sec;
60199461Sobrien
60299461Sobrien  /* Total number of relocs copied for the input section.  */
60399461Sobrien  bfd_size_type count;
60499461Sobrien
60599461Sobrien  /* Number of pc-relative relocs copied for the input section.  */
60699461Sobrien  bfd_size_type pc_count;
60799461Sobrien};
60899461Sobrien
60999461Sobrien/* s390 ELF linker hash entry.  */
61099461Sobrien
61199461Sobrienstruct elf_s390_link_hash_entry
61299461Sobrien{
61399461Sobrien  struct elf_link_hash_entry elf;
61499461Sobrien
61599461Sobrien  /* Track dynamic relocs copied for this symbol.  */
61699461Sobrien  struct elf_s390_dyn_relocs *dyn_relocs;
617130561Sobrien
618130561Sobrien  /* Number of GOTPLT references for a function.  */
619130561Sobrien  bfd_signed_vma gotplt_refcount;
620130561Sobrien
621130561Sobrien#define GOT_UNKNOWN	0
622130561Sobrien#define GOT_NORMAL	1
623130561Sobrien#define GOT_TLS_GD	2
624130561Sobrien#define GOT_TLS_IE	3
625130561Sobrien#define GOT_TLS_IE_NLT	3
626130561Sobrien  unsigned char tls_type;
62799461Sobrien};
62899461Sobrien
629130561Sobrien#define elf_s390_hash_entry(ent) \
630130561Sobrien  ((struct elf_s390_link_hash_entry *)(ent))
631130561Sobrien
632130561Sobrienstruct elf_s390_obj_tdata
633130561Sobrien{
634130561Sobrien  struct elf_obj_tdata root;
635130561Sobrien
636130561Sobrien  /* tls_type for each local got entry.  */
637130561Sobrien  char *local_got_tls_type;
638130561Sobrien};
639130561Sobrien
640130561Sobrien#define elf_s390_tdata(abfd) \
641130561Sobrien  ((struct elf_s390_obj_tdata *) (abfd)->tdata.any)
642130561Sobrien
643130561Sobrien#define elf_s390_local_got_tls_type(abfd) \
644130561Sobrien  (elf_s390_tdata (abfd)->local_got_tls_type)
645130561Sobrien
646130561Sobrienstatic bfd_boolean
647218822Sdimelf_s390_mkobject (bfd *abfd)
648130561Sobrien{
649130561Sobrien  if (abfd->tdata.any == NULL)
650218822Sdim    {
651218822Sdim      bfd_size_type amt = sizeof (struct elf_s390_obj_tdata);
652218822Sdim      abfd->tdata.any = bfd_zalloc (abfd, amt);
653218822Sdim      if (abfd->tdata.any == NULL)
654218822Sdim	return FALSE;
655218822Sdim    }
656218822Sdim  return bfd_elf_mkobject (abfd);
657130561Sobrien}
658130561Sobrien
659130561Sobrienstatic bfd_boolean
660130561Sobrienelf_s390_object_p (abfd)
661130561Sobrien     bfd *abfd;
662130561Sobrien{
663130561Sobrien  /* Set the right machine number for an s390 elf32 file.  */
664130561Sobrien  return bfd_default_set_arch_mach (abfd, bfd_arch_s390, bfd_mach_s390_64);
665130561Sobrien}
666130561Sobrien
66799461Sobrien/* s390 ELF linker hash table.  */
66899461Sobrien
66999461Sobrienstruct elf_s390_link_hash_table
67099461Sobrien{
67199461Sobrien  struct elf_link_hash_table elf;
67299461Sobrien
67399461Sobrien  /* Short-cuts to get to dynamic linker sections.  */
67499461Sobrien  asection *sgot;
67599461Sobrien  asection *sgotplt;
67699461Sobrien  asection *srelgot;
67799461Sobrien  asection *splt;
67899461Sobrien  asection *srelplt;
67999461Sobrien  asection *sdynbss;
68099461Sobrien  asection *srelbss;
68199461Sobrien
682130561Sobrien  union {
683130561Sobrien    bfd_signed_vma refcount;
684130561Sobrien    bfd_vma offset;
685130561Sobrien  } tls_ldm_got;
686130561Sobrien
68799461Sobrien  /* Small local sym to section mapping cache.  */
68899461Sobrien  struct sym_sec_cache sym_sec;
68999461Sobrien};
69099461Sobrien
69199461Sobrien/* Get the s390 ELF linker hash table from a link_info structure.  */
69299461Sobrien
69399461Sobrien#define elf_s390_hash_table(p) \
69499461Sobrien  ((struct elf_s390_link_hash_table *) ((p)->hash))
69599461Sobrien
69699461Sobrien/* Create an entry in an s390 ELF linker hash table.  */
69799461Sobrien
69899461Sobrienstatic struct bfd_hash_entry *
69999461Sobrienlink_hash_newfunc (entry, table, string)
70099461Sobrien     struct bfd_hash_entry *entry;
70199461Sobrien     struct bfd_hash_table *table;
70299461Sobrien     const char *string;
70399461Sobrien{
70499461Sobrien  /* Allocate the structure if it has not already been allocated by a
70599461Sobrien     subclass.  */
70699461Sobrien  if (entry == NULL)
70799461Sobrien    {
70899461Sobrien      entry = bfd_hash_allocate (table,
70999461Sobrien				 sizeof (struct elf_s390_link_hash_entry));
71099461Sobrien      if (entry == NULL)
71199461Sobrien	return entry;
71299461Sobrien    }
71399461Sobrien
71499461Sobrien  /* Call the allocation method of the superclass.  */
71599461Sobrien  entry = _bfd_elf_link_hash_newfunc (entry, table, string);
71699461Sobrien  if (entry != NULL)
71799461Sobrien    {
71899461Sobrien      struct elf_s390_link_hash_entry *eh;
71999461Sobrien
72099461Sobrien      eh = (struct elf_s390_link_hash_entry *) entry;
72199461Sobrien      eh->dyn_relocs = NULL;
722130561Sobrien      eh->gotplt_refcount = 0;
723130561Sobrien      eh->tls_type = GOT_UNKNOWN;
72499461Sobrien    }
72599461Sobrien
72699461Sobrien  return entry;
72799461Sobrien}
72899461Sobrien
72999461Sobrien/* Create an s390 ELF linker hash table.  */
73099461Sobrien
73199461Sobrienstatic struct bfd_link_hash_table *
73299461Sobrienelf_s390_link_hash_table_create (abfd)
73399461Sobrien     bfd *abfd;
73499461Sobrien{
73599461Sobrien  struct elf_s390_link_hash_table *ret;
73699461Sobrien  bfd_size_type amt = sizeof (struct elf_s390_link_hash_table);
73799461Sobrien
738107492Sobrien  ret = (struct elf_s390_link_hash_table *) bfd_malloc (amt);
73999461Sobrien  if (ret == NULL)
74099461Sobrien    return NULL;
74199461Sobrien
742218822Sdim  if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd, link_hash_newfunc,
743218822Sdim				      sizeof (struct elf_s390_link_hash_entry)))
74499461Sobrien    {
745107492Sobrien      free (ret);
74699461Sobrien      return NULL;
74799461Sobrien    }
74899461Sobrien
74999461Sobrien  ret->sgot = NULL;
75099461Sobrien  ret->sgotplt = NULL;
75199461Sobrien  ret->srelgot = NULL;
75299461Sobrien  ret->splt = NULL;
75399461Sobrien  ret->srelplt = NULL;
75499461Sobrien  ret->sdynbss = NULL;
75599461Sobrien  ret->srelbss = NULL;
756130561Sobrien  ret->tls_ldm_got.refcount = 0;
75799461Sobrien  ret->sym_sec.abfd = NULL;
75899461Sobrien
75999461Sobrien  return &ret->elf.root;
76099461Sobrien}
76199461Sobrien
76299461Sobrien/* Create .got, .gotplt, and .rela.got sections in DYNOBJ, and set up
76399461Sobrien   shortcuts to them in our hash table.  */
76499461Sobrien
765130561Sobrienstatic bfd_boolean
76699461Sobriencreate_got_section (dynobj, info)
76799461Sobrien     bfd *dynobj;
76899461Sobrien     struct bfd_link_info *info;
76999461Sobrien{
77099461Sobrien  struct elf_s390_link_hash_table *htab;
77199461Sobrien
77299461Sobrien  if (! _bfd_elf_create_got_section (dynobj, info))
773130561Sobrien    return FALSE;
77499461Sobrien
77599461Sobrien  htab = elf_s390_hash_table (info);
77699461Sobrien  htab->sgot = bfd_get_section_by_name (dynobj, ".got");
77799461Sobrien  htab->sgotplt = bfd_get_section_by_name (dynobj, ".got.plt");
77899461Sobrien  if (!htab->sgot || !htab->sgotplt)
77999461Sobrien    abort ();
78099461Sobrien
781218822Sdim  htab->srelgot = bfd_make_section_with_flags (dynobj, ".rela.got",
782218822Sdim					       (SEC_ALLOC | SEC_LOAD
783218822Sdim						| SEC_HAS_CONTENTS
784218822Sdim						| SEC_IN_MEMORY
785218822Sdim						| SEC_LINKER_CREATED
786218822Sdim						| SEC_READONLY));
78799461Sobrien  if (htab->srelgot == NULL
788107492Sobrien      || ! bfd_set_section_alignment (dynobj, htab->srelgot, 3))
789130561Sobrien    return FALSE;
790130561Sobrien  return TRUE;
79199461Sobrien}
79299461Sobrien
79399461Sobrien/* Create .plt, .rela.plt, .got, .got.plt, .rela.got, .dynbss, and
79499461Sobrien   .rela.bss sections in DYNOBJ, and set up shortcuts to them in our
79599461Sobrien   hash table.  */
79699461Sobrien
797130561Sobrienstatic bfd_boolean
79899461Sobrienelf_s390_create_dynamic_sections (dynobj, info)
79999461Sobrien     bfd *dynobj;
80099461Sobrien     struct bfd_link_info *info;
80199461Sobrien{
80299461Sobrien  struct elf_s390_link_hash_table *htab;
80399461Sobrien
80499461Sobrien  htab = elf_s390_hash_table (info);
80599461Sobrien  if (!htab->sgot && !create_got_section (dynobj, info))
806130561Sobrien    return FALSE;
80799461Sobrien
80899461Sobrien  if (!_bfd_elf_create_dynamic_sections (dynobj, info))
809130561Sobrien    return FALSE;
81099461Sobrien
81199461Sobrien  htab->splt = bfd_get_section_by_name (dynobj, ".plt");
81299461Sobrien  htab->srelplt = bfd_get_section_by_name (dynobj, ".rela.plt");
81399461Sobrien  htab->sdynbss = bfd_get_section_by_name (dynobj, ".dynbss");
81499461Sobrien  if (!info->shared)
81599461Sobrien    htab->srelbss = bfd_get_section_by_name (dynobj, ".rela.bss");
81699461Sobrien
81799461Sobrien  if (!htab->splt || !htab->srelplt || !htab->sdynbss
81899461Sobrien      || (!info->shared && !htab->srelbss))
81999461Sobrien    abort ();
82099461Sobrien
821130561Sobrien  return TRUE;
82299461Sobrien}
82399461Sobrien
82499461Sobrien/* Copy the extra info we tack onto an elf_link_hash_entry.  */
82599461Sobrien
82699461Sobrienstatic void
827218822Sdimelf_s390_copy_indirect_symbol (info, dir, ind)
828218822Sdim     struct bfd_link_info *info;
82999461Sobrien     struct elf_link_hash_entry *dir, *ind;
83099461Sobrien{
83199461Sobrien  struct elf_s390_link_hash_entry *edir, *eind;
83299461Sobrien
83399461Sobrien  edir = (struct elf_s390_link_hash_entry *) dir;
83499461Sobrien  eind = (struct elf_s390_link_hash_entry *) ind;
83599461Sobrien
83699461Sobrien  if (eind->dyn_relocs != NULL)
83799461Sobrien    {
83899461Sobrien      if (edir->dyn_relocs != NULL)
83999461Sobrien	{
84099461Sobrien	  struct elf_s390_dyn_relocs **pp;
84199461Sobrien	  struct elf_s390_dyn_relocs *p;
84299461Sobrien
843218822Sdim	  /* Add reloc counts against the indirect sym to the direct sym
84499461Sobrien	     list.  Merge any entries against the same section.  */
84599461Sobrien	  for (pp = &eind->dyn_relocs; (p = *pp) != NULL; )
84699461Sobrien	    {
84799461Sobrien	      struct elf_s390_dyn_relocs *q;
84899461Sobrien
84999461Sobrien	      for (q = edir->dyn_relocs; q != NULL; q = q->next)
85099461Sobrien		if (q->sec == p->sec)
85199461Sobrien		  {
85299461Sobrien		    q->pc_count += p->pc_count;
85399461Sobrien		    q->count += p->count;
85499461Sobrien		    *pp = p->next;
85599461Sobrien		    break;
85699461Sobrien		  }
85799461Sobrien	      if (q == NULL)
85899461Sobrien		pp = &p->next;
85999461Sobrien	    }
86099461Sobrien	  *pp = edir->dyn_relocs;
86199461Sobrien	}
86299461Sobrien
86399461Sobrien      edir->dyn_relocs = eind->dyn_relocs;
86499461Sobrien      eind->dyn_relocs = NULL;
86599461Sobrien    }
86699461Sobrien
867130561Sobrien  if (ind->root.type == bfd_link_hash_indirect
868130561Sobrien      && dir->got.refcount <= 0)
869130561Sobrien    {
870130561Sobrien      edir->tls_type = eind->tls_type;
871130561Sobrien      eind->tls_type = GOT_UNKNOWN;
872130561Sobrien    }
873130561Sobrien
874130561Sobrien  if (ELIMINATE_COPY_RELOCS
875130561Sobrien      && ind->root.type != bfd_link_hash_indirect
876218822Sdim      && dir->dynamic_adjusted)
877218822Sdim    {
878218822Sdim      /* If called to transfer flags for a weakdef during processing
879218822Sdim	 of elf_adjust_dynamic_symbol, don't copy non_got_ref.
880218822Sdim	 We clear it ourselves for ELIMINATE_COPY_RELOCS.  */
881218822Sdim      dir->ref_dynamic |= ind->ref_dynamic;
882218822Sdim      dir->ref_regular |= ind->ref_regular;
883218822Sdim      dir->ref_regular_nonweak |= ind->ref_regular_nonweak;
884218822Sdim      dir->needs_plt |= ind->needs_plt;
885218822Sdim    }
886130561Sobrien  else
887218822Sdim    _bfd_elf_link_hash_copy_indirect (info, dir, ind);
88899461Sobrien}
88999461Sobrien
890130561Sobrienstatic int
891130561Sobrienelf_s390_tls_transition (info, r_type, is_local)
892130561Sobrien     struct bfd_link_info *info;
893130561Sobrien     int r_type;
894130561Sobrien     int is_local;
895130561Sobrien{
896130561Sobrien  if (info->shared)
897130561Sobrien    return r_type;
898130561Sobrien
899130561Sobrien  switch (r_type)
900130561Sobrien    {
901130561Sobrien    case R_390_TLS_GD64:
902130561Sobrien    case R_390_TLS_IE64:
903130561Sobrien      if (is_local)
904130561Sobrien	return R_390_TLS_LE64;
905130561Sobrien      return R_390_TLS_IE64;
906130561Sobrien    case R_390_TLS_GOTIE64:
907130561Sobrien      if (is_local)
908130561Sobrien	return R_390_TLS_LE64;
909130561Sobrien      return R_390_TLS_GOTIE64;
910130561Sobrien    case R_390_TLS_LDM64:
911130561Sobrien      return R_390_TLS_LE64;
912130561Sobrien    }
913130561Sobrien
914130561Sobrien  return r_type;
915130561Sobrien}
916130561Sobrien
91799461Sobrien/* Look through the relocs for a section during the first phase, and
91899461Sobrien   allocate space in the global offset table or procedure linkage
91999461Sobrien   table.  */
92099461Sobrien
921130561Sobrienstatic bfd_boolean
92299461Sobrienelf_s390_check_relocs (abfd, info, sec, relocs)
92399461Sobrien     bfd *abfd;
92499461Sobrien     struct bfd_link_info *info;
92599461Sobrien     asection *sec;
92699461Sobrien     const Elf_Internal_Rela *relocs;
92799461Sobrien{
92899461Sobrien  struct elf_s390_link_hash_table *htab;
92999461Sobrien  Elf_Internal_Shdr *symtab_hdr;
93099461Sobrien  struct elf_link_hash_entry **sym_hashes;
93199461Sobrien  const Elf_Internal_Rela *rel;
93299461Sobrien  const Elf_Internal_Rela *rel_end;
93399461Sobrien  asection *sreloc;
934130561Sobrien  bfd_signed_vma *local_got_refcounts;
935130561Sobrien  int tls_type, old_tls_type;
93699461Sobrien
937130561Sobrien  if (info->relocatable)
938130561Sobrien    return TRUE;
93999461Sobrien
94099461Sobrien  htab = elf_s390_hash_table (info);
94199461Sobrien  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
94299461Sobrien  sym_hashes = elf_sym_hashes (abfd);
943130561Sobrien  local_got_refcounts = elf_local_got_refcounts (abfd);
94499461Sobrien
94599461Sobrien  sreloc = NULL;
94699461Sobrien
94799461Sobrien  rel_end = relocs + sec->reloc_count;
94899461Sobrien  for (rel = relocs; rel < rel_end; rel++)
94999461Sobrien    {
950130561Sobrien      unsigned int r_type;
95199461Sobrien      unsigned long r_symndx;
95299461Sobrien      struct elf_link_hash_entry *h;
95399461Sobrien
95499461Sobrien      r_symndx = ELF64_R_SYM (rel->r_info);
95599461Sobrien
95699461Sobrien      if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr))
95799461Sobrien	{
958218822Sdim	  (*_bfd_error_handler) (_("%B: bad symbol index: %d"),
959218822Sdim				 abfd,
96099461Sobrien				 r_symndx);
961130561Sobrien	  return FALSE;
96299461Sobrien	}
96399461Sobrien
96499461Sobrien      if (r_symndx < symtab_hdr->sh_info)
96599461Sobrien	h = NULL;
96699461Sobrien      else
967218822Sdim	{
968218822Sdim	  h = sym_hashes[r_symndx - symtab_hdr->sh_info];
969218822Sdim	  while (h->root.type == bfd_link_hash_indirect
970218822Sdim		 || h->root.type == bfd_link_hash_warning)
971218822Sdim	    h = (struct elf_link_hash_entry *) h->root.u.i.link;
972218822Sdim	}
97399461Sobrien
974130561Sobrien      /* Create got section and local_got_refcounts array if they
975130561Sobrien	 are needed.  */
976130561Sobrien      r_type = elf_s390_tls_transition (info,
977130561Sobrien					ELF64_R_TYPE (rel->r_info),
978130561Sobrien					h == NULL);
979130561Sobrien      switch (r_type)
98099461Sobrien	{
98199461Sobrien	case R_390_GOT12:
982130561Sobrien	case R_390_GOT16:
983130561Sobrien	case R_390_GOT20:
98499461Sobrien	case R_390_GOT32:
98599461Sobrien	case R_390_GOT64:
98699461Sobrien	case R_390_GOTENT:
987130561Sobrien	case R_390_GOTPLT12:
988130561Sobrien	case R_390_GOTPLT16:
989130561Sobrien	case R_390_GOTPLT20:
990130561Sobrien	case R_390_GOTPLT32:
991130561Sobrien	case R_390_GOTPLT64:
992130561Sobrien	case R_390_GOTPLTENT:
993130561Sobrien	case R_390_TLS_GD64:
994130561Sobrien	case R_390_TLS_GOTIE12:
995130561Sobrien	case R_390_TLS_GOTIE20:
996130561Sobrien	case R_390_TLS_GOTIE64:
997130561Sobrien	case R_390_TLS_IEENT:
998130561Sobrien	case R_390_TLS_IE64:
999130561Sobrien	case R_390_TLS_LDM64:
1000130561Sobrien	  if (h == NULL
1001130561Sobrien	      && local_got_refcounts == NULL)
100299461Sobrien	    {
1003130561Sobrien	      bfd_size_type size;
100499461Sobrien
1005130561Sobrien	      size = symtab_hdr->sh_info;
1006130561Sobrien	      size *= (sizeof (bfd_signed_vma) + sizeof(char));
1007130561Sobrien	      local_got_refcounts = ((bfd_signed_vma *)
1008130561Sobrien				     bfd_zalloc (abfd, size));
100999461Sobrien	      if (local_got_refcounts == NULL)
1010130561Sobrien		return FALSE;
1011130561Sobrien	      elf_local_got_refcounts (abfd) = local_got_refcounts;
1012130561Sobrien	      elf_s390_local_got_tls_type (abfd)
1013130561Sobrien		= (char *) (local_got_refcounts + symtab_hdr->sh_info);
101499461Sobrien	    }
1015130561Sobrien	  /* Fall through.  */
1016130561Sobrien	case R_390_GOTOFF16:
1017130561Sobrien	case R_390_GOTOFF32:
1018130561Sobrien	case R_390_GOTOFF64:
101999461Sobrien	case R_390_GOTPC:
102099461Sobrien	case R_390_GOTPCDBL:
102199461Sobrien	  if (htab->sgot == NULL)
102299461Sobrien	    {
102399461Sobrien	      if (htab->elf.dynobj == NULL)
102499461Sobrien		htab->elf.dynobj = abfd;
102599461Sobrien	      if (!create_got_section (htab->elf.dynobj, info))
1026130561Sobrien		return FALSE;
102799461Sobrien	    }
1028130561Sobrien	}
1029130561Sobrien
1030130561Sobrien      switch (r_type)
1031130561Sobrien	{
1032130561Sobrien	case R_390_GOTOFF16:
1033130561Sobrien	case R_390_GOTOFF32:
1034130561Sobrien	case R_390_GOTOFF64:
1035130561Sobrien	case R_390_GOTPC:
1036130561Sobrien	case R_390_GOTPCDBL:
1037130561Sobrien	  /* Got is created, nothing to be done.  */
103899461Sobrien	  break;
103999461Sobrien
1040130561Sobrien	case R_390_PLT16DBL:
104199461Sobrien	case R_390_PLT32:
104299461Sobrien	case R_390_PLT32DBL:
104399461Sobrien	case R_390_PLT64:
1044130561Sobrien	case R_390_PLTOFF16:
1045130561Sobrien	case R_390_PLTOFF32:
1046130561Sobrien	case R_390_PLTOFF64:
104799461Sobrien	  /* This symbol requires a procedure linkage table entry.  We
1048130561Sobrien	     actually build the entry in adjust_dynamic_symbol,
1049130561Sobrien	     because this might be a case of linking PIC code which is
1050130561Sobrien	     never referenced by a dynamic object, in which case we
1051130561Sobrien	     don't need to generate a procedure linkage table entry
1052130561Sobrien	     after all.  */
105399461Sobrien
105499461Sobrien	  /* If this is a local symbol, we resolve it directly without
1055130561Sobrien	     creating a procedure linkage table entry.  */
1056130561Sobrien	  if (h != NULL)
1057130561Sobrien	    {
1058218822Sdim	      h->needs_plt = 1;
1059130561Sobrien	      h->plt.refcount += 1;
1060130561Sobrien	    }
1061130561Sobrien	  break;
106299461Sobrien
1063130561Sobrien	case R_390_GOTPLT12:
1064130561Sobrien	case R_390_GOTPLT16:
1065130561Sobrien	case R_390_GOTPLT20:
1066130561Sobrien	case R_390_GOTPLT32:
1067130561Sobrien	case R_390_GOTPLT64:
1068130561Sobrien	case R_390_GOTPLTENT:
1069130561Sobrien	  /* This symbol requires either a procedure linkage table entry
1070130561Sobrien	     or an entry in the local got. We actually build the entry
1071130561Sobrien	     in adjust_dynamic_symbol because whether this is really a
1072130561Sobrien	     global reference can change and with it the fact if we have
1073130561Sobrien	     to create a plt entry or a local got entry. To be able to
1074130561Sobrien	     make a once global symbol a local one we have to keep track
1075130561Sobrien	     of the number of gotplt references that exist for this
1076130561Sobrien	     symbol.  */
1077130561Sobrien	  if (h != NULL)
1078130561Sobrien	    {
1079130561Sobrien	      ((struct elf_s390_link_hash_entry *) h)->gotplt_refcount++;
1080218822Sdim	      h->needs_plt = 1;
1081130561Sobrien	      h->plt.refcount += 1;
1082130561Sobrien	    }
1083130561Sobrien	  else
1084130561Sobrien	    local_got_refcounts[r_symndx] += 1;
108599461Sobrien	  break;
108699461Sobrien
1087130561Sobrien	case R_390_TLS_LDM64:
1088130561Sobrien	  htab->tls_ldm_got.refcount += 1;
1089130561Sobrien	  break;
1090130561Sobrien
1091130561Sobrien	case R_390_TLS_IE64:
1092130561Sobrien	case R_390_TLS_GOTIE12:
1093130561Sobrien	case R_390_TLS_GOTIE20:
1094130561Sobrien	case R_390_TLS_GOTIE64:
1095130561Sobrien	case R_390_TLS_IEENT:
1096130561Sobrien	  if (info->shared)
1097130561Sobrien	    info->flags |= DF_STATIC_TLS;
1098130561Sobrien	  /* Fall through */
1099130561Sobrien
1100130561Sobrien	case R_390_GOT12:
1101130561Sobrien	case R_390_GOT16:
1102130561Sobrien	case R_390_GOT20:
1103130561Sobrien	case R_390_GOT32:
1104130561Sobrien	case R_390_GOT64:
1105130561Sobrien	case R_390_GOTENT:
1106130561Sobrien	case R_390_TLS_GD64:
1107130561Sobrien	  /* This symbol requires a global offset table entry.  */
1108130561Sobrien	  switch (r_type)
1109130561Sobrien	    {
1110130561Sobrien	    default:
1111130561Sobrien	    case R_390_GOT12:
1112130561Sobrien	    case R_390_GOT16:
1113130561Sobrien	    case R_390_GOT20:
1114130561Sobrien	    case R_390_GOT32:
1115130561Sobrien	    case R_390_GOTENT:
1116130561Sobrien	      tls_type = GOT_NORMAL;
1117130561Sobrien	      break;
1118130561Sobrien	    case R_390_TLS_GD64:
1119130561Sobrien	      tls_type = GOT_TLS_GD;
1120130561Sobrien	      break;
1121130561Sobrien	    case R_390_TLS_IE64:
1122130561Sobrien	    case R_390_TLS_GOTIE64:
1123130561Sobrien	      tls_type = GOT_TLS_IE;
1124130561Sobrien	      break;
1125130561Sobrien	    case R_390_TLS_GOTIE12:
1126130561Sobrien	    case R_390_TLS_GOTIE20:
1127130561Sobrien	    case R_390_TLS_IEENT:
1128130561Sobrien	      tls_type = GOT_TLS_IE_NLT;
1129130561Sobrien	      break;
1130130561Sobrien	    }
1131130561Sobrien
1132130561Sobrien	  if (h != NULL)
1133130561Sobrien	    {
1134130561Sobrien	      h->got.refcount += 1;
1135130561Sobrien	      old_tls_type = elf_s390_hash_entry(h)->tls_type;
1136130561Sobrien	    }
1137130561Sobrien	  else
1138130561Sobrien	    {
1139130561Sobrien	      local_got_refcounts[r_symndx] += 1;
1140130561Sobrien	      old_tls_type = elf_s390_local_got_tls_type (abfd) [r_symndx];
1141130561Sobrien	    }
1142130561Sobrien	  /* If a TLS symbol is accessed using IE at least once,
1143130561Sobrien	     there is no point to use dynamic model for it.  */
1144130561Sobrien	  if (old_tls_type != tls_type && old_tls_type != GOT_UNKNOWN)
1145130561Sobrien	    {
1146130561Sobrien	      if (old_tls_type == GOT_NORMAL || tls_type == GOT_NORMAL)
1147130561Sobrien		{
1148130561Sobrien		  (*_bfd_error_handler)
1149218822Sdim		    (_("%B: `%s' accessed both as normal and thread local symbol"),
1150218822Sdim		     abfd, h->root.root.string);
1151130561Sobrien		  return FALSE;
1152130561Sobrien		}
1153130561Sobrien	      if (old_tls_type > tls_type)
1154130561Sobrien		tls_type = old_tls_type;
1155130561Sobrien	    }
1156130561Sobrien
1157130561Sobrien	  if (old_tls_type != tls_type)
1158130561Sobrien	    {
1159130561Sobrien	      if (h != NULL)
1160130561Sobrien		elf_s390_hash_entry (h)->tls_type = tls_type;
1161130561Sobrien	      else
1162130561Sobrien		elf_s390_local_got_tls_type (abfd) [r_symndx] = tls_type;
1163130561Sobrien	    }
1164130561Sobrien
1165130561Sobrien	  if (r_type != R_390_TLS_IE64)
1166130561Sobrien	    break;
1167130561Sobrien	  /* Fall through */
1168130561Sobrien
1169130561Sobrien	case R_390_TLS_LE64:
1170130561Sobrien	  if (!info->shared)
1171130561Sobrien	    break;
1172130561Sobrien	  info->flags |= DF_STATIC_TLS;
1173130561Sobrien	  /* Fall through */
1174130561Sobrien
1175130561Sobrien	case R_390_8:
1176130561Sobrien	case R_390_16:
117799461Sobrien	case R_390_32:
117899461Sobrien	case R_390_64:
1179130561Sobrien	case R_390_PC16:
1180130561Sobrien	case R_390_PC16DBL:
118199461Sobrien	case R_390_PC32:
118299461Sobrien	case R_390_PC32DBL:
118399461Sobrien	case R_390_PC64:
118499461Sobrien	  if (h != NULL && !info->shared)
118599461Sobrien	    {
118699461Sobrien	      /* If this reloc is in a read-only section, we might
118799461Sobrien		 need a copy reloc.  We can't check reliably at this
118899461Sobrien		 stage whether the section is read-only, as input
118999461Sobrien		 sections have not yet been mapped to output sections.
119099461Sobrien		 Tentatively set the flag for now, and correct in
119199461Sobrien		 adjust_dynamic_symbol.  */
1192218822Sdim	      h->non_got_ref = 1;
119399461Sobrien
119499461Sobrien	      /* We may need a .plt entry if the function this reloc
119599461Sobrien		 refers to is in a shared lib.  */
119699461Sobrien	      h->plt.refcount += 1;
119799461Sobrien	    }
119899461Sobrien
119999461Sobrien	  /* If we are creating a shared library, and this is a reloc
120099461Sobrien	     against a global symbol, or a non PC relative reloc
120199461Sobrien	     against a local symbol, then we need to copy the reloc
120299461Sobrien	     into the shared library.  However, if we are linking with
120399461Sobrien	     -Bsymbolic, we do not need to copy a reloc against a
120499461Sobrien	     global symbol which is defined in an object we are
120599461Sobrien	     including in the link (i.e., DEF_REGULAR is set).  At
120699461Sobrien	     this point we have not seen all the input files, so it is
120799461Sobrien	     possible that DEF_REGULAR is not set now but will be set
120899461Sobrien	     later (it is never cleared).  In case of a weak definition,
120999461Sobrien	     DEF_REGULAR may be cleared later by a strong definition in
121099461Sobrien	     a shared library. We account for that possibility below by
121199461Sobrien	     storing information in the relocs_copied field of the hash
121299461Sobrien	     table entry.  A similar situation occurs when creating
121399461Sobrien	     shared libraries and symbol visibility changes render the
121499461Sobrien	     symbol local.
121599461Sobrien
121699461Sobrien	     If on the other hand, we are creating an executable, we
121799461Sobrien	     may need to keep relocations for symbols satisfied by a
121899461Sobrien	     dynamic library if we manage to avoid copy relocs for the
121999461Sobrien	     symbol.  */
122099461Sobrien	  if ((info->shared
122199461Sobrien	       && (sec->flags & SEC_ALLOC) != 0
122299461Sobrien	       && ((ELF64_R_TYPE (rel->r_info) != R_390_PC16
122399461Sobrien		    && ELF64_R_TYPE (rel->r_info) != R_390_PC16DBL
122499461Sobrien		    && ELF64_R_TYPE (rel->r_info) != R_390_PC32
122599461Sobrien		    && ELF64_R_TYPE (rel->r_info) != R_390_PC32DBL
122699461Sobrien		    && ELF64_R_TYPE (rel->r_info) != R_390_PC64)
122799461Sobrien		   || (h != NULL
122899461Sobrien		       && (! info->symbolic
122999461Sobrien			   || h->root.type == bfd_link_hash_defweak
1230218822Sdim			   || !h->def_regular))))
1231130561Sobrien	      || (ELIMINATE_COPY_RELOCS
1232130561Sobrien		  && !info->shared
123399461Sobrien		  && (sec->flags & SEC_ALLOC) != 0
123499461Sobrien		  && h != NULL
123599461Sobrien		  && (h->root.type == bfd_link_hash_defweak
1236218822Sdim		      || !h->def_regular)))
123799461Sobrien	    {
123899461Sobrien	      struct elf_s390_dyn_relocs *p;
123999461Sobrien	      struct elf_s390_dyn_relocs **head;
124099461Sobrien
124199461Sobrien	      /* We must copy these reloc types into the output file.
124299461Sobrien		 Create a reloc section in dynobj and make room for
124399461Sobrien		 this reloc.  */
124499461Sobrien	      if (sreloc == NULL)
124599461Sobrien		{
124699461Sobrien		  const char *name;
124799461Sobrien		  bfd *dynobj;
124899461Sobrien
124999461Sobrien		  name = (bfd_elf_string_from_elf_section
125099461Sobrien			  (abfd,
125199461Sobrien			   elf_elfheader (abfd)->e_shstrndx,
125299461Sobrien			   elf_section_data (sec)->rel_hdr.sh_name));
125399461Sobrien		  if (name == NULL)
1254130561Sobrien		    return FALSE;
125599461Sobrien
1256218822Sdim		  if (! CONST_STRNEQ (name, ".rela")
125799461Sobrien		      || strcmp (bfd_get_section_name (abfd, sec),
125899461Sobrien				 name + 5) != 0)
125999461Sobrien		    {
126099461Sobrien		      (*_bfd_error_handler)
1261218822Sdim			(_("%B: bad relocation section name `%s\'"),
1262218822Sdim			 abfd, name);
126399461Sobrien		    }
126499461Sobrien
126599461Sobrien		  if (htab->elf.dynobj == NULL)
126699461Sobrien		    htab->elf.dynobj = abfd;
126799461Sobrien
126899461Sobrien		  dynobj = htab->elf.dynobj;
126999461Sobrien		  sreloc = bfd_get_section_by_name (dynobj, name);
127099461Sobrien		  if (sreloc == NULL)
127199461Sobrien		    {
127299461Sobrien		      flagword flags;
127399461Sobrien
127499461Sobrien		      flags = (SEC_HAS_CONTENTS | SEC_READONLY
127599461Sobrien			       | SEC_IN_MEMORY | SEC_LINKER_CREATED);
127699461Sobrien		      if ((sec->flags & SEC_ALLOC) != 0)
127799461Sobrien			flags |= SEC_ALLOC | SEC_LOAD;
1278218822Sdim		      sreloc = bfd_make_section_with_flags (dynobj,
1279218822Sdim							    name,
1280218822Sdim							    flags);
128199461Sobrien		      if (sreloc == NULL
1282107492Sobrien			  || ! bfd_set_section_alignment (dynobj, sreloc, 3))
1283130561Sobrien			return FALSE;
128499461Sobrien		    }
128599461Sobrien		  elf_section_data (sec)->sreloc = sreloc;
128699461Sobrien		}
128799461Sobrien
128899461Sobrien	      /* If this is a global symbol, we count the number of
128999461Sobrien		 relocations we need for this symbol.  */
129099461Sobrien	      if (h != NULL)
129199461Sobrien		{
129299461Sobrien		  head = &((struct elf_s390_link_hash_entry *) h)->dyn_relocs;
129399461Sobrien		}
129499461Sobrien	      else
129599461Sobrien		{
129699461Sobrien		  /* Track dynamic relocs needed for local syms too.
129799461Sobrien		     We really need local syms available to do this
129899461Sobrien		     easily.  Oh well.  */
129999461Sobrien
130099461Sobrien		  asection *s;
1301218822Sdim		  void *vpp;
1302218822Sdim
130399461Sobrien		  s = bfd_section_from_r_symndx (abfd, &htab->sym_sec,
130499461Sobrien						 sec, r_symndx);
130599461Sobrien		  if (s == NULL)
1306130561Sobrien		    return FALSE;
130799461Sobrien
1308218822Sdim		  vpp = &elf_section_data (s)->local_dynrel;
1309218822Sdim		  head = (struct elf_s390_dyn_relocs **) vpp;
131099461Sobrien		}
131199461Sobrien
131299461Sobrien	      p = *head;
131399461Sobrien	      if (p == NULL || p->sec != sec)
131499461Sobrien		{
131599461Sobrien		  bfd_size_type amt = sizeof *p;
131699461Sobrien		  p = ((struct elf_s390_dyn_relocs *)
131799461Sobrien		       bfd_alloc (htab->elf.dynobj, amt));
131899461Sobrien		  if (p == NULL)
1319130561Sobrien		    return FALSE;
132099461Sobrien		  p->next = *head;
132199461Sobrien		  *head = p;
132299461Sobrien		  p->sec = sec;
132399461Sobrien		  p->count = 0;
132499461Sobrien		  p->pc_count = 0;
132599461Sobrien		}
132699461Sobrien
132799461Sobrien	      p->count += 1;
132899461Sobrien	      if (ELF64_R_TYPE (rel->r_info) == R_390_PC16
132999461Sobrien		  || ELF64_R_TYPE (rel->r_info) == R_390_PC16DBL
133099461Sobrien		  || ELF64_R_TYPE (rel->r_info) == R_390_PC32
133199461Sobrien		  || ELF64_R_TYPE (rel->r_info) == R_390_PC32DBL
133299461Sobrien		  || ELF64_R_TYPE (rel->r_info) == R_390_PC64)
133399461Sobrien		p->pc_count += 1;
133499461Sobrien	    }
133599461Sobrien	  break;
133699461Sobrien
133799461Sobrien	  /* This relocation describes the C++ object vtable hierarchy.
133899461Sobrien	     Reconstruct it for later use during GC.  */
1339130561Sobrien	case R_390_GNU_VTINHERIT:
1340130561Sobrien	  if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
1341130561Sobrien	    return FALSE;
1342130561Sobrien	  break;
134399461Sobrien
134499461Sobrien	  /* This relocation describes which C++ vtable entries are actually
134599461Sobrien	     used.  Record for later use during GC.  */
1346130561Sobrien	case R_390_GNU_VTENTRY:
1347130561Sobrien	  if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
1348130561Sobrien	    return FALSE;
1349130561Sobrien	  break;
135099461Sobrien
135199461Sobrien	default:
135299461Sobrien	  break;
135399461Sobrien	}
135499461Sobrien    }
135599461Sobrien
1356130561Sobrien  return TRUE;
135799461Sobrien}
135899461Sobrien
135999461Sobrien/* Return the section that should be marked against GC for a given
136099461Sobrien   relocation.  */
136199461Sobrien
136299461Sobrienstatic asection *
1363218822Sdimelf_s390_gc_mark_hook (asection *sec,
1364218822Sdim		       struct bfd_link_info *info,
1365218822Sdim		       Elf_Internal_Rela *rel,
1366218822Sdim		       struct elf_link_hash_entry *h,
1367218822Sdim		       Elf_Internal_Sym *sym)
136899461Sobrien{
136999461Sobrien  if (h != NULL)
1370218822Sdim    switch (ELF64_R_TYPE (rel->r_info))
1371218822Sdim      {
1372218822Sdim      case R_390_GNU_VTINHERIT:
1373218822Sdim      case R_390_GNU_VTENTRY:
1374218822Sdim	return NULL;
1375218822Sdim      }
137699461Sobrien
1377218822Sdim  return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
137899461Sobrien}
137999461Sobrien
138099461Sobrien/* Update the got entry reference counts for the section being removed.  */
138199461Sobrien
1382130561Sobrienstatic bfd_boolean
1383218822Sdimelf_s390_gc_sweep_hook (bfd *abfd,
1384218822Sdim			struct bfd_link_info *info,
1385218822Sdim			asection *sec,
1386218822Sdim			const Elf_Internal_Rela *relocs)
138799461Sobrien{
138899461Sobrien  Elf_Internal_Shdr *symtab_hdr;
138999461Sobrien  struct elf_link_hash_entry **sym_hashes;
139099461Sobrien  bfd_signed_vma *local_got_refcounts;
139199461Sobrien  const Elf_Internal_Rela *rel, *relend;
139299461Sobrien
139399461Sobrien  elf_section_data (sec)->local_dynrel = NULL;
139499461Sobrien
139599461Sobrien  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
139699461Sobrien  sym_hashes = elf_sym_hashes (abfd);
139799461Sobrien  local_got_refcounts = elf_local_got_refcounts (abfd);
139899461Sobrien
139999461Sobrien  relend = relocs + sec->reloc_count;
140099461Sobrien  for (rel = relocs; rel < relend; rel++)
1401130561Sobrien    {
1402130561Sobrien      unsigned long r_symndx;
1403130561Sobrien      unsigned int r_type;
1404130561Sobrien      struct elf_link_hash_entry *h = NULL;
140599461Sobrien
1406130561Sobrien      r_symndx = ELF64_R_SYM (rel->r_info);
1407130561Sobrien      if (r_symndx >= symtab_hdr->sh_info)
1408130561Sobrien	{
1409130561Sobrien	  struct elf_s390_link_hash_entry *eh;
1410130561Sobrien	  struct elf_s390_dyn_relocs **pp;
1411130561Sobrien	  struct elf_s390_dyn_relocs *p;
141299461Sobrien
1413130561Sobrien	  h = sym_hashes[r_symndx - symtab_hdr->sh_info];
1414218822Sdim	  while (h->root.type == bfd_link_hash_indirect
1415218822Sdim		 || h->root.type == bfd_link_hash_warning)
1416218822Sdim	    h = (struct elf_link_hash_entry *) h->root.u.i.link;
1417130561Sobrien	  eh = (struct elf_s390_link_hash_entry *) h;
141899461Sobrien
1419130561Sobrien	  for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next)
1420130561Sobrien	    if (p->sec == sec)
1421130561Sobrien	      {
1422130561Sobrien		/* Everything must go for SEC.  */
1423130561Sobrien		*pp = p->next;
1424130561Sobrien		break;
1425130561Sobrien	      }
1426130561Sobrien	}
142799461Sobrien
1428130561Sobrien      r_type = ELF64_R_TYPE (rel->r_info);
1429130561Sobrien      r_type = elf_s390_tls_transition (info, r_type, h != NULL);
1430130561Sobrien      switch (r_type)
1431130561Sobrien	{
1432130561Sobrien	case R_390_TLS_LDM64:
1433130561Sobrien	  if (elf_s390_hash_table (info)->tls_ldm_got.refcount > 0)
1434130561Sobrien	    elf_s390_hash_table (info)->tls_ldm_got.refcount -= 1;
1435130561Sobrien	  break;
143699461Sobrien
1437130561Sobrien	case R_390_TLS_GD64:
1438130561Sobrien	case R_390_TLS_IE64:
1439130561Sobrien	case R_390_TLS_GOTIE12:
1440130561Sobrien	case R_390_TLS_GOTIE20:
1441130561Sobrien	case R_390_TLS_GOTIE64:
1442130561Sobrien	case R_390_TLS_IEENT:
1443130561Sobrien	case R_390_GOT12:
1444130561Sobrien	case R_390_GOT16:
1445130561Sobrien	case R_390_GOT20:
1446130561Sobrien	case R_390_GOT32:
1447130561Sobrien	case R_390_GOT64:
1448130561Sobrien	case R_390_GOTOFF16:
1449130561Sobrien	case R_390_GOTOFF32:
1450130561Sobrien	case R_390_GOTOFF64:
1451130561Sobrien	case R_390_GOTPC:
1452130561Sobrien	case R_390_GOTPCDBL:
1453130561Sobrien	case R_390_GOTENT:
1454130561Sobrien	  if (h != NULL)
1455130561Sobrien	    {
1456130561Sobrien	      if (h->got.refcount > 0)
1457130561Sobrien		h->got.refcount -= 1;
1458130561Sobrien	    }
1459130561Sobrien	  else if (local_got_refcounts != NULL)
1460130561Sobrien	    {
1461130561Sobrien	      if (local_got_refcounts[r_symndx] > 0)
1462130561Sobrien		local_got_refcounts[r_symndx] -= 1;
1463130561Sobrien	    }
1464130561Sobrien	  break;
1465130561Sobrien
1466130561Sobrien	case R_390_8:
1467130561Sobrien	case R_390_12:
1468130561Sobrien	case R_390_16:
1469130561Sobrien	case R_390_20:
1470130561Sobrien	case R_390_32:
1471130561Sobrien	case R_390_64:
1472130561Sobrien	case R_390_PC16:
1473130561Sobrien	case R_390_PC16DBL:
1474130561Sobrien	case R_390_PC32:
1475130561Sobrien	case R_390_PC32DBL:
1476130561Sobrien	case R_390_PC64:
1477130561Sobrien	  if (info->shared)
1478130561Sobrien	    break;
1479130561Sobrien	  /* Fall through */
1480130561Sobrien
1481130561Sobrien	case R_390_PLT16DBL:
1482130561Sobrien	case R_390_PLT32:
1483130561Sobrien	case R_390_PLT32DBL:
1484130561Sobrien	case R_390_PLT64:
1485130561Sobrien	case R_390_PLTOFF16:
1486130561Sobrien	case R_390_PLTOFF32:
1487130561Sobrien	case R_390_PLTOFF64:
1488130561Sobrien	  if (h != NULL)
1489130561Sobrien	    {
1490130561Sobrien	      if (h->plt.refcount > 0)
1491130561Sobrien		h->plt.refcount -= 1;
1492130561Sobrien	    }
1493130561Sobrien	  break;
1494130561Sobrien
1495130561Sobrien	case R_390_GOTPLT12:
1496130561Sobrien	case R_390_GOTPLT16:
1497130561Sobrien	case R_390_GOTPLT20:
1498130561Sobrien	case R_390_GOTPLT32:
1499130561Sobrien	case R_390_GOTPLT64:
1500130561Sobrien	case R_390_GOTPLTENT:
1501130561Sobrien	  if (h != NULL)
1502130561Sobrien	    {
1503130561Sobrien	      if (h->plt.refcount > 0)
150499461Sobrien		{
1505130561Sobrien		  ((struct elf_s390_link_hash_entry *) h)->gotplt_refcount--;
1506130561Sobrien		  h->plt.refcount -= 1;
150799461Sobrien		}
1508130561Sobrien	    }
1509130561Sobrien	  else if (local_got_refcounts != NULL)
1510130561Sobrien	    {
1511130561Sobrien	      if (local_got_refcounts[r_symndx] > 0)
1512130561Sobrien		local_got_refcounts[r_symndx] -= 1;
1513130561Sobrien	    }
1514130561Sobrien	  break;
151599461Sobrien
1516130561Sobrien	default:
1517130561Sobrien	  break;
1518130561Sobrien	}
1519130561Sobrien    }
152099461Sobrien
1521130561Sobrien  return TRUE;
1522130561Sobrien}
152399461Sobrien
1524130561Sobrien/* Make sure we emit a GOT entry if the symbol was supposed to have a PLT
1525130561Sobrien   entry but we found we will not create any.  Called when we find we will
1526130561Sobrien   not have any PLT for this symbol, by for example
1527130561Sobrien   elf_s390_adjust_dynamic_symbol when we're doing a proper dynamic link,
1528130561Sobrien   or elf_s390_size_dynamic_sections if no dynamic sections will be
1529130561Sobrien   created (we're only linking static objects).  */
1530130561Sobrien
1531130561Sobrienstatic void
1532130561Sobrienelf_s390_adjust_gotplt (h)
1533130561Sobrien     struct elf_s390_link_hash_entry *h;
1534130561Sobrien{
1535130561Sobrien  if (h->elf.root.type == bfd_link_hash_warning)
1536130561Sobrien    h = (struct elf_s390_link_hash_entry *) h->elf.root.u.i.link;
1537130561Sobrien
1538130561Sobrien  if (h->gotplt_refcount <= 0)
1539130561Sobrien    return;
1540130561Sobrien
1541130561Sobrien  /* We simply add the number of gotplt references to the number
1542130561Sobrien   * of got references for this symbol.  */
1543130561Sobrien  h->elf.got.refcount += h->gotplt_refcount;
1544130561Sobrien  h->gotplt_refcount = -1;
154599461Sobrien}
154699461Sobrien
154799461Sobrien/* Adjust a symbol defined by a dynamic object and referenced by a
154899461Sobrien   regular object.  The current definition is in some section of the
154999461Sobrien   dynamic object, but we're not including those sections.  We have to
155099461Sobrien   change the definition to something the rest of the link can
155199461Sobrien   understand.  */
155299461Sobrien
1553130561Sobrienstatic bfd_boolean
155499461Sobrienelf_s390_adjust_dynamic_symbol (info, h)
155599461Sobrien     struct bfd_link_info *info;
155699461Sobrien     struct elf_link_hash_entry *h;
155799461Sobrien{
155899461Sobrien  struct elf_s390_link_hash_table *htab;
155999461Sobrien  asection *s;
156099461Sobrien
156199461Sobrien  /* If this is a function, put it in the procedure linkage table.  We
156299461Sobrien     will fill in the contents of the procedure linkage table later
1563107492Sobrien     (although we could actually do it here).  */
156499461Sobrien  if (h->type == STT_FUNC
1565218822Sdim      || h->needs_plt)
156699461Sobrien    {
156799461Sobrien      if (h->plt.refcount <= 0
156899461Sobrien	  || (! info->shared
1569218822Sdim	      && !h->def_dynamic
1570218822Sdim	      && !h->ref_dynamic
157199461Sobrien	      && h->root.type != bfd_link_hash_undefweak
157299461Sobrien	      && h->root.type != bfd_link_hash_undefined))
157399461Sobrien	{
157499461Sobrien	  /* This case can occur if we saw a PLT32 reloc in an input
1575130561Sobrien	     file, but the symbol was never referred to by a dynamic
1576130561Sobrien	     object, or if all references were garbage collected.  In
157799461Sobrien	     such a case, we don't actually need to build a procedure
157899461Sobrien	     linkage table, and we can just do a PC32 reloc instead.  */
157999461Sobrien	  h->plt.offset = (bfd_vma) -1;
1580218822Sdim	  h->needs_plt = 0;
1581130561Sobrien	  elf_s390_adjust_gotplt((struct elf_s390_link_hash_entry *) h);
158299461Sobrien	}
158399461Sobrien
1584130561Sobrien      return TRUE;
158599461Sobrien    }
158699461Sobrien  else
158799461Sobrien    /* It's possible that we incorrectly decided a .plt reloc was
158899461Sobrien       needed for an R_390_PC32 reloc to a non-function sym in
158999461Sobrien       check_relocs.  We can't decide accurately between function and
159099461Sobrien       non-function syms in check-relocs;  Objects loaded later in
159199461Sobrien       the link may change h->type.  So fix it now.  */
159299461Sobrien    h->plt.offset = (bfd_vma) -1;
159399461Sobrien
159499461Sobrien  /* If this is a weak symbol, and there is a real definition, the
159599461Sobrien     processor independent code will have arranged for us to see the
159699461Sobrien     real definition first, and we can just use the same value.  */
1597218822Sdim  if (h->u.weakdef != NULL)
159899461Sobrien    {
1599218822Sdim      BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined
1600218822Sdim		  || h->u.weakdef->root.type == bfd_link_hash_defweak);
1601218822Sdim      h->root.u.def.section = h->u.weakdef->root.u.def.section;
1602218822Sdim      h->root.u.def.value = h->u.weakdef->root.u.def.value;
1603130561Sobrien      if (ELIMINATE_COPY_RELOCS || info->nocopyreloc)
1604218822Sdim	h->non_got_ref = h->u.weakdef->non_got_ref;
1605130561Sobrien      return TRUE;
160699461Sobrien    }
160799461Sobrien
160899461Sobrien  /* This is a reference to a symbol defined by a dynamic object which
160999461Sobrien     is not a function.  */
161099461Sobrien
161199461Sobrien  /* If we are creating a shared library, we must presume that the
161299461Sobrien     only references to the symbol are via the global offset table.
161399461Sobrien     For such cases we need not do anything here; the relocations will
161499461Sobrien     be handled correctly by relocate_section.  */
161599461Sobrien  if (info->shared)
1616130561Sobrien    return TRUE;
161799461Sobrien
161899461Sobrien  /* If there are no references to this symbol that do not use the
161999461Sobrien     GOT, we don't need to generate a copy reloc.  */
1620218822Sdim  if (!h->non_got_ref)
1621130561Sobrien    return TRUE;
162299461Sobrien
162399461Sobrien  /* If -z nocopyreloc was given, we won't generate them either.  */
162499461Sobrien  if (info->nocopyreloc)
162599461Sobrien    {
1626218822Sdim      h->non_got_ref = 0;
1627130561Sobrien      return TRUE;
162899461Sobrien    }
162999461Sobrien
1630130561Sobrien  if (ELIMINATE_COPY_RELOCS)
163199461Sobrien    {
1632130561Sobrien      struct elf_s390_link_hash_entry * eh;
1633130561Sobrien      struct elf_s390_dyn_relocs *p;
163499461Sobrien
1635130561Sobrien      eh = (struct elf_s390_link_hash_entry *) h;
1636130561Sobrien      for (p = eh->dyn_relocs; p != NULL; p = p->next)
1637130561Sobrien	{
1638130561Sobrien	  s = p->sec->output_section;
1639130561Sobrien	  if (s != NULL && (s->flags & SEC_READONLY) != 0)
1640130561Sobrien	    break;
1641130561Sobrien	}
1642130561Sobrien
1643130561Sobrien      /* If we didn't find any dynamic relocs in read-only sections, then
1644130561Sobrien	 we'll be keeping the dynamic relocs and avoiding the copy reloc.  */
1645130561Sobrien      if (p == NULL)
1646130561Sobrien	{
1647218822Sdim	  h->non_got_ref = 0;
1648130561Sobrien	  return TRUE;
1649130561Sobrien	}
165099461Sobrien    }
165199461Sobrien
1652218822Sdim  if (h->size == 0)
1653218822Sdim    {
1654218822Sdim      (*_bfd_error_handler) (_("dynamic variable `%s' is zero size"),
1655218822Sdim			     h->root.root.string);
1656218822Sdim      return TRUE;
1657218822Sdim    }
1658218822Sdim
165999461Sobrien  /* We must allocate the symbol in our .dynbss section, which will
166099461Sobrien     become part of the .bss section of the executable.  There will be
166199461Sobrien     an entry for this symbol in the .dynsym section.  The dynamic
166299461Sobrien     object will contain position independent code, so all references
166399461Sobrien     from the dynamic object to this symbol will go through the global
166499461Sobrien     offset table.  The dynamic linker will use the .dynsym entry to
166599461Sobrien     determine the address it must put in the global offset table, so
166699461Sobrien     both the dynamic object and the regular object will refer to the
166799461Sobrien     same memory location for the variable.  */
166899461Sobrien
166999461Sobrien  htab = elf_s390_hash_table (info);
167099461Sobrien
167199461Sobrien  /* We must generate a R_390_COPY reloc to tell the dynamic linker to
167299461Sobrien     copy the initial value out of the dynamic object and into the
167399461Sobrien     runtime process image.  */
167499461Sobrien  if ((h->root.u.def.section->flags & SEC_ALLOC) != 0)
167599461Sobrien    {
1676218822Sdim      htab->srelbss->size += sizeof (Elf64_External_Rela);
1677218822Sdim      h->needs_copy = 1;
167899461Sobrien    }
167999461Sobrien
168099461Sobrien  s = htab->sdynbss;
168199461Sobrien
1682218822Sdim  return _bfd_elf_adjust_dynamic_copy (h, s);
168399461Sobrien}
168499461Sobrien
168599461Sobrien/* Allocate space in .plt, .got and associated reloc sections for
168699461Sobrien   dynamic relocs.  */
168799461Sobrien
1688130561Sobrienstatic bfd_boolean
168999461Sobrienallocate_dynrelocs (h, inf)
169099461Sobrien     struct elf_link_hash_entry *h;
169199461Sobrien     PTR inf;
169299461Sobrien{
169399461Sobrien  struct bfd_link_info *info;
169499461Sobrien  struct elf_s390_link_hash_table *htab;
169599461Sobrien  struct elf_s390_link_hash_entry *eh;
169699461Sobrien  struct elf_s390_dyn_relocs *p;
169799461Sobrien
169899461Sobrien  if (h->root.type == bfd_link_hash_indirect)
1699130561Sobrien    return TRUE;
170099461Sobrien
170199461Sobrien  if (h->root.type == bfd_link_hash_warning)
1702130561Sobrien    /* When warning symbols are created, they **replace** the "real"
1703130561Sobrien       entry in the hash table, thus we never get to see the real
1704130561Sobrien       symbol in a hash traversal.  So look at it now.  */
170599461Sobrien    h = (struct elf_link_hash_entry *) h->root.u.i.link;
170699461Sobrien
170799461Sobrien  info = (struct bfd_link_info *) inf;
170899461Sobrien  htab = elf_s390_hash_table (info);
170999461Sobrien
171099461Sobrien  if (htab->elf.dynamic_sections_created
1711130561Sobrien      && h->plt.refcount > 0
1712130561Sobrien      && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
1713130561Sobrien	  || h->root.type != bfd_link_hash_undefweak))
171499461Sobrien    {
171599461Sobrien      /* Make sure this symbol is output as a dynamic symbol.
171699461Sobrien	 Undefined weak syms won't yet be marked as dynamic.  */
171799461Sobrien      if (h->dynindx == -1
1718218822Sdim	  && !h->forced_local)
171999461Sobrien	{
1720130561Sobrien	  if (! bfd_elf_link_record_dynamic_symbol (info, h))
1721130561Sobrien	    return FALSE;
172299461Sobrien	}
172399461Sobrien
1724130561Sobrien      if (info->shared
1725130561Sobrien	  || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h))
172699461Sobrien	{
172799461Sobrien	  asection *s = htab->splt;
172899461Sobrien
172999461Sobrien	  /* If this is the first .plt entry, make room for the special
173099461Sobrien	     first entry.  */
1731218822Sdim	  if (s->size == 0)
1732218822Sdim	    s->size += PLT_FIRST_ENTRY_SIZE;
173399461Sobrien
1734218822Sdim	  h->plt.offset = s->size;
173599461Sobrien
173699461Sobrien	  /* If this symbol is not defined in a regular file, and we are
173799461Sobrien	     not generating a shared library, then set the symbol to this
173899461Sobrien	     location in the .plt.  This is required to make function
173999461Sobrien	     pointers compare as equal between the normal executable and
174099461Sobrien	     the shared library.  */
174199461Sobrien	  if (! info->shared
1742218822Sdim	      && !h->def_regular)
174399461Sobrien	    {
174499461Sobrien	      h->root.u.def.section = s;
174599461Sobrien	      h->root.u.def.value = h->plt.offset;
174699461Sobrien	    }
174799461Sobrien
174899461Sobrien	  /* Make room for this entry.  */
1749218822Sdim	  s->size += PLT_ENTRY_SIZE;
175099461Sobrien
175199461Sobrien	  /* We also need to make an entry in the .got.plt section, which
175299461Sobrien	     will be placed in the .got section by the linker script.  */
1753218822Sdim	  htab->sgotplt->size += GOT_ENTRY_SIZE;
175499461Sobrien
175599461Sobrien	  /* We also need to make an entry in the .rela.plt section.  */
1756218822Sdim	  htab->srelplt->size += sizeof (Elf64_External_Rela);
175799461Sobrien	}
175899461Sobrien      else
175999461Sobrien	{
176099461Sobrien	  h->plt.offset = (bfd_vma) -1;
1761218822Sdim	  h->needs_plt = 0;
1762130561Sobrien	  elf_s390_adjust_gotplt((struct elf_s390_link_hash_entry *) h);
176399461Sobrien	}
176499461Sobrien    }
176599461Sobrien  else
176699461Sobrien    {
176799461Sobrien      h->plt.offset = (bfd_vma) -1;
1768218822Sdim      h->needs_plt = 0;
1769130561Sobrien      elf_s390_adjust_gotplt((struct elf_s390_link_hash_entry *) h);
177099461Sobrien    }
177199461Sobrien
1772130561Sobrien  /* If R_390_TLS_{IE64,GOTIE64,GOTIE12,IEENT} symbol is now local to
1773130561Sobrien     the binary, we can optimize a bit. IE64 and GOTIE64 get converted
1774130561Sobrien     to R_390_TLS_LE64 requiring no TLS entry. For GOTIE12 and IEENT
1775130561Sobrien     we can save the dynamic TLS relocation.  */
1776130561Sobrien  if (h->got.refcount > 0
1777130561Sobrien      && !info->shared
1778130561Sobrien      && h->dynindx == -1
1779130561Sobrien      && elf_s390_hash_entry(h)->tls_type >= GOT_TLS_IE)
178099461Sobrien    {
1781130561Sobrien      if (elf_s390_hash_entry(h)->tls_type == GOT_TLS_IE_NLT)
1782130561Sobrien	/* For the GOTIE access without a literal pool entry the offset has
1783130561Sobrien	   to be stored somewhere. The immediate value in the instruction
1784130561Sobrien	   is not bit enough so the value is stored in the got.  */
1785130561Sobrien	{
1786218822Sdim	  h->got.offset = htab->sgot->size;
1787218822Sdim	  htab->sgot->size += GOT_ENTRY_SIZE;
1788130561Sobrien	}
1789130561Sobrien      else
1790130561Sobrien	h->got.offset = (bfd_vma) -1;
1791130561Sobrien    }
1792130561Sobrien  else if (h->got.refcount > 0)
1793130561Sobrien    {
179499461Sobrien      asection *s;
1795130561Sobrien      bfd_boolean dyn;
1796130561Sobrien      int tls_type = elf_s390_hash_entry(h)->tls_type;
179799461Sobrien
179899461Sobrien      /* Make sure this symbol is output as a dynamic symbol.
179999461Sobrien	 Undefined weak syms won't yet be marked as dynamic.  */
180099461Sobrien      if (h->dynindx == -1
1801218822Sdim	  && !h->forced_local)
180299461Sobrien	{
1803130561Sobrien	  if (! bfd_elf_link_record_dynamic_symbol (info, h))
1804130561Sobrien	    return FALSE;
180599461Sobrien	}
180699461Sobrien
180799461Sobrien      s = htab->sgot;
1808218822Sdim      h->got.offset = s->size;
1809218822Sdim      s->size += GOT_ENTRY_SIZE;
1810130561Sobrien      /* R_390_TLS_GD64 needs 2 consecutive GOT slots.  */
1811130561Sobrien      if (tls_type == GOT_TLS_GD)
1812218822Sdim	s->size += GOT_ENTRY_SIZE;
181399461Sobrien      dyn = htab->elf.dynamic_sections_created;
1814130561Sobrien      /* R_390_TLS_IE64 needs one dynamic relocation,
1815130561Sobrien	 R_390_TLS_GD64 needs one if local symbol and two if global.  */
1816130561Sobrien      if ((tls_type == GOT_TLS_GD && h->dynindx == -1)
1817130561Sobrien	  || tls_type >= GOT_TLS_IE)
1818218822Sdim	htab->srelgot->size += sizeof (Elf64_External_Rela);
1819130561Sobrien      else if (tls_type == GOT_TLS_GD)
1820218822Sdim	htab->srelgot->size += 2 * sizeof (Elf64_External_Rela);
1821130561Sobrien      else if ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
1822130561Sobrien		|| h->root.type != bfd_link_hash_undefweak)
1823130561Sobrien	       && (info->shared
1824130561Sobrien		   || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)))
1825218822Sdim	htab->srelgot->size += sizeof (Elf64_External_Rela);
182699461Sobrien    }
182799461Sobrien  else
182899461Sobrien    h->got.offset = (bfd_vma) -1;
182999461Sobrien
183099461Sobrien  eh = (struct elf_s390_link_hash_entry *) h;
183199461Sobrien  if (eh->dyn_relocs == NULL)
1832130561Sobrien    return TRUE;
183399461Sobrien
183499461Sobrien  /* In the shared -Bsymbolic case, discard space allocated for
183599461Sobrien     dynamic pc-relative relocs against symbols which turn out to be
183699461Sobrien     defined in regular objects.  For the normal shared case, discard
183799461Sobrien     space for pc-relative relocs that have become local due to symbol
183899461Sobrien     visibility changes.  */
183999461Sobrien
184099461Sobrien  if (info->shared)
184199461Sobrien    {
1842130561Sobrien      if (SYMBOL_REFERENCES_LOCAL (info, h))
184399461Sobrien	{
184499461Sobrien	  struct elf_s390_dyn_relocs **pp;
184599461Sobrien
184699461Sobrien	  for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
184799461Sobrien	    {
184899461Sobrien	      p->count -= p->pc_count;
184999461Sobrien	      p->pc_count = 0;
185099461Sobrien	      if (p->count == 0)
185199461Sobrien		*pp = p->next;
185299461Sobrien	      else
185399461Sobrien		pp = &p->next;
185499461Sobrien	    }
185599461Sobrien	}
1856130561Sobrien
1857130561Sobrien      /* Also discard relocs on undefined weak syms with non-default
1858130561Sobrien	 visibility.  */
1859218822Sdim      if (eh->dyn_relocs != NULL
1860130561Sobrien	  && h->root.type == bfd_link_hash_undefweak)
1861218822Sdim	{
1862218822Sdim	  if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
1863218822Sdim	    eh->dyn_relocs = NULL;
1864218822Sdim
1865218822Sdim	  /* Make sure undefined weak symbols are output as a dynamic
1866218822Sdim	     symbol in PIEs.  */
1867218822Sdim	  else if (h->dynindx == -1
1868218822Sdim		   && !h->forced_local)
1869218822Sdim	    {
1870218822Sdim	      if (! bfd_elf_link_record_dynamic_symbol (info, h))
1871218822Sdim		return FALSE;
1872218822Sdim	    }
1873218822Sdim	}
187499461Sobrien    }
1875130561Sobrien  else if (ELIMINATE_COPY_RELOCS)
187699461Sobrien    {
187799461Sobrien      /* For the non-shared case, discard space for relocs against
187899461Sobrien	 symbols which turn out to need copy relocs or are not
187999461Sobrien	 dynamic.  */
188099461Sobrien
1881218822Sdim      if (!h->non_got_ref
1882218822Sdim	  && ((h->def_dynamic
1883218822Sdim	       && !h->def_regular)
188499461Sobrien	      || (htab->elf.dynamic_sections_created
188599461Sobrien		  && (h->root.type == bfd_link_hash_undefweak
188699461Sobrien		      || h->root.type == bfd_link_hash_undefined))))
188799461Sobrien	{
188899461Sobrien	  /* Make sure this symbol is output as a dynamic symbol.
188999461Sobrien	     Undefined weak syms won't yet be marked as dynamic.  */
189099461Sobrien	  if (h->dynindx == -1
1891218822Sdim	      && !h->forced_local)
189299461Sobrien	    {
1893130561Sobrien	      if (! bfd_elf_link_record_dynamic_symbol (info, h))
1894130561Sobrien		return FALSE;
189599461Sobrien	    }
189699461Sobrien
189799461Sobrien	  /* If that succeeded, we know we'll be keeping all the
189899461Sobrien	     relocs.  */
189999461Sobrien	  if (h->dynindx != -1)
190099461Sobrien	    goto keep;
190199461Sobrien	}
190299461Sobrien
190399461Sobrien      eh->dyn_relocs = NULL;
190499461Sobrien
190599461Sobrien    keep: ;
190699461Sobrien    }
190799461Sobrien
190899461Sobrien  /* Finally, allocate space.  */
190999461Sobrien  for (p = eh->dyn_relocs; p != NULL; p = p->next)
191099461Sobrien    {
191199461Sobrien      asection *sreloc = elf_section_data (p->sec)->sreloc;
1912218822Sdim      sreloc->size += p->count * sizeof (Elf64_External_Rela);
191399461Sobrien    }
191499461Sobrien
1915130561Sobrien  return TRUE;
191699461Sobrien}
191799461Sobrien
191899461Sobrien/* Find any dynamic relocs that apply to read-only sections.  */
191999461Sobrien
1920130561Sobrienstatic bfd_boolean
192199461Sobrienreadonly_dynrelocs (h, inf)
192299461Sobrien     struct elf_link_hash_entry *h;
192399461Sobrien     PTR inf;
192499461Sobrien{
192599461Sobrien  struct elf_s390_link_hash_entry *eh;
192699461Sobrien  struct elf_s390_dyn_relocs *p;
192799461Sobrien
192899461Sobrien  if (h->root.type == bfd_link_hash_warning)
192999461Sobrien    h = (struct elf_link_hash_entry *) h->root.u.i.link;
193099461Sobrien
193199461Sobrien  eh = (struct elf_s390_link_hash_entry *) h;
193299461Sobrien  for (p = eh->dyn_relocs; p != NULL; p = p->next)
193399461Sobrien    {
193499461Sobrien      asection *s = p->sec->output_section;
193599461Sobrien
193699461Sobrien      if (s != NULL && (s->flags & SEC_READONLY) != 0)
193799461Sobrien	{
193899461Sobrien	  struct bfd_link_info *info = (struct bfd_link_info *) inf;
193999461Sobrien
194099461Sobrien	  info->flags |= DF_TEXTREL;
194199461Sobrien
194299461Sobrien	  /* Not an error, just cut short the traversal.  */
1943130561Sobrien	  return FALSE;
194499461Sobrien	}
194599461Sobrien    }
1946130561Sobrien  return TRUE;
194799461Sobrien}
194899461Sobrien
194999461Sobrien/* Set the sizes of the dynamic sections.  */
195099461Sobrien
1951130561Sobrienstatic bfd_boolean
195299461Sobrienelf_s390_size_dynamic_sections (output_bfd, info)
195399461Sobrien     bfd *output_bfd ATTRIBUTE_UNUSED;
195499461Sobrien     struct bfd_link_info *info;
195599461Sobrien{
195699461Sobrien  struct elf_s390_link_hash_table *htab;
195799461Sobrien  bfd *dynobj;
195899461Sobrien  asection *s;
1959130561Sobrien  bfd_boolean relocs;
196099461Sobrien  bfd *ibfd;
196199461Sobrien
196299461Sobrien  htab = elf_s390_hash_table (info);
196399461Sobrien  dynobj = htab->elf.dynobj;
196499461Sobrien  if (dynobj == NULL)
196599461Sobrien    abort ();
196699461Sobrien
196799461Sobrien  if (htab->elf.dynamic_sections_created)
196899461Sobrien    {
196999461Sobrien      /* Set the contents of the .interp section to the interpreter.  */
1970130561Sobrien      if (info->executable)
197199461Sobrien	{
197299461Sobrien	  s = bfd_get_section_by_name (dynobj, ".interp");
197399461Sobrien	  if (s == NULL)
197499461Sobrien	    abort ();
1975218822Sdim	  s->size = sizeof ELF_DYNAMIC_INTERPRETER;
197699461Sobrien	  s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
197799461Sobrien	}
197899461Sobrien    }
197999461Sobrien
198099461Sobrien  /* Set up .got offsets for local syms, and space for local dynamic
198199461Sobrien     relocs.  */
198299461Sobrien  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
198399461Sobrien    {
198499461Sobrien      bfd_signed_vma *local_got;
198599461Sobrien      bfd_signed_vma *end_local_got;
1986130561Sobrien      char *local_tls_type;
198799461Sobrien      bfd_size_type locsymcount;
198899461Sobrien      Elf_Internal_Shdr *symtab_hdr;
198999461Sobrien      asection *srela;
199099461Sobrien
199199461Sobrien      if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
199299461Sobrien	continue;
199399461Sobrien
199499461Sobrien      for (s = ibfd->sections; s != NULL; s = s->next)
199599461Sobrien	{
199699461Sobrien	  struct elf_s390_dyn_relocs *p;
199799461Sobrien
1998218822Sdim	  for (p = elf_section_data (s)->local_dynrel; p != NULL; p = p->next)
199999461Sobrien	    {
200099461Sobrien	      if (!bfd_is_abs_section (p->sec)
200199461Sobrien		  && bfd_is_abs_section (p->sec->output_section))
200299461Sobrien		{
200399461Sobrien		  /* Input section has been discarded, either because
200499461Sobrien		     it is a copy of a linkonce section or due to
200599461Sobrien		     linker script /DISCARD/, so we'll be discarding
200699461Sobrien		     the relocs too.  */
200799461Sobrien		}
200899461Sobrien	      else if (p->count != 0)
200999461Sobrien		{
201099461Sobrien		  srela = elf_section_data (p->sec)->sreloc;
2011218822Sdim		  srela->size += p->count * sizeof (Elf64_External_Rela);
201299461Sobrien		  if ((p->sec->output_section->flags & SEC_READONLY) != 0)
201399461Sobrien		    info->flags |= DF_TEXTREL;
201499461Sobrien		}
201599461Sobrien	    }
201699461Sobrien	}
201799461Sobrien
201899461Sobrien      local_got = elf_local_got_refcounts (ibfd);
201999461Sobrien      if (!local_got)
202099461Sobrien	continue;
202199461Sobrien
202299461Sobrien      symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
202399461Sobrien      locsymcount = symtab_hdr->sh_info;
202499461Sobrien      end_local_got = local_got + locsymcount;
2025130561Sobrien      local_tls_type = elf_s390_local_got_tls_type (ibfd);
202699461Sobrien      s = htab->sgot;
202799461Sobrien      srela = htab->srelgot;
2028130561Sobrien      for (; local_got < end_local_got; ++local_got, ++local_tls_type)
202999461Sobrien	{
203099461Sobrien	  if (*local_got > 0)
203199461Sobrien	    {
2032218822Sdim	      *local_got = s->size;
2033218822Sdim	      s->size += GOT_ENTRY_SIZE;
2034130561Sobrien	      if (*local_tls_type == GOT_TLS_GD)
2035218822Sdim		s->size += GOT_ENTRY_SIZE;
203699461Sobrien	      if (info->shared)
2037218822Sdim		srela->size += sizeof (Elf64_External_Rela);
203899461Sobrien	    }
203999461Sobrien	  else
204099461Sobrien	    *local_got = (bfd_vma) -1;
204199461Sobrien	}
204299461Sobrien    }
204399461Sobrien
2044130561Sobrien  if (htab->tls_ldm_got.refcount > 0)
2045130561Sobrien    {
2046130561Sobrien      /* Allocate 2 got entries and 1 dynamic reloc for R_390_TLS_LDM64
2047130561Sobrien	 relocs.  */
2048218822Sdim      htab->tls_ldm_got.offset = htab->sgot->size;
2049218822Sdim      htab->sgot->size += 2 * GOT_ENTRY_SIZE;
2050218822Sdim      htab->srelgot->size += sizeof (Elf64_External_Rela);
2051130561Sobrien    }
2052130561Sobrien  else
2053130561Sobrien    htab->tls_ldm_got.offset = -1;
2054130561Sobrien
205599461Sobrien  /* Allocate global sym .plt and .got entries, and space for global
205699461Sobrien     sym dynamic relocs.  */
205799461Sobrien  elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, (PTR) info);
205899461Sobrien
205999461Sobrien  /* We now have determined the sizes of the various dynamic sections.
206099461Sobrien     Allocate memory for them.  */
2061130561Sobrien  relocs = FALSE;
206299461Sobrien  for (s = dynobj->sections; s != NULL; s = s->next)
206399461Sobrien    {
206499461Sobrien      if ((s->flags & SEC_LINKER_CREATED) == 0)
206599461Sobrien	continue;
206699461Sobrien
206799461Sobrien      if (s == htab->splt
206899461Sobrien	  || s == htab->sgot
2069218822Sdim	  || s == htab->sgotplt
2070218822Sdim	  || s == htab->sdynbss)
207199461Sobrien	{
207299461Sobrien	  /* Strip this section if we don't need it; see the
207399461Sobrien	     comment below.  */
207499461Sobrien	}
2075218822Sdim      else if (CONST_STRNEQ (bfd_get_section_name (dynobj, s), ".rela"))
207699461Sobrien	{
2077218822Sdim	  if (s->size != 0 && s != htab->srelplt)
2078130561Sobrien	    relocs = TRUE;
207999461Sobrien
208099461Sobrien	  /* We use the reloc_count field as a counter if we need
208199461Sobrien	     to copy relocs into the output file.  */
208299461Sobrien	  s->reloc_count = 0;
208399461Sobrien	}
208499461Sobrien      else
208599461Sobrien	{
208699461Sobrien	  /* It's not one of our sections, so don't allocate space.  */
208799461Sobrien	  continue;
208899461Sobrien	}
208999461Sobrien
2090218822Sdim      if (s->size == 0)
209199461Sobrien	{
209299461Sobrien	  /* If we don't need this section, strip it from the
209399461Sobrien	     output file.  This is to handle .rela.bss and
209499461Sobrien	     .rela.plt.  We must create it in
209599461Sobrien	     create_dynamic_sections, because it must be created
209699461Sobrien	     before the linker maps input sections to output
209799461Sobrien	     sections.  The linker does that before
209899461Sobrien	     adjust_dynamic_symbol is called, and it is that
209999461Sobrien	     function which decides whether anything needs to go
210099461Sobrien	     into these sections.  */
210199461Sobrien
2102218822Sdim	  s->flags |= SEC_EXCLUDE;
210399461Sobrien	  continue;
210499461Sobrien	}
210599461Sobrien
2106218822Sdim      if ((s->flags & SEC_HAS_CONTENTS) == 0)
2107218822Sdim	continue;
2108218822Sdim
210999461Sobrien      /* Allocate memory for the section contents.  We use bfd_zalloc
211099461Sobrien	 here in case unused entries are not reclaimed before the
211199461Sobrien	 section's contents are written out.  This should not happen,
211299461Sobrien	 but this way if it does, we get a R_390_NONE reloc instead
211399461Sobrien	 of garbage.  */
2114218822Sdim      s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size);
211599461Sobrien      if (s->contents == NULL)
2116130561Sobrien	return FALSE;
211799461Sobrien    }
211899461Sobrien
211999461Sobrien  if (htab->elf.dynamic_sections_created)
212099461Sobrien    {
212199461Sobrien      /* Add some entries to the .dynamic section.  We fill in the
212299461Sobrien	 values later, in elf_s390_finish_dynamic_sections, but we
212399461Sobrien	 must add the entries now so that we get the correct size for
212499461Sobrien	 the .dynamic section.  The DT_DEBUG entry is filled in by the
212599461Sobrien	 dynamic linker and used by the debugger.  */
212699461Sobrien#define add_dynamic_entry(TAG, VAL) \
2127130561Sobrien  _bfd_elf_add_dynamic_entry (info, TAG, VAL)
212899461Sobrien
2129130561Sobrien      if (info->executable)
213099461Sobrien	{
213199461Sobrien	  if (!add_dynamic_entry (DT_DEBUG, 0))
2132130561Sobrien	    return FALSE;
213399461Sobrien	}
213499461Sobrien
2135218822Sdim      if (htab->splt->size != 0)
213699461Sobrien	{
213799461Sobrien	  if (!add_dynamic_entry (DT_PLTGOT, 0)
213899461Sobrien	      || !add_dynamic_entry (DT_PLTRELSZ, 0)
213999461Sobrien	      || !add_dynamic_entry (DT_PLTREL, DT_RELA)
214099461Sobrien	      || !add_dynamic_entry (DT_JMPREL, 0))
2141130561Sobrien	    return FALSE;
214299461Sobrien	}
214399461Sobrien
214499461Sobrien      if (relocs)
2145130561Sobrien	{
2146130561Sobrien	  if (!add_dynamic_entry (DT_RELA, 0)
2147130561Sobrien	      || !add_dynamic_entry (DT_RELASZ, 0)
2148130561Sobrien	      || !add_dynamic_entry (DT_RELAENT, sizeof (Elf64_External_Rela)))
2149130561Sobrien	    return FALSE;
215099461Sobrien
215199461Sobrien	  /* If any dynamic relocs apply to a read-only section,
215299461Sobrien	     then we need a DT_TEXTREL entry.  */
215399461Sobrien	  if ((info->flags & DF_TEXTREL) == 0)
215499461Sobrien	    elf_link_hash_traverse (&htab->elf, readonly_dynrelocs,
215599461Sobrien				    (PTR) info);
215699461Sobrien
215799461Sobrien	  if ((info->flags & DF_TEXTREL) != 0)
215899461Sobrien	    {
215999461Sobrien	      if (!add_dynamic_entry (DT_TEXTREL, 0))
2160130561Sobrien		return FALSE;
216199461Sobrien	    }
216299461Sobrien	}
216399461Sobrien    }
216499461Sobrien#undef add_dynamic_entry
216599461Sobrien
2166130561Sobrien  return TRUE;
216799461Sobrien}
216899461Sobrien
2169130561Sobrien/* Return the base VMA address which should be subtracted from real addresses
2170130561Sobrien   when resolving @dtpoff relocation.
2171130561Sobrien   This is PT_TLS segment p_vaddr.  */
2172130561Sobrien
2173130561Sobrienstatic bfd_vma
2174130561Sobriendtpoff_base (info)
2175130561Sobrien     struct bfd_link_info *info;
2176130561Sobrien{
2177130561Sobrien  /* If tls_sec is NULL, we should have signalled an error already.  */
2178130561Sobrien  if (elf_hash_table (info)->tls_sec == NULL)
2179130561Sobrien    return 0;
2180130561Sobrien  return elf_hash_table (info)->tls_sec->vma;
2181130561Sobrien}
2182130561Sobrien
2183130561Sobrien/* Return the relocation value for @tpoff relocation
2184130561Sobrien   if STT_TLS virtual address is ADDRESS.  */
2185130561Sobrien
2186130561Sobrienstatic bfd_vma
2187130561Sobrientpoff (info, address)
2188130561Sobrien     struct bfd_link_info *info;
2189130561Sobrien     bfd_vma address;
2190130561Sobrien{
2191130561Sobrien  struct elf_link_hash_table *htab = elf_hash_table (info);
2192130561Sobrien
2193130561Sobrien  /* If tls_sec is NULL, we should have signalled an error already.  */
2194130561Sobrien  if (htab->tls_sec == NULL)
2195130561Sobrien    return 0;
2196130561Sobrien  return htab->tls_size + htab->tls_sec->vma - address;
2197130561Sobrien}
2198130561Sobrien
2199130561Sobrien/* Complain if TLS instruction relocation is against an invalid
2200130561Sobrien   instruction.  */
2201130561Sobrien
2202130561Sobrienstatic void
2203130561Sobrieninvalid_tls_insn (input_bfd, input_section, rel)
2204130561Sobrien     bfd *input_bfd;
2205130561Sobrien     asection *input_section;
2206130561Sobrien     Elf_Internal_Rela *rel;
2207130561Sobrien{
2208130561Sobrien  reloc_howto_type *howto;
2209130561Sobrien
2210130561Sobrien  howto = elf_howto_table + ELF64_R_TYPE (rel->r_info);
2211130561Sobrien  (*_bfd_error_handler)
2212218822Sdim    (_("%B(%A+0x%lx): invalid instruction for TLS relocation %s"),
2213218822Sdim     input_bfd,
2214218822Sdim     input_section,
2215130561Sobrien     (long) rel->r_offset,
2216130561Sobrien     howto->name);
2217218822Sdim  bfd_set_error (bfd_error_bad_value);
2218130561Sobrien}
2219130561Sobrien
222099461Sobrien/* Relocate a 390 ELF section.  */
222199461Sobrien
2222130561Sobrienstatic bfd_boolean
222399461Sobrienelf_s390_relocate_section (output_bfd, info, input_bfd, input_section,
222499461Sobrien			      contents, relocs, local_syms, local_sections)
222599461Sobrien     bfd *output_bfd;
222699461Sobrien     struct bfd_link_info *info;
222799461Sobrien     bfd *input_bfd;
222899461Sobrien     asection *input_section;
222999461Sobrien     bfd_byte *contents;
223099461Sobrien     Elf_Internal_Rela *relocs;
223199461Sobrien     Elf_Internal_Sym *local_syms;
223299461Sobrien     asection **local_sections;
223399461Sobrien{
223499461Sobrien  struct elf_s390_link_hash_table *htab;
223599461Sobrien  Elf_Internal_Shdr *symtab_hdr;
223699461Sobrien  struct elf_link_hash_entry **sym_hashes;
223799461Sobrien  bfd_vma *local_got_offsets;
223899461Sobrien  Elf_Internal_Rela *rel;
223999461Sobrien  Elf_Internal_Rela *relend;
224099461Sobrien
224199461Sobrien  htab = elf_s390_hash_table (info);
224299461Sobrien  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
224399461Sobrien  sym_hashes = elf_sym_hashes (input_bfd);
224499461Sobrien  local_got_offsets = elf_local_got_offsets (input_bfd);
224599461Sobrien
224699461Sobrien  rel = relocs;
224799461Sobrien  relend = relocs + input_section->reloc_count;
224899461Sobrien  for (; rel < relend; rel++)
224999461Sobrien    {
2250130561Sobrien      unsigned int r_type;
225199461Sobrien      reloc_howto_type *howto;
225299461Sobrien      unsigned long r_symndx;
225399461Sobrien      struct elf_link_hash_entry *h;
225499461Sobrien      Elf_Internal_Sym *sym;
225599461Sobrien      asection *sec;
225699461Sobrien      bfd_vma off;
225799461Sobrien      bfd_vma relocation;
2258130561Sobrien      bfd_boolean unresolved_reloc;
225999461Sobrien      bfd_reloc_status_type r;
2260130561Sobrien      int tls_type;
226199461Sobrien
226299461Sobrien      r_type = ELF64_R_TYPE (rel->r_info);
226399461Sobrien      if (r_type == (int) R_390_GNU_VTINHERIT
2264130561Sobrien	  || r_type == (int) R_390_GNU_VTENTRY)
2265130561Sobrien	continue;
2266130561Sobrien      if (r_type >= (int) R_390_max)
226799461Sobrien	{
226899461Sobrien	  bfd_set_error (bfd_error_bad_value);
2269130561Sobrien	  return FALSE;
227099461Sobrien	}
227199461Sobrien
227299461Sobrien      howto = elf_howto_table + r_type;
227399461Sobrien      r_symndx = ELF64_R_SYM (rel->r_info);
2274130561Sobrien
227599461Sobrien      h = NULL;
227699461Sobrien      sym = NULL;
227799461Sobrien      sec = NULL;
2278130561Sobrien      unresolved_reloc = FALSE;
227999461Sobrien      if (r_symndx < symtab_hdr->sh_info)
228099461Sobrien	{
228199461Sobrien	  sym = local_syms + r_symndx;
228299461Sobrien	  sec = local_sections[r_symndx];
2283130561Sobrien	  relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
228499461Sobrien	}
228599461Sobrien      else
228699461Sobrien	{
2287130561Sobrien	  bfd_boolean warned ATTRIBUTE_UNUSED;
228899461Sobrien
2289130561Sobrien	  RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
2290130561Sobrien				   r_symndx, symtab_hdr, sym_hashes,
2291130561Sobrien				   h, sec, relocation,
2292130561Sobrien				   unresolved_reloc, warned);
229399461Sobrien	}
229499461Sobrien
2295218822Sdim      if (sec != NULL && elf_discarded_section (sec))
2296218822Sdim	{
2297218822Sdim	  /* For relocs against symbols from removed linkonce sections,
2298218822Sdim	     or sections discarded by a linker script, we just want the
2299218822Sdim	     section contents zeroed.  Avoid any special processing.  */
2300218822Sdim	  _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
2301218822Sdim	  rel->r_info = 0;
2302218822Sdim	  rel->r_addend = 0;
2303218822Sdim	  continue;
2304218822Sdim	}
2305218822Sdim
2306218822Sdim      if (info->relocatable)
2307218822Sdim	continue;
2308218822Sdim
230999461Sobrien      switch (r_type)
231099461Sobrien	{
2311130561Sobrien	case R_390_GOTPLT12:
2312130561Sobrien	case R_390_GOTPLT16:
2313130561Sobrien	case R_390_GOTPLT20:
2314130561Sobrien	case R_390_GOTPLT32:
2315130561Sobrien	case R_390_GOTPLT64:
2316130561Sobrien	case R_390_GOTPLTENT:
2317130561Sobrien	  /* There are three cases for a GOTPLT relocation. 1) The
2318130561Sobrien	     relocation is against the jump slot entry of a plt that
2319130561Sobrien	     will get emitted to the output file. 2) The relocation
2320130561Sobrien	     is against the jump slot of a plt entry that has been
2321130561Sobrien	     removed. elf_s390_adjust_gotplt has created a GOT entry
2322130561Sobrien	     as replacement. 3) The relocation is against a local symbol.
2323130561Sobrien	     Cases 2) and 3) are the same as the GOT relocation code
2324130561Sobrien	     so we just have to test for case 1 and fall through for
2325130561Sobrien	     the other two.  */
2326130561Sobrien	  if (h != NULL && h->plt.offset != (bfd_vma) -1)
2327130561Sobrien	    {
2328130561Sobrien	      bfd_vma plt_index;
2329130561Sobrien
2330130561Sobrien	      /* Calc. index no.
2331130561Sobrien		 Current offset - size first entry / entry size.  */
2332130561Sobrien	      plt_index = (h->plt.offset - PLT_FIRST_ENTRY_SIZE) /
2333130561Sobrien		PLT_ENTRY_SIZE;
2334130561Sobrien
2335130561Sobrien	      /* Offset in GOT is PLT index plus GOT headers(3) times 4,
2336130561Sobrien		 addr & GOT addr.  */
2337130561Sobrien	      relocation = (plt_index + 3) * GOT_ENTRY_SIZE;
2338130561Sobrien	      unresolved_reloc = FALSE;
2339130561Sobrien
2340130561Sobrien	      if (r_type == R_390_GOTPLTENT)
2341130561Sobrien		relocation += htab->sgot->output_section->vma;
2342130561Sobrien	      break;
2343130561Sobrien	    }
2344130561Sobrien	  /* Fall through.  */
2345130561Sobrien
2346130561Sobrien	case R_390_GOT12:
2347130561Sobrien	case R_390_GOT16:
2348130561Sobrien	case R_390_GOT20:
2349130561Sobrien	case R_390_GOT32:
2350130561Sobrien	case R_390_GOT64:
2351130561Sobrien	case R_390_GOTENT:
2352130561Sobrien	  /* Relocation is to the entry for this symbol in the global
2353130561Sobrien	     offset table.  */
235499461Sobrien	  if (htab->sgot == NULL)
235599461Sobrien	    abort ();
235699461Sobrien
2357130561Sobrien	  if (h != NULL)
2358130561Sobrien	    {
2359130561Sobrien	      bfd_boolean dyn;
236099461Sobrien
2361130561Sobrien	      off = h->got.offset;
236299461Sobrien	      dyn = htab->elf.dynamic_sections_created;
2363130561Sobrien	      if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
2364130561Sobrien		  || (info->shared
2365130561Sobrien		      && (info->symbolic
236699461Sobrien			  || h->dynindx == -1
2367218822Sdim			  || h->forced_local)
2368218822Sdim		      && h->def_regular)
2369130561Sobrien		  || (ELF_ST_VISIBILITY (h->other)
2370130561Sobrien		      && h->root.type == bfd_link_hash_undefweak))
2371130561Sobrien		{
2372130561Sobrien		  /* This is actually a static link, or it is a
2373130561Sobrien		     -Bsymbolic link and the symbol is defined
2374130561Sobrien		     locally, or the symbol was forced to be local
2375130561Sobrien		     because of a version file.  We must initialize
2376130561Sobrien		     this entry in the global offset table.  Since the
2377130561Sobrien		     offset must always be a multiple of 2, we use the
2378130561Sobrien		     least significant bit to record whether we have
2379130561Sobrien		     initialized it already.
238099461Sobrien
2381130561Sobrien		     When doing a dynamic link, we create a .rel.got
2382130561Sobrien		     relocation entry to initialize the value.  This
2383130561Sobrien		     is done in the finish_dynamic_symbol routine.  */
2384130561Sobrien		  if ((off & 1) != 0)
2385130561Sobrien		    off &= ~1;
2386130561Sobrien		  else
2387130561Sobrien		    {
238899461Sobrien		      bfd_put_64 (output_bfd, relocation,
238999461Sobrien				  htab->sgot->contents + off);
2390130561Sobrien		      h->got.offset |= 1;
2391130561Sobrien		    }
2392130561Sobrien		}
239399461Sobrien	      else
2394130561Sobrien		unresolved_reloc = FALSE;
2395130561Sobrien	    }
2396130561Sobrien	  else
2397130561Sobrien	    {
239899461Sobrien	      if (local_got_offsets == NULL)
239999461Sobrien		abort ();
240099461Sobrien
2401130561Sobrien	      off = local_got_offsets[r_symndx];
240299461Sobrien
2403130561Sobrien	      /* The offset must always be a multiple of 8.  We use
2404130561Sobrien		 the least significant bit to record whether we have
2405130561Sobrien		 already generated the necessary reloc.  */
2406130561Sobrien	      if ((off & 1) != 0)
2407130561Sobrien		off &= ~1;
2408130561Sobrien	      else
2409130561Sobrien		{
2410130561Sobrien		  bfd_put_64 (output_bfd, relocation,
241199461Sobrien			      htab->sgot->contents + off);
241299461Sobrien
2413130561Sobrien		  if (info->shared)
2414130561Sobrien		    {
2415130561Sobrien		      asection *s;
2416130561Sobrien		      Elf_Internal_Rela outrel;
2417130561Sobrien		      bfd_byte *loc;
241899461Sobrien
2419130561Sobrien		      s = htab->srelgot;
2420130561Sobrien		      if (s == NULL)
242199461Sobrien			abort ();
242299461Sobrien
2423130561Sobrien		      outrel.r_offset = (htab->sgot->output_section->vma
2424130561Sobrien					 + htab->sgot->output_offset
2425130561Sobrien					 + off);
2426130561Sobrien		      outrel.r_info = ELF64_R_INFO (0, R_390_RELATIVE);
242799461Sobrien		      outrel.r_addend = relocation;
2428130561Sobrien		      loc = s->contents;
2429130561Sobrien		      loc += s->reloc_count++ * sizeof (Elf64_External_Rela);
2430130561Sobrien		      bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
2431130561Sobrien		    }
243299461Sobrien
2433130561Sobrien		  local_got_offsets[r_symndx] |= 1;
2434130561Sobrien		}
2435130561Sobrien	    }
243699461Sobrien
243799461Sobrien	  if (off >= (bfd_vma) -2)
243899461Sobrien	    abort ();
243999461Sobrien
244099461Sobrien	  relocation = htab->sgot->output_offset + off;
244199461Sobrien
2442130561Sobrien	  /* For @GOTENT the relocation is against the offset between
2443130561Sobrien	     the instruction and the symbols entry in the GOT and not
2444130561Sobrien	     between the start of the GOT and the symbols entry. We
2445130561Sobrien	     add the vma of the GOT to get the correct value.  */
2446130561Sobrien	  if (   r_type == R_390_GOTENT
2447130561Sobrien	      || r_type == R_390_GOTPLTENT)
244899461Sobrien	    relocation += htab->sgot->output_section->vma;
244999461Sobrien
2450130561Sobrien	  break;
245199461Sobrien
2452130561Sobrien	case R_390_GOTOFF16:
2453130561Sobrien	case R_390_GOTOFF32:
2454130561Sobrien	case R_390_GOTOFF64:
2455130561Sobrien	  /* Relocation is relative to the start of the global offset
2456130561Sobrien	     table.  */
245799461Sobrien
2458130561Sobrien	  /* Note that sgot->output_offset is not involved in this
2459130561Sobrien	     calculation.  We always want the start of .got.  If we
2460130561Sobrien	     defined _GLOBAL_OFFSET_TABLE in a different way, as is
2461130561Sobrien	     permitted by the ABI, we might have to change this
2462130561Sobrien	     calculation.  */
2463130561Sobrien	  relocation -= htab->sgot->output_section->vma;
2464130561Sobrien	  break;
246599461Sobrien
2466130561Sobrien	case R_390_GOTPC:
246799461Sobrien	case R_390_GOTPCDBL:
2468130561Sobrien	  /* Use global offset table as symbol value.  */
2469130561Sobrien	  relocation = htab->sgot->output_section->vma;
2470130561Sobrien	  unresolved_reloc = FALSE;
2471130561Sobrien	  break;
247299461Sobrien
2473130561Sobrien	case R_390_PLT16DBL:
2474130561Sobrien	case R_390_PLT32:
2475130561Sobrien	case R_390_PLT32DBL:
2476130561Sobrien	case R_390_PLT64:
2477130561Sobrien	  /* Relocation is to the entry for this symbol in the
2478130561Sobrien	     procedure linkage table.  */
247999461Sobrien
2480130561Sobrien	  /* Resolve a PLT32 reloc against a local symbol directly,
2481130561Sobrien	     without using the procedure linkage table.  */
2482130561Sobrien	  if (h == NULL)
2483130561Sobrien	    break;
248499461Sobrien
2485130561Sobrien	  if (h->plt.offset == (bfd_vma) -1
248699461Sobrien	      || htab->splt == NULL)
2487130561Sobrien	    {
2488130561Sobrien	      /* We didn't make a PLT entry for this symbol.  This
2489130561Sobrien		 happens when statically linking PIC code, or when
2490130561Sobrien		 using -Bsymbolic.  */
2491130561Sobrien	      break;
2492130561Sobrien	    }
249399461Sobrien
2494130561Sobrien	  relocation = (htab->splt->output_section->vma
2495130561Sobrien			+ htab->splt->output_offset
2496130561Sobrien			+ h->plt.offset);
2497130561Sobrien	  unresolved_reloc = FALSE;
2498130561Sobrien	  break;
249999461Sobrien
2500130561Sobrien	case R_390_PLTOFF16:
2501130561Sobrien	case R_390_PLTOFF32:
2502130561Sobrien	case R_390_PLTOFF64:
2503130561Sobrien	  /* Relocation is to the entry for this symbol in the
2504130561Sobrien	     procedure linkage table relative to the start of the GOT.  */
2505130561Sobrien
2506130561Sobrien	  /* For local symbols or if we didn't make a PLT entry for
2507130561Sobrien	     this symbol resolve the symbol directly.  */
2508130561Sobrien	  if (   h == NULL
2509130561Sobrien	      || h->plt.offset == (bfd_vma) -1
2510130561Sobrien	      || htab->splt == NULL)
2511130561Sobrien	    {
2512130561Sobrien	      relocation -= htab->sgot->output_section->vma;
2513130561Sobrien	      break;
2514130561Sobrien	    }
2515130561Sobrien
2516130561Sobrien	  relocation = (htab->splt->output_section->vma
2517130561Sobrien			+ htab->splt->output_offset
2518130561Sobrien			+ h->plt.offset
2519130561Sobrien			- htab->sgot->output_section->vma);
2520130561Sobrien	  unresolved_reloc = FALSE;
2521130561Sobrien	  break;
2522130561Sobrien
2523130561Sobrien	case R_390_8:
2524130561Sobrien	case R_390_16:
2525130561Sobrien	case R_390_32:
2526130561Sobrien	case R_390_64:
2527130561Sobrien	case R_390_PC16:
2528130561Sobrien	case R_390_PC16DBL:
2529130561Sobrien	case R_390_PC32:
253099461Sobrien	case R_390_PC32DBL:
2531130561Sobrien	case R_390_PC64:
2532218822Sdim	  if ((input_section->flags & SEC_ALLOC) == 0)
253399461Sobrien	    break;
253499461Sobrien
2535130561Sobrien	  if ((info->shared
2536130561Sobrien	       && (h == NULL
2537130561Sobrien		   || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
2538130561Sobrien		   || h->root.type != bfd_link_hash_undefweak)
253999461Sobrien	       && ((r_type != R_390_PC16
254099461Sobrien		    && r_type != R_390_PC16DBL
254199461Sobrien		    && r_type != R_390_PC32
254299461Sobrien		    && r_type != R_390_PC32DBL
254399461Sobrien		    && r_type != R_390_PC64)
254499461Sobrien		   || (h != NULL
2545130561Sobrien		       && !SYMBOL_REFERENCES_LOCAL (info, h))))
2546130561Sobrien	      || (ELIMINATE_COPY_RELOCS
2547130561Sobrien		  && !info->shared
254899461Sobrien		  && h != NULL
254999461Sobrien		  && h->dynindx != -1
2550218822Sdim		  && !h->non_got_ref
2551218822Sdim		  && ((h->def_dynamic
2552218822Sdim		       && !h->def_regular)
255399461Sobrien		      || h->root.type == bfd_link_hash_undefweak
255499461Sobrien		      || h->root.type == bfd_link_hash_undefined)))
2555130561Sobrien	    {
2556130561Sobrien	      Elf_Internal_Rela outrel;
2557130561Sobrien	      bfd_boolean skip, relocate;
255899461Sobrien	      asection *sreloc;
2559130561Sobrien	      bfd_byte *loc;
256099461Sobrien
2561130561Sobrien	      /* When generating a shared object, these relocations
2562130561Sobrien		 are copied into the output file to be resolved at run
2563130561Sobrien		 time.  */
2564130561Sobrien	      skip = FALSE;
2565130561Sobrien	      relocate = FALSE;
256699461Sobrien
256799461Sobrien	      outrel.r_offset =
256899461Sobrien		_bfd_elf_section_offset (output_bfd, info, input_section,
256999461Sobrien					 rel->r_offset);
257099461Sobrien	      if (outrel.r_offset == (bfd_vma) -1)
2571130561Sobrien		skip = TRUE;
257299461Sobrien	      else if (outrel.r_offset == (bfd_vma) -2)
2573130561Sobrien		skip = TRUE, relocate = TRUE;
257499461Sobrien
2575130561Sobrien	      outrel.r_offset += (input_section->output_section->vma
2576130561Sobrien				  + input_section->output_offset);
257799461Sobrien
2578130561Sobrien	      if (skip)
257999461Sobrien		memset (&outrel, 0, sizeof outrel);
2580130561Sobrien	      else if (h != NULL
258199461Sobrien		       && h->dynindx != -1
258299461Sobrien		       && (r_type == R_390_PC16
258399461Sobrien			   || r_type == R_390_PC16DBL
258499461Sobrien			   || r_type == R_390_PC32
258599461Sobrien			   || r_type == R_390_PC32DBL
258699461Sobrien			   || r_type == R_390_PC64
258799461Sobrien			   || !info->shared
258899461Sobrien			   || !info->symbolic
2589218822Sdim			   || !h->def_regular))
2590130561Sobrien		{
2591130561Sobrien		  outrel.r_info = ELF64_R_INFO (h->dynindx, r_type);
259299461Sobrien		  outrel.r_addend = rel->r_addend;
2593130561Sobrien		}
2594130561Sobrien	      else
2595130561Sobrien		{
259699461Sobrien		  /* This symbol is local, or marked to become local.  */
259799461Sobrien		  outrel.r_addend = relocation + rel->r_addend;
2598130561Sobrien		  if (r_type == R_390_64)
2599130561Sobrien		    {
2600130561Sobrien		      relocate = TRUE;
2601130561Sobrien		      outrel.r_info = ELF64_R_INFO (0, R_390_RELATIVE);
2602130561Sobrien		    }
2603130561Sobrien		  else
2604130561Sobrien		    {
2605130561Sobrien		      long sindx;
2606130561Sobrien
2607130561Sobrien		      if (bfd_is_abs_section (sec))
2608130561Sobrien			sindx = 0;
2609130561Sobrien		      else if (sec == NULL || sec->owner == NULL)
2610130561Sobrien			{
2611130561Sobrien			  bfd_set_error(bfd_error_bad_value);
2612130561Sobrien			  return FALSE;
2613130561Sobrien			}
2614130561Sobrien		      else
2615130561Sobrien			{
2616130561Sobrien			  asection *osec;
2617130561Sobrien
2618130561Sobrien			  osec = sec->output_section;
2619130561Sobrien			  sindx = elf_section_data (osec)->dynindx;
2620130561Sobrien
2621218822Sdim			  if (sindx == 0)
2622218822Sdim			    {
2623218822Sdim			      osec = htab->elf.text_index_section;
2624218822Sdim			      sindx = elf_section_data (osec)->dynindx;
2625218822Sdim			    }
2626218822Sdim			  BFD_ASSERT (sindx != 0);
2627218822Sdim
2628130561Sobrien			  /* We are turning this relocation into one
2629130561Sobrien			     against a section symbol, so subtract out
2630130561Sobrien			     the output section's address but not the
2631130561Sobrien			     offset of the input section in the output
2632130561Sobrien			     section.  */
2633130561Sobrien			  outrel.r_addend -= osec->vma;
2634130561Sobrien			}
2635130561Sobrien		      outrel.r_info = ELF64_R_INFO (sindx, r_type);
2636130561Sobrien		    }
263799461Sobrien		}
263899461Sobrien
263999461Sobrien	      sreloc = elf_section_data (input_section)->sreloc;
264099461Sobrien	      if (sreloc == NULL)
264199461Sobrien		abort ();
264299461Sobrien
2643130561Sobrien	      loc = sreloc->contents;
2644130561Sobrien	      loc += sreloc->reloc_count++ * sizeof (Elf64_External_Rela);
2645130561Sobrien	      bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
264699461Sobrien
2647130561Sobrien	      /* If this reloc is against an external symbol, we do
2648130561Sobrien		 not want to fiddle with the addend.  Otherwise, we
2649130561Sobrien		 need to include the symbol value so that it becomes
2650130561Sobrien		 an addend for the dynamic reloc.  */
2651130561Sobrien	      if (! relocate)
2652130561Sobrien		continue;
2653130561Sobrien	    }
265499461Sobrien
2655130561Sobrien	  break;
265699461Sobrien
2657130561Sobrien	  /* Relocations for tls literal pool entries.  */
2658130561Sobrien	case R_390_TLS_IE64:
2659130561Sobrien	  if (info->shared)
2660130561Sobrien	    {
2661130561Sobrien	      Elf_Internal_Rela outrel;
2662130561Sobrien	      asection *sreloc;
2663130561Sobrien	      bfd_byte *loc;
266499461Sobrien
2665130561Sobrien	      outrel.r_offset = rel->r_offset
2666130561Sobrien				+ input_section->output_section->vma
2667130561Sobrien				+ input_section->output_offset;
2668130561Sobrien	      outrel.r_info = ELF64_R_INFO (0, R_390_RELATIVE);
2669130561Sobrien	      sreloc = elf_section_data (input_section)->sreloc;
2670130561Sobrien	      if (sreloc == NULL)
2671130561Sobrien		abort ();
2672130561Sobrien	      loc = sreloc->contents;
2673130561Sobrien	      loc += sreloc->reloc_count++ * sizeof (Elf64_External_Rela);
2674130561Sobrien	      bfd_elf64_swap_reloc_out (output_bfd, &outrel, loc);
2675130561Sobrien	    }
2676130561Sobrien	  /* Fall through.  */
2677130561Sobrien
2678130561Sobrien	case R_390_TLS_GD64:
2679130561Sobrien	case R_390_TLS_GOTIE64:
2680130561Sobrien	  r_type = elf_s390_tls_transition (info, r_type, h == NULL);
2681130561Sobrien	  tls_type = GOT_UNKNOWN;
2682130561Sobrien	  if (h == NULL && local_got_offsets)
2683130561Sobrien	    tls_type = elf_s390_local_got_tls_type (input_bfd) [r_symndx];
2684130561Sobrien	  else if (h != NULL)
2685130561Sobrien	    {
2686130561Sobrien	      tls_type = elf_s390_hash_entry(h)->tls_type;
2687130561Sobrien	      if (!info->shared && h->dynindx == -1 && tls_type >= GOT_TLS_IE)
2688130561Sobrien		r_type = R_390_TLS_LE64;
2689130561Sobrien	    }
2690130561Sobrien	  if (r_type == R_390_TLS_GD64 && tls_type >= GOT_TLS_IE)
2691130561Sobrien	    r_type = R_390_TLS_IE64;
2692130561Sobrien
2693130561Sobrien	  if (r_type == R_390_TLS_LE64)
2694130561Sobrien	    {
2695130561Sobrien	      /* This relocation gets optimized away by the local exec
2696130561Sobrien		 access optimization.  */
2697130561Sobrien	      BFD_ASSERT (! unresolved_reloc);
2698130561Sobrien	      bfd_put_64 (output_bfd, -tpoff (info, relocation),
2699130561Sobrien			  contents + rel->r_offset);
2700130561Sobrien	      continue;
2701130561Sobrien	    }
2702130561Sobrien
2703130561Sobrien	  if (htab->sgot == NULL)
2704130561Sobrien	    abort ();
2705130561Sobrien
2706130561Sobrien	  if (h != NULL)
2707130561Sobrien	    off = h->got.offset;
2708130561Sobrien	  else
2709130561Sobrien	    {
2710130561Sobrien	      if (local_got_offsets == NULL)
2711130561Sobrien		abort ();
2712130561Sobrien
2713130561Sobrien	      off = local_got_offsets[r_symndx];
2714130561Sobrien	    }
2715130561Sobrien
2716130561Sobrien	emit_tls_relocs:
2717130561Sobrien
2718130561Sobrien	  if ((off & 1) != 0)
2719130561Sobrien	    off &= ~1;
2720130561Sobrien	  else
2721130561Sobrien	    {
2722130561Sobrien	      Elf_Internal_Rela outrel;
2723130561Sobrien	      bfd_byte *loc;
2724130561Sobrien	      int dr_type, indx;
2725130561Sobrien
2726130561Sobrien	      if (htab->srelgot == NULL)
2727130561Sobrien		abort ();
2728130561Sobrien
2729130561Sobrien	      outrel.r_offset = (htab->sgot->output_section->vma
2730130561Sobrien				 + htab->sgot->output_offset + off);
2731130561Sobrien
2732130561Sobrien	      indx = h && h->dynindx != -1 ? h->dynindx : 0;
2733130561Sobrien	      if (r_type == R_390_TLS_GD64)
2734130561Sobrien		dr_type = R_390_TLS_DTPMOD;
2735130561Sobrien	      else
2736130561Sobrien		dr_type = R_390_TLS_TPOFF;
2737130561Sobrien	      if (dr_type == R_390_TLS_TPOFF && indx == 0)
2738130561Sobrien		outrel.r_addend = relocation - dtpoff_base (info);
2739130561Sobrien	      else
2740130561Sobrien		outrel.r_addend = 0;
2741130561Sobrien	      outrel.r_info = ELF64_R_INFO (indx, dr_type);
2742130561Sobrien	      loc = htab->srelgot->contents;
2743130561Sobrien	      loc += htab->srelgot->reloc_count++
2744130561Sobrien		* sizeof (Elf64_External_Rela);
2745130561Sobrien	      bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
2746130561Sobrien
2747130561Sobrien	      if (r_type == R_390_TLS_GD64)
2748130561Sobrien		{
2749130561Sobrien		  if (indx == 0)
2750130561Sobrien		    {
2751130561Sobrien	    	      BFD_ASSERT (! unresolved_reloc);
2752130561Sobrien		      bfd_put_64 (output_bfd,
2753130561Sobrien				  relocation - dtpoff_base (info),
2754130561Sobrien				  htab->sgot->contents + off + GOT_ENTRY_SIZE);
2755130561Sobrien		    }
2756130561Sobrien		  else
2757130561Sobrien		    {
2758130561Sobrien		      outrel.r_info = ELF64_R_INFO (indx, R_390_TLS_DTPOFF);
2759130561Sobrien		      outrel.r_offset += GOT_ENTRY_SIZE;
2760130561Sobrien		      outrel.r_addend = 0;
2761130561Sobrien		      htab->srelgot->reloc_count++;
2762130561Sobrien		      loc += sizeof (Elf64_External_Rela);
2763130561Sobrien		      bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
2764130561Sobrien		    }
2765130561Sobrien		}
2766130561Sobrien
2767130561Sobrien	      if (h != NULL)
2768130561Sobrien		h->got.offset |= 1;
2769130561Sobrien	      else
2770130561Sobrien		local_got_offsets[r_symndx] |= 1;
2771130561Sobrien	    }
2772130561Sobrien
2773130561Sobrien	  if (off >= (bfd_vma) -2)
2774130561Sobrien	    abort ();
2775130561Sobrien	  if (r_type == ELF64_R_TYPE (rel->r_info))
2776130561Sobrien	    {
2777130561Sobrien	      relocation = htab->sgot->output_offset + off;
2778130561Sobrien	      if (r_type == R_390_TLS_IE64 || r_type == R_390_TLS_IEENT)
2779130561Sobrien		relocation += htab->sgot->output_section->vma;
2780130561Sobrien	      unresolved_reloc = FALSE;
2781130561Sobrien	    }
2782130561Sobrien	  else
2783130561Sobrien	    {
2784130561Sobrien	      bfd_put_64 (output_bfd, htab->sgot->output_offset + off,
2785130561Sobrien			  contents + rel->r_offset);
2786130561Sobrien	      continue;
2787130561Sobrien	    }
2788130561Sobrien	  break;
2789130561Sobrien
2790130561Sobrien	case R_390_TLS_GOTIE12:
2791130561Sobrien	case R_390_TLS_GOTIE20:
2792130561Sobrien	case R_390_TLS_IEENT:
2793130561Sobrien	  if (h == NULL)
2794130561Sobrien	    {
2795130561Sobrien	      if (local_got_offsets == NULL)
2796130561Sobrien		abort();
2797130561Sobrien	      off = local_got_offsets[r_symndx];
2798130561Sobrien	      if (info->shared)
2799130561Sobrien		goto emit_tls_relocs;
2800130561Sobrien	    }
2801130561Sobrien	  else
2802130561Sobrien	    {
2803130561Sobrien	      off = h->got.offset;
2804130561Sobrien	      tls_type = elf_s390_hash_entry(h)->tls_type;
2805130561Sobrien	      if (info->shared || h->dynindx != -1 || tls_type < GOT_TLS_IE)
2806130561Sobrien		goto emit_tls_relocs;
2807130561Sobrien	    }
2808130561Sobrien
2809130561Sobrien	  if (htab->sgot == NULL)
2810130561Sobrien	    abort ();
2811130561Sobrien
2812130561Sobrien	  BFD_ASSERT (! unresolved_reloc);
2813130561Sobrien	  bfd_put_64 (output_bfd, -tpoff (info, relocation),
2814130561Sobrien		      htab->sgot->contents + off);
2815130561Sobrien	  relocation = htab->sgot->output_offset + off;
2816130561Sobrien	  if (r_type == R_390_TLS_IEENT)
2817130561Sobrien	    relocation += htab->sgot->output_section->vma;
2818130561Sobrien	  unresolved_reloc = FALSE;
2819130561Sobrien	  break;
2820130561Sobrien
2821130561Sobrien	case R_390_TLS_LDM64:
2822130561Sobrien	  if (! info->shared)
2823130561Sobrien	    /* The literal pool entry this relocation refers to gets ignored
2824130561Sobrien	       by the optimized code of the local exec model. Do nothing
2825130561Sobrien	       and the value will turn out zero.  */
2826130561Sobrien	    continue;
2827130561Sobrien
2828130561Sobrien	  if (htab->sgot == NULL)
2829130561Sobrien	    abort ();
2830130561Sobrien
2831130561Sobrien	  off = htab->tls_ldm_got.offset;
2832130561Sobrien	  if (off & 1)
2833130561Sobrien	    off &= ~1;
2834130561Sobrien	  else
2835130561Sobrien	    {
2836130561Sobrien	      Elf_Internal_Rela outrel;
2837130561Sobrien	      bfd_byte *loc;
2838130561Sobrien
2839130561Sobrien	      if (htab->srelgot == NULL)
2840130561Sobrien		abort ();
2841130561Sobrien
2842130561Sobrien	      outrel.r_offset = (htab->sgot->output_section->vma
2843130561Sobrien				 + htab->sgot->output_offset + off);
2844130561Sobrien
2845130561Sobrien	      bfd_put_64 (output_bfd, 0,
2846130561Sobrien			  htab->sgot->contents + off + GOT_ENTRY_SIZE);
2847130561Sobrien	      outrel.r_info = ELF64_R_INFO (0, R_390_TLS_DTPMOD);
2848130561Sobrien	      outrel.r_addend = 0;
2849130561Sobrien	      loc = htab->srelgot->contents;
2850130561Sobrien	      loc += htab->srelgot->reloc_count++
2851130561Sobrien		* sizeof (Elf64_External_Rela);
2852130561Sobrien	      bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
2853130561Sobrien	      htab->tls_ldm_got.offset |= 1;
2854130561Sobrien	    }
2855130561Sobrien	  relocation = htab->sgot->output_offset + off;
2856130561Sobrien	  unresolved_reloc = FALSE;
2857130561Sobrien	  break;
2858130561Sobrien
2859130561Sobrien	case R_390_TLS_LE64:
2860130561Sobrien	  if (info->shared)
2861130561Sobrien	    {
2862130561Sobrien	      /* Linking a shared library with non-fpic code requires
2863130561Sobrien		 a R_390_TLS_TPOFF relocation.  */
2864130561Sobrien	      Elf_Internal_Rela outrel;
2865130561Sobrien	      asection *sreloc;
2866130561Sobrien	      bfd_byte *loc;
2867130561Sobrien	      int indx;
2868130561Sobrien
2869130561Sobrien	      outrel.r_offset = rel->r_offset
2870130561Sobrien				+ input_section->output_section->vma
2871130561Sobrien				+ input_section->output_offset;
2872130561Sobrien	      if (h != NULL && h->dynindx != -1)
2873130561Sobrien		indx = h->dynindx;
2874130561Sobrien	      else
2875130561Sobrien		indx = 0;
2876130561Sobrien	      outrel.r_info = ELF64_R_INFO (indx, R_390_TLS_TPOFF);
2877130561Sobrien	      if (indx == 0)
2878130561Sobrien		outrel.r_addend = relocation - dtpoff_base (info);
2879130561Sobrien	      else
2880130561Sobrien		outrel.r_addend = 0;
2881130561Sobrien	      sreloc = elf_section_data (input_section)->sreloc;
2882130561Sobrien	      if (sreloc == NULL)
2883130561Sobrien		abort ();
2884130561Sobrien	      loc = sreloc->contents;
2885130561Sobrien	      loc += sreloc->reloc_count++ * sizeof (Elf64_External_Rela);
2886130561Sobrien	      bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
2887130561Sobrien	    }
2888130561Sobrien	  else
2889130561Sobrien	    {
2890130561Sobrien	      BFD_ASSERT (! unresolved_reloc);
2891130561Sobrien	      bfd_put_64 (output_bfd, -tpoff (info, relocation),
2892130561Sobrien			  contents + rel->r_offset);
2893130561Sobrien	    }
2894130561Sobrien	  continue;
2895130561Sobrien
2896130561Sobrien	case R_390_TLS_LDO64:
2897218822Sdim	  if (info->shared)
2898130561Sobrien	    relocation -= dtpoff_base (info);
2899130561Sobrien	  else
2900130561Sobrien	    /* When converting LDO to LE, we must negate.  */
2901130561Sobrien	    relocation = -tpoff (info, relocation);
2902130561Sobrien	  break;
2903130561Sobrien
2904130561Sobrien	  /* Relocations for tls instructions.  */
2905130561Sobrien	case R_390_TLS_LOAD:
2906130561Sobrien	case R_390_TLS_GDCALL:
2907130561Sobrien	case R_390_TLS_LDCALL:
2908130561Sobrien	  tls_type = GOT_UNKNOWN;
2909130561Sobrien	  if (h == NULL && local_got_offsets)
2910130561Sobrien	    tls_type = elf_s390_local_got_tls_type (input_bfd) [r_symndx];
2911130561Sobrien	  else if (h != NULL)
2912130561Sobrien	    tls_type = elf_s390_hash_entry(h)->tls_type;
2913130561Sobrien
2914130561Sobrien	  if (tls_type == GOT_TLS_GD)
2915130561Sobrien	    continue;
2916130561Sobrien
2917130561Sobrien	  if (r_type == R_390_TLS_LOAD)
2918130561Sobrien	    {
2919130561Sobrien	      if (!info->shared && (h == NULL || h->dynindx == -1))
2920130561Sobrien		{
2921130561Sobrien		  /* IE->LE transition. Four valid cases:
2922130561Sobrien		     lg %rx,(0,%ry)    -> sllg %rx,%ry,0
2923130561Sobrien		     lg %rx,(%ry,0)    -> sllg %rx,%ry,0
2924130561Sobrien		     lg %rx,(%ry,%r12) -> sllg %rx,%ry,0
2925130561Sobrien		     lg %rx,(%r12,%ry) -> sllg %rx,%ry,0  */
2926130561Sobrien		  unsigned int insn0, insn1, ry;
2927130561Sobrien
2928130561Sobrien		  insn0 = bfd_get_32 (input_bfd, contents + rel->r_offset);
2929130561Sobrien		  insn1 = bfd_get_16 (input_bfd, contents + rel->r_offset + 4);
2930130561Sobrien		  if (insn1 != 0x0004)
2931130561Sobrien		    invalid_tls_insn (input_bfd, input_section, rel);
2932130561Sobrien		  ry = 0;
2933130561Sobrien		  if ((insn0 & 0xff00f000) == 0xe3000000)
2934130561Sobrien		    /* lg %rx,0(%ry,0) -> sllg %rx,%ry,0  */
2935130561Sobrien		    ry = (insn0 & 0x000f0000);
2936130561Sobrien		  else if ((insn0 & 0xff0f0000) == 0xe3000000)
2937130561Sobrien		    /* lg %rx,0(0,%ry) -> sllg %rx,%ry,0  */
2938130561Sobrien		    ry = (insn0 & 0x0000f000) << 4;
2939130561Sobrien		  else if ((insn0 & 0xff00f000) == 0xe300c000)
2940130561Sobrien		    /* lg %rx,0(%ry,%r12) -> sllg %rx,%ry,0  */
2941130561Sobrien		    ry = (insn0 & 0x000f0000);
2942130561Sobrien		  else if ((insn0 & 0xff0f0000) == 0xe30c0000)
2943130561Sobrien		    /* lg %rx,0(%r12,%ry) -> sllg %rx,%ry,0  */
2944130561Sobrien		    ry = (insn0 & 0x0000f000) << 4;
2945130561Sobrien		  else
2946130561Sobrien		    invalid_tls_insn (input_bfd, input_section, rel);
2947130561Sobrien		  insn0 = 0xeb000000 | (insn0 & 0x00f00000) | ry;
2948130561Sobrien		  insn1 = 0x000d;
2949130561Sobrien		  bfd_put_32 (output_bfd, insn0, contents + rel->r_offset);
2950130561Sobrien		  bfd_put_16 (output_bfd, insn1, contents + rel->r_offset + 4);
2951130561Sobrien		}
2952130561Sobrien	    }
2953130561Sobrien	  else if (r_type == R_390_TLS_GDCALL)
2954130561Sobrien	    {
2955130561Sobrien	      unsigned int insn0, insn1;
2956130561Sobrien
2957130561Sobrien	      insn0 = bfd_get_32 (input_bfd, contents + rel->r_offset);
2958130561Sobrien	      insn1 = bfd_get_16 (input_bfd, contents + rel->r_offset + 4);
2959130561Sobrien	      if ((insn0 & 0xffff0000) != 0xc0e50000)
2960130561Sobrien		invalid_tls_insn (input_bfd, input_section, rel);
2961130561Sobrien	      if (!info->shared && (h == NULL || h->dynindx == -1))
2962130561Sobrien		{
2963130561Sobrien		  /* GD->LE transition.
2964130561Sobrien		     brasl %r14,__tls_get_addr@plt -> brcl 0,. */
2965130561Sobrien		  insn0 = 0xc0040000;
2966130561Sobrien		  insn1 = 0x0000;
2967130561Sobrien		}
2968130561Sobrien	      else
2969130561Sobrien		{
2970130561Sobrien		  /* GD->IE transition.
2971130561Sobrien		     brasl %r14,__tls_get_addr@plt -> lg %r2,0(%r2,%r12)  */
2972130561Sobrien		  insn0 = 0xe322c000;
2973130561Sobrien		  insn1 = 0x0004;
2974130561Sobrien		}
2975130561Sobrien	      bfd_put_32 (output_bfd, insn0, contents + rel->r_offset);
2976130561Sobrien	      bfd_put_16 (output_bfd, insn1, contents + rel->r_offset + 4);
2977130561Sobrien	    }
2978130561Sobrien	  else if (r_type == R_390_TLS_LDCALL)
2979130561Sobrien	    {
2980130561Sobrien	      if (!info->shared)
2981130561Sobrien		{
2982130561Sobrien		  unsigned int insn0, insn1;
2983130561Sobrien
2984130561Sobrien		  insn0 = bfd_get_32 (input_bfd, contents + rel->r_offset);
2985130561Sobrien		  insn1 = bfd_get_16 (input_bfd, contents + rel->r_offset + 4);
2986130561Sobrien		  if ((insn0 & 0xffff0000) != 0xc0e50000)
2987130561Sobrien		    invalid_tls_insn (input_bfd, input_section, rel);
2988130561Sobrien		  /* LD->LE transition.
2989130561Sobrien		     brasl %r14,__tls_get_addr@plt -> brcl 0,. */
2990130561Sobrien		  insn0 = 0xc0040000;
2991130561Sobrien		  insn1 = 0x0000;
2992130561Sobrien		  bfd_put_32 (output_bfd, insn0, contents + rel->r_offset);
2993130561Sobrien		  bfd_put_16 (output_bfd, insn1, contents + rel->r_offset + 4);
2994130561Sobrien		}
2995130561Sobrien	    }
2996130561Sobrien	  continue;
2997130561Sobrien
2998130561Sobrien	default:
2999130561Sobrien	  break;
3000130561Sobrien	}
3001130561Sobrien
3002107492Sobrien      /* Dynamic relocs are not propagated for SEC_DEBUGGING sections
3003107492Sobrien	 because such sections are not SEC_ALLOC and thus ld.so will
3004107492Sobrien	 not process them.  */
300599461Sobrien      if (unresolved_reloc
3006107492Sobrien	  && !((input_section->flags & SEC_DEBUGGING) != 0
3007218822Sdim	       && h->def_dynamic))
300899461Sobrien	(*_bfd_error_handler)
3009218822Sdim	  (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"),
3010218822Sdim	   input_bfd,
3011218822Sdim	   input_section,
301299461Sobrien	   (long) rel->r_offset,
3013218822Sdim	   howto->name,
301499461Sobrien	   h->root.root.string);
301599461Sobrien
3016130561Sobrien      if (r_type == R_390_20
3017130561Sobrien	  || r_type == R_390_GOT20
3018130561Sobrien	  || r_type == R_390_GOTPLT20
3019130561Sobrien	  || r_type == R_390_TLS_GOTIE20)
3020130561Sobrien	{
3021130561Sobrien	  relocation += rel->r_addend;
3022130561Sobrien	  relocation = (relocation&0xfff) << 8 | (relocation&0xff000) >> 12;
3023130561Sobrien	  r = _bfd_final_link_relocate (howto, input_bfd, input_section,
3024130561Sobrien					contents, rel->r_offset,
3025130561Sobrien					relocation, 0);
3026130561Sobrien	}
3027130561Sobrien      else
3028130561Sobrien	r = _bfd_final_link_relocate (howto, input_bfd, input_section,
302999461Sobrien				      contents, rel->r_offset,
303099461Sobrien				      relocation, rel->r_addend);
303199461Sobrien
303299461Sobrien      if (r != bfd_reloc_ok)
303399461Sobrien	{
303499461Sobrien	  const char *name;
303599461Sobrien
303699461Sobrien	  if (h != NULL)
303799461Sobrien	    name = h->root.root.string;
303899461Sobrien	  else
303999461Sobrien	    {
304099461Sobrien	      name = bfd_elf_string_from_elf_section (input_bfd,
304199461Sobrien						      symtab_hdr->sh_link,
304299461Sobrien						      sym->st_name);
304399461Sobrien	      if (name == NULL)
3044130561Sobrien		return FALSE;
304599461Sobrien	      if (*name == '\0')
304699461Sobrien		name = bfd_section_name (input_bfd, sec);
304799461Sobrien	    }
304899461Sobrien
304999461Sobrien	  if (r == bfd_reloc_overflow)
305099461Sobrien	    {
305199461Sobrien
305299461Sobrien	      if (! ((*info->callbacks->reloc_overflow)
3053218822Sdim		     (info, (h ? &h->root : NULL), name, howto->name,
3054218822Sdim		      (bfd_vma) 0, input_bfd, input_section,
3055218822Sdim		      rel->r_offset)))
3056130561Sobrien		return FALSE;
305799461Sobrien	    }
305899461Sobrien	  else
305999461Sobrien	    {
306099461Sobrien	      (*_bfd_error_handler)
3061218822Sdim		(_("%B(%A+0x%lx): reloc against `%s': error %d"),
3062218822Sdim		 input_bfd, input_section,
306399461Sobrien		 (long) rel->r_offset, name, (int) r);
3064130561Sobrien	      return FALSE;
306599461Sobrien	    }
306699461Sobrien	}
306799461Sobrien    }
306899461Sobrien
3069130561Sobrien  return TRUE;
307099461Sobrien}
307199461Sobrien
307299461Sobrien/* Finish up dynamic symbol handling.  We set the contents of various
307399461Sobrien   dynamic sections here.  */
307499461Sobrien
3075130561Sobrienstatic bfd_boolean
307699461Sobrienelf_s390_finish_dynamic_symbol (output_bfd, info, h, sym)
307799461Sobrien     bfd *output_bfd;
307899461Sobrien     struct bfd_link_info *info;
307999461Sobrien     struct elf_link_hash_entry *h;
308099461Sobrien     Elf_Internal_Sym *sym;
308199461Sobrien{
308299461Sobrien  struct elf_s390_link_hash_table *htab;
308399461Sobrien
308499461Sobrien  htab = elf_s390_hash_table (info);
308599461Sobrien
308699461Sobrien  if (h->plt.offset != (bfd_vma) -1)
308799461Sobrien    {
308899461Sobrien      bfd_vma plt_index;
308999461Sobrien      bfd_vma got_offset;
309099461Sobrien      Elf_Internal_Rela rela;
3091130561Sobrien      bfd_byte *loc;
309299461Sobrien
309399461Sobrien      /* This symbol has an entry in the procedure linkage table.  Set
3094130561Sobrien	 it up.  */
309599461Sobrien
309699461Sobrien      if (h->dynindx == -1
309799461Sobrien	  || htab->splt == NULL
309899461Sobrien	  || htab->sgotplt == NULL
309999461Sobrien	  || htab->srelplt == NULL)
310099461Sobrien	abort ();
310199461Sobrien
310299461Sobrien      /* Calc. index no.
3103130561Sobrien	 Current offset - size first entry / entry size.  */
310499461Sobrien      plt_index = (h->plt.offset - PLT_FIRST_ENTRY_SIZE) / PLT_ENTRY_SIZE;
310599461Sobrien
310699461Sobrien      /* Offset in GOT is PLT index plus GOT headers(3) times 8,
3107130561Sobrien	 addr & GOT addr.  */
310899461Sobrien      got_offset = (plt_index + 3) * GOT_ENTRY_SIZE;
310999461Sobrien
311099461Sobrien      /* Fill in the blueprint of a PLT.  */
311199461Sobrien      bfd_put_32 (output_bfd, (bfd_vma) PLT_ENTRY_WORD0,
311299461Sobrien		  htab->splt->contents + h->plt.offset);
311399461Sobrien      bfd_put_32 (output_bfd, (bfd_vma) PLT_ENTRY_WORD1,
311499461Sobrien		  htab->splt->contents + h->plt.offset + 4);
311599461Sobrien      bfd_put_32 (output_bfd, (bfd_vma) PLT_ENTRY_WORD2,
311699461Sobrien		  htab->splt->contents + h->plt.offset + 8);
311799461Sobrien      bfd_put_32 (output_bfd, (bfd_vma) PLT_ENTRY_WORD3,
311899461Sobrien		  htab->splt->contents + h->plt.offset + 12);
311999461Sobrien      bfd_put_32 (output_bfd, (bfd_vma) PLT_ENTRY_WORD4,
312099461Sobrien		  htab->splt->contents + h->plt.offset + 16);
312199461Sobrien      bfd_put_32 (output_bfd, (bfd_vma) PLT_ENTRY_WORD5,
312299461Sobrien		  htab->splt->contents + h->plt.offset + 20);
312399461Sobrien      bfd_put_32 (output_bfd, (bfd_vma) PLT_ENTRY_WORD6,
312499461Sobrien		  htab->splt->contents + h->plt.offset + 24);
312599461Sobrien      bfd_put_32 (output_bfd, (bfd_vma) PLT_ENTRY_WORD7,
312699461Sobrien		  htab->splt->contents + h->plt.offset + 28);
312799461Sobrien      /* Fixup the relative address to the GOT entry */
312899461Sobrien      bfd_put_32 (output_bfd,
312999461Sobrien		  (htab->sgotplt->output_section->vma +
313099461Sobrien		   htab->sgotplt->output_offset + got_offset
313199461Sobrien		   - (htab->splt->output_section->vma + h->plt.offset))/2,
313299461Sobrien		  htab->splt->contents + h->plt.offset + 2);
313399461Sobrien      /* Fixup the relative branch to PLT 0 */
313499461Sobrien      bfd_put_32 (output_bfd, - (PLT_FIRST_ENTRY_SIZE +
313599461Sobrien				 (PLT_ENTRY_SIZE * plt_index) + 22)/2,
313699461Sobrien		  htab->splt->contents + h->plt.offset + 24);
313799461Sobrien      /* Fixup offset into symbol table */
313899461Sobrien      bfd_put_32 (output_bfd, plt_index * sizeof (Elf64_External_Rela),
313999461Sobrien		  htab->splt->contents + h->plt.offset + 28);
314099461Sobrien
314199461Sobrien      /* Fill in the entry in the global offset table.
3142130561Sobrien	 Points to instruction after GOT offset.  */
314399461Sobrien      bfd_put_64 (output_bfd,
314499461Sobrien		  (htab->splt->output_section->vma
314599461Sobrien		   + htab->splt->output_offset
314699461Sobrien		   + h->plt.offset
314799461Sobrien		   + 14),
314899461Sobrien		  htab->sgotplt->contents + got_offset);
314999461Sobrien
315099461Sobrien      /* Fill in the entry in the .rela.plt section.  */
315199461Sobrien      rela.r_offset = (htab->sgotplt->output_section->vma
315299461Sobrien		       + htab->sgotplt->output_offset
315399461Sobrien		       + got_offset);
315499461Sobrien      rela.r_info = ELF64_R_INFO (h->dynindx, R_390_JMP_SLOT);
315599461Sobrien      rela.r_addend = 0;
3156130561Sobrien      loc = htab->srelplt->contents + plt_index * sizeof (Elf64_External_Rela);
315799461Sobrien      bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
315899461Sobrien
3159218822Sdim      if (!h->def_regular)
316099461Sobrien	{
316199461Sobrien	  /* Mark the symbol as undefined, rather than as defined in
316299461Sobrien	     the .plt section.  Leave the value alone.  This is a clue
316399461Sobrien	     for the dynamic linker, to make function pointer
316499461Sobrien	     comparisons work between an application and shared
316599461Sobrien	     library.  */
316699461Sobrien	  sym->st_shndx = SHN_UNDEF;
316799461Sobrien	}
316899461Sobrien    }
316999461Sobrien
3170130561Sobrien  if (h->got.offset != (bfd_vma) -1
3171130561Sobrien      && elf_s390_hash_entry(h)->tls_type != GOT_TLS_GD
3172130561Sobrien      && elf_s390_hash_entry(h)->tls_type != GOT_TLS_IE
3173130561Sobrien      && elf_s390_hash_entry(h)->tls_type != GOT_TLS_IE_NLT)
317499461Sobrien    {
317599461Sobrien      Elf_Internal_Rela rela;
3176130561Sobrien      bfd_byte *loc;
317799461Sobrien
317899461Sobrien      /* This symbol has an entry in the global offset table.  Set it
3179130561Sobrien	 up.  */
318099461Sobrien      if (htab->sgot == NULL || htab->srelgot == NULL)
318199461Sobrien	abort ();
318299461Sobrien
318399461Sobrien      rela.r_offset = (htab->sgot->output_section->vma
318499461Sobrien		       + htab->sgot->output_offset
318599461Sobrien		       + (h->got.offset &~ (bfd_vma) 1));
318699461Sobrien
318799461Sobrien      /* If this is a static link, or it is a -Bsymbolic link and the
318899461Sobrien	 symbol is defined locally or was forced to be local because
318999461Sobrien	 of a version file, we just want to emit a RELATIVE reloc.
319099461Sobrien	 The entry in the global offset table will already have been
319199461Sobrien	 initialized in the relocate_section function.  */
319299461Sobrien      if (info->shared
319399461Sobrien	  && (info->symbolic
319499461Sobrien	      || h->dynindx == -1
3195218822Sdim	      || h->forced_local)
3196218822Sdim	  && h->def_regular)
3197130561Sobrien	{
319899461Sobrien	  BFD_ASSERT((h->got.offset & 1) != 0);
3199130561Sobrien	  rela.r_info = ELF64_R_INFO (0, R_390_RELATIVE);
3200130561Sobrien	  rela.r_addend = (h->root.u.def.value
3201130561Sobrien			   + h->root.u.def.section->output_section->vma
3202130561Sobrien			   + h->root.u.def.section->output_offset);
3203130561Sobrien	}
320499461Sobrien      else
320599461Sobrien	{
320699461Sobrien	  BFD_ASSERT((h->got.offset & 1) == 0);
320799461Sobrien	  bfd_put_64 (output_bfd, (bfd_vma) 0, htab->sgot->contents + h->got.offset);
320899461Sobrien	  rela.r_info = ELF64_R_INFO (h->dynindx, R_390_GLOB_DAT);
3209130561Sobrien	  rela.r_addend = 0;
3210130561Sobrien	}
321199461Sobrien
3212130561Sobrien      loc = htab->srelgot->contents;
3213130561Sobrien      loc += htab->srelgot->reloc_count++ * sizeof (Elf64_External_Rela);
321499461Sobrien      bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
321599461Sobrien    }
321699461Sobrien
3217218822Sdim  if (h->needs_copy)
321899461Sobrien    {
321999461Sobrien      Elf_Internal_Rela rela;
3220130561Sobrien      bfd_byte *loc;
322199461Sobrien
322299461Sobrien      /* This symbols needs a copy reloc.  Set it up.  */
322399461Sobrien
322499461Sobrien      if (h->dynindx == -1
322599461Sobrien	  || (h->root.type != bfd_link_hash_defined
322699461Sobrien	      && h->root.type != bfd_link_hash_defweak)
322799461Sobrien	  || htab->srelbss == NULL)
322899461Sobrien	abort ();
322999461Sobrien
323099461Sobrien      rela.r_offset = (h->root.u.def.value
323199461Sobrien		       + h->root.u.def.section->output_section->vma
323299461Sobrien		       + h->root.u.def.section->output_offset);
323399461Sobrien      rela.r_info = ELF64_R_INFO (h->dynindx, R_390_COPY);
323499461Sobrien      rela.r_addend = 0;
3235130561Sobrien      loc = htab->srelbss->contents;
3236130561Sobrien      loc += htab->srelbss->reloc_count++ * sizeof (Elf64_External_Rela);
323799461Sobrien      bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
323899461Sobrien    }
323999461Sobrien
324099461Sobrien  /* Mark some specially defined symbols as absolute.  */
324199461Sobrien  if (strcmp (h->root.root.string, "_DYNAMIC") == 0
3242218822Sdim      || h == htab->elf.hgot
3243218822Sdim      || h == htab->elf.hplt)
324499461Sobrien    sym->st_shndx = SHN_ABS;
324599461Sobrien
3246130561Sobrien  return TRUE;
324799461Sobrien}
324899461Sobrien
324999461Sobrien/* Used to decide how to sort relocs in an optimal manner for the
325099461Sobrien   dynamic linker, before writing them out.  */
325199461Sobrien
325299461Sobrienstatic enum elf_reloc_type_class
325399461Sobrienelf_s390_reloc_type_class (rela)
325499461Sobrien     const Elf_Internal_Rela *rela;
325599461Sobrien{
325699461Sobrien  switch ((int) ELF64_R_TYPE (rela->r_info))
325799461Sobrien    {
325899461Sobrien    case R_390_RELATIVE:
325999461Sobrien      return reloc_class_relative;
326099461Sobrien    case R_390_JMP_SLOT:
326199461Sobrien      return reloc_class_plt;
326299461Sobrien    case R_390_COPY:
326399461Sobrien      return reloc_class_copy;
326499461Sobrien    default:
326599461Sobrien      return reloc_class_normal;
326699461Sobrien    }
326799461Sobrien}
326899461Sobrien
326999461Sobrien/* Finish up the dynamic sections.  */
327099461Sobrien
3271130561Sobrienstatic bfd_boolean
327299461Sobrienelf_s390_finish_dynamic_sections (output_bfd, info)
327399461Sobrien     bfd *output_bfd;
327499461Sobrien     struct bfd_link_info *info;
327599461Sobrien{
327699461Sobrien  struct elf_s390_link_hash_table *htab;
327799461Sobrien  bfd *dynobj;
327899461Sobrien  asection *sdyn;
327999461Sobrien
328099461Sobrien  htab = elf_s390_hash_table (info);
328199461Sobrien  dynobj = htab->elf.dynobj;
328299461Sobrien  sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
328399461Sobrien
328499461Sobrien  if (htab->elf.dynamic_sections_created)
328599461Sobrien    {
328699461Sobrien      Elf64_External_Dyn *dyncon, *dynconend;
328799461Sobrien
328899461Sobrien      if (sdyn == NULL || htab->sgot == NULL)
328999461Sobrien	abort ();
329099461Sobrien
329199461Sobrien      dyncon = (Elf64_External_Dyn *) sdyn->contents;
3292218822Sdim      dynconend = (Elf64_External_Dyn *) (sdyn->contents + sdyn->size);
329399461Sobrien      for (; dyncon < dynconend; dyncon++)
329499461Sobrien	{
329599461Sobrien	  Elf_Internal_Dyn dyn;
329699461Sobrien	  asection *s;
329799461Sobrien
329899461Sobrien	  bfd_elf64_swap_dyn_in (dynobj, dyncon, &dyn);
329999461Sobrien
330099461Sobrien	  switch (dyn.d_tag)
330199461Sobrien	    {
330299461Sobrien	    default:
330399461Sobrien	      continue;
330499461Sobrien
330599461Sobrien	    case DT_PLTGOT:
330699461Sobrien	      dyn.d_un.d_ptr = htab->sgot->output_section->vma;
330799461Sobrien	      break;
330899461Sobrien
330999461Sobrien	    case DT_JMPREL:
331099461Sobrien	      dyn.d_un.d_ptr = htab->srelplt->output_section->vma;
331199461Sobrien	      break;
331299461Sobrien
331399461Sobrien	    case DT_PLTRELSZ:
331499461Sobrien	      s = htab->srelplt->output_section;
3315218822Sdim	      dyn.d_un.d_val = s->size;
331699461Sobrien	      break;
331799461Sobrien
331899461Sobrien	    case DT_RELASZ:
331999461Sobrien	      /* The procedure linkage table relocs (DT_JMPREL) should
332099461Sobrien		 not be included in the overall relocs (DT_RELA).
332199461Sobrien		 Therefore, we override the DT_RELASZ entry here to
332299461Sobrien		 make it not include the JMPREL relocs.  Since the
332399461Sobrien		 linker script arranges for .rela.plt to follow all
332499461Sobrien		 other relocation sections, we don't have to worry
332599461Sobrien		 about changing the DT_RELA entry.  */
332699461Sobrien	      s = htab->srelplt->output_section;
3327218822Sdim	      dyn.d_un.d_val -= s->size;
332899461Sobrien	      break;
332999461Sobrien	    }
333099461Sobrien
333199461Sobrien	  bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon);
333299461Sobrien	}
333399461Sobrien
333499461Sobrien      /* Fill in the special first entry in the procedure linkage table.  */
3335218822Sdim      if (htab->splt && htab->splt->size > 0)
333699461Sobrien	{
333799461Sobrien	  /* fill in blueprint for plt 0 entry */
333899461Sobrien	  bfd_put_32 (output_bfd, (bfd_vma) PLT_FIRST_ENTRY_WORD0,
333999461Sobrien		      htab->splt->contents );
334099461Sobrien	  bfd_put_32 (output_bfd, (bfd_vma) PLT_FIRST_ENTRY_WORD1,
334199461Sobrien		      htab->splt->contents +4 );
334299461Sobrien	  bfd_put_32 (output_bfd, (bfd_vma) PLT_FIRST_ENTRY_WORD3,
334399461Sobrien		      htab->splt->contents +12 );
334499461Sobrien	  bfd_put_32 (output_bfd, (bfd_vma) PLT_FIRST_ENTRY_WORD4,
334599461Sobrien		      htab->splt->contents +16 );
334699461Sobrien	  bfd_put_32 (output_bfd, (bfd_vma) PLT_FIRST_ENTRY_WORD5,
334799461Sobrien		      htab->splt->contents +20 );
334899461Sobrien	  bfd_put_32 (output_bfd, (bfd_vma) PLT_FIRST_ENTRY_WORD6,
334999461Sobrien		      htab->splt->contents + 24);
335099461Sobrien	  bfd_put_32 (output_bfd, (bfd_vma) PLT_FIRST_ENTRY_WORD7,
335199461Sobrien		      htab->splt->contents + 28 );
335299461Sobrien	  /* Fixup relative address to start of GOT */
335399461Sobrien	  bfd_put_32 (output_bfd,
335499461Sobrien		      (htab->sgotplt->output_section->vma +
335599461Sobrien		       htab->sgotplt->output_offset
335699461Sobrien		       - htab->splt->output_section->vma - 6)/2,
335799461Sobrien		      htab->splt->contents + 8);
335899461Sobrien	}
335999461Sobrien      elf_section_data (htab->splt->output_section)
336099461Sobrien	->this_hdr.sh_entsize = PLT_ENTRY_SIZE;
336199461Sobrien    }
336299461Sobrien
336399461Sobrien  if (htab->sgotplt)
336499461Sobrien    {
336599461Sobrien      /* Fill in the first three entries in the global offset table.  */
3366218822Sdim      if (htab->sgotplt->size > 0)
336799461Sobrien	{
336899461Sobrien	  bfd_put_64 (output_bfd,
336999461Sobrien		      (sdyn == NULL ? (bfd_vma) 0
337099461Sobrien		       : sdyn->output_section->vma + sdyn->output_offset),
337199461Sobrien		      htab->sgotplt->contents);
337299461Sobrien	  /* One entry for shared object struct ptr.  */
337399461Sobrien	  bfd_put_64 (output_bfd, (bfd_vma) 0, htab->sgotplt->contents + 8);
337499461Sobrien	  /* One entry for _dl_runtime_resolve.  */
337599461Sobrien	  bfd_put_64 (output_bfd, (bfd_vma) 0, htab->sgotplt->contents + 12);
337699461Sobrien	}
337799461Sobrien
337899461Sobrien      elf_section_data (htab->sgot->output_section)
337999461Sobrien	->this_hdr.sh_entsize = 8;
338099461Sobrien    }
3381130561Sobrien  return TRUE;
338299461Sobrien}
338399461Sobrien
3384218822Sdim/* Return address for Ith PLT stub in section PLT, for relocation REL
3385218822Sdim   or (bfd_vma) -1 if it should not be included.  */
3386218822Sdim
3387218822Sdimstatic bfd_vma
3388218822Sdimelf_s390_plt_sym_val (bfd_vma i, const asection *plt,
3389218822Sdim		      const arelent *rel ATTRIBUTE_UNUSED)
3390218822Sdim{
3391218822Sdim  return plt->vma + PLT_FIRST_ENTRY_SIZE + i * PLT_ENTRY_SIZE;
3392218822Sdim}
3393218822Sdim
3394218822Sdim
3395130561Sobrien/* Why was the hash table entry size definition changed from
3396130561Sobrien   ARCH_SIZE/8 to 4? This breaks the 64 bit dynamic linker and
3397130561Sobrien   this is the only reason for the s390_elf64_size_info structure.  */
339899461Sobrien
339999461Sobrienconst struct elf_size_info s390_elf64_size_info =
340099461Sobrien{
340199461Sobrien  sizeof (Elf64_External_Ehdr),
340299461Sobrien  sizeof (Elf64_External_Phdr),
340399461Sobrien  sizeof (Elf64_External_Shdr),
340499461Sobrien  sizeof (Elf64_External_Rel),
340599461Sobrien  sizeof (Elf64_External_Rela),
340699461Sobrien  sizeof (Elf64_External_Sym),
340799461Sobrien  sizeof (Elf64_External_Dyn),
340899461Sobrien  sizeof (Elf_External_Note),
3409130561Sobrien  8,		/* hash-table entry size.  */
3410130561Sobrien  1,		/* internal relocations per external relocations.  */
3411130561Sobrien  64,		/* arch_size.  */
3412130561Sobrien  3,		/* log_file_align.  */
341399461Sobrien  ELFCLASS64, EV_CURRENT,
341499461Sobrien  bfd_elf64_write_out_phdrs,
341599461Sobrien  bfd_elf64_write_shdrs_and_ehdr,
341699461Sobrien  bfd_elf64_write_relocs,
3417107492Sobrien  bfd_elf64_swap_symbol_in,
341899461Sobrien  bfd_elf64_swap_symbol_out,
341999461Sobrien  bfd_elf64_slurp_reloc_table,
342099461Sobrien  bfd_elf64_slurp_symbol_table,
342199461Sobrien  bfd_elf64_swap_dyn_in,
342299461Sobrien  bfd_elf64_swap_dyn_out,
3423130561Sobrien  bfd_elf64_swap_reloc_in,
3424130561Sobrien  bfd_elf64_swap_reloc_out,
3425130561Sobrien  bfd_elf64_swap_reloca_in,
3426130561Sobrien  bfd_elf64_swap_reloca_out
342799461Sobrien};
342899461Sobrien
342999461Sobrien#define TARGET_BIG_SYM	bfd_elf64_s390_vec
343099461Sobrien#define TARGET_BIG_NAME	"elf64-s390"
343199461Sobrien#define ELF_ARCH	bfd_arch_s390
343299461Sobrien#define ELF_MACHINE_CODE EM_S390
343399461Sobrien#define ELF_MACHINE_ALT1 EM_S390_OLD
343499461Sobrien#define ELF_MAXPAGESIZE 0x1000
343599461Sobrien
343699461Sobrien#define elf_backend_size_info		s390_elf64_size_info
343799461Sobrien
343899461Sobrien#define elf_backend_can_gc_sections	1
343999461Sobrien#define elf_backend_can_refcount	1
344099461Sobrien#define elf_backend_want_got_plt	1
344199461Sobrien#define elf_backend_plt_readonly	1
344299461Sobrien#define elf_backend_want_plt_sym	0
344399461Sobrien#define elf_backend_got_header_size	24
344499461Sobrien#define elf_backend_rela_normal		1
344599461Sobrien
344699461Sobrien#define elf_info_to_howto		elf_s390_info_to_howto
344799461Sobrien
344899461Sobrien#define bfd_elf64_bfd_is_local_label_name     elf_s390_is_local_label_name
344999461Sobrien#define bfd_elf64_bfd_link_hash_table_create  elf_s390_link_hash_table_create
345099461Sobrien#define bfd_elf64_bfd_reloc_type_lookup	      elf_s390_reloc_type_lookup
3451218822Sdim#define bfd_elf64_bfd_reloc_name_lookup elf_s390_reloc_name_lookup
345299461Sobrien
345399461Sobrien#define elf_backend_adjust_dynamic_symbol     elf_s390_adjust_dynamic_symbol
345499461Sobrien#define elf_backend_check_relocs	      elf_s390_check_relocs
345599461Sobrien#define elf_backend_copy_indirect_symbol      elf_s390_copy_indirect_symbol
345699461Sobrien#define elf_backend_create_dynamic_sections   elf_s390_create_dynamic_sections
345799461Sobrien#define elf_backend_finish_dynamic_sections   elf_s390_finish_dynamic_sections
345899461Sobrien#define elf_backend_finish_dynamic_symbol     elf_s390_finish_dynamic_symbol
345999461Sobrien#define elf_backend_gc_mark_hook	      elf_s390_gc_mark_hook
346099461Sobrien#define elf_backend_gc_sweep_hook	      elf_s390_gc_sweep_hook
346199461Sobrien#define elf_backend_reloc_type_class	      elf_s390_reloc_type_class
346299461Sobrien#define elf_backend_relocate_section	      elf_s390_relocate_section
346399461Sobrien#define elf_backend_size_dynamic_sections     elf_s390_size_dynamic_sections
3464218822Sdim#define elf_backend_init_index_section	      _bfd_elf_init_1_index_section
346599461Sobrien#define elf_backend_reloc_type_class	      elf_s390_reloc_type_class
3466218822Sdim#define elf_backend_plt_sym_val		      elf_s390_plt_sym_val
346799461Sobrien
3468130561Sobrien#define bfd_elf64_mkobject		elf_s390_mkobject
3469130561Sobrien#define elf_backend_object_p		elf_s390_object_p
347099461Sobrien
347199461Sobrien#include "elf64-target.h"
3472