1214571Sdim/* 32-bit ELF support for S+core.
2214571Sdim   Copyright 2006, 2007 Free Software Foundation, Inc.
3214571Sdim   Contributed by
4214571Sdim   Mei Ligang (ligang@sunnorth.com.cn)
5214571Sdim   Pei-Lin Tsai (pltsai@sunplus.com)
6214571Sdim
7214571Sdim   This file is part of BFD, the Binary File Descriptor library.
8214571Sdim
9214571Sdim   This program is free software; you can redistribute it and/or modify
10214571Sdim   it under the terms of the GNU General Public License as published by
11214571Sdim   the Free Software Foundation; either version 2 of the License, or
12214571Sdim   (at your option) any later version.
13214571Sdim
14214571Sdim   This program is distributed in the hope that it will be useful,
15214571Sdim   but WITHOUT ANY WARRANTY; without even the implied warranty of
16214571Sdim   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17214571Sdim   GNU General Public License for more details.
18214571Sdim
19214571Sdim   You should have received a copy of the GNU General Public License
20214571Sdim   along with this program; if not, write to the Free Software
21214571Sdim   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
22214571Sdim
23214571Sdim#include "sysdep.h"
24214571Sdim#include "bfd.h"
25214571Sdim#include "libbfd.h"
26214571Sdim#include "libiberty.h"
27214571Sdim#include "elf-bfd.h"
28214571Sdim#include "elf/score.h"
29214571Sdim#include "elf/common.h"
30214571Sdim#include "elf/internal.h"
31214571Sdim#include "hashtab.h"
32214571Sdim
33214571Sdim
34214571Sdim/* Score ELF linker hash table.  */
35214571Sdim
36214571Sdimstruct score_elf_link_hash_table
37214571Sdim{
38214571Sdim  /* The main hash table.  */
39214571Sdim  struct elf_link_hash_table root;
40214571Sdim};
41214571Sdim
42214571Sdim/* The SCORE ELF linker needs additional information for each symbol in
43214571Sdim   the global hash table.  */
44214571Sdim
45214571Sdimstruct score_elf_link_hash_entry
46214571Sdim{
47214571Sdim  struct elf_link_hash_entry root;
48214571Sdim
49214571Sdim  /* Number of R_SCORE_ABS32, R_SCORE_REL32 relocs against this symbol.  */
50214571Sdim  unsigned int possibly_dynamic_relocs;
51214571Sdim
52214571Sdim  /* If the R_SCORE_ABS32, R_SCORE_REL32 reloc is against a readonly section.  */
53214571Sdim  bfd_boolean readonly_reloc;
54214571Sdim
55214571Sdim  /* We must not create a stub for a symbol that has relocations related to
56214571Sdim     taking the function's address, i.e. any but R_SCORE_CALL15 ones.  */
57214571Sdim  bfd_boolean no_fn_stub;
58214571Sdim
59214571Sdim  /* Are we forced local?  This will only be set if we have converted
60214571Sdim     the initial global GOT entry to a local GOT entry.  */
61214571Sdim  bfd_boolean forced_local;
62214571Sdim};
63214571Sdim
64214571Sdim/* Traverse a score ELF linker hash table.  */
65214571Sdim#define score_elf_link_hash_traverse(table, func, info) \
66214571Sdim  (elf_link_hash_traverse \
67214571Sdim   (&(table)->root, \
68214571Sdim    (bfd_boolean (*) (struct elf_link_hash_entry *, void *)) (func), \
69214571Sdim    (info)))
70214571Sdim
71214571Sdim/* Get the SCORE elf linker hash table from a link_info structure.  */
72214571Sdim#define score_elf_hash_table(info) \
73214571Sdim  ((struct score_elf_link_hash_table *) ((info)->hash))
74214571Sdim
75214571Sdim/* This structure is used to hold .got entries while estimating got sizes.  */
76214571Sdimstruct score_got_entry
77214571Sdim{
78214571Sdim  /* The input bfd in which the symbol is defined.  */
79214571Sdim  bfd *abfd;
80214571Sdim  /* The index of the symbol, as stored in the relocation r_info, if
81214571Sdim     we have a local symbol; -1 otherwise.  */
82214571Sdim  long symndx;
83214571Sdim  union
84214571Sdim  {
85214571Sdim    /* If abfd == NULL, an address that must be stored in the got.  */
86214571Sdim    bfd_vma address;
87214571Sdim    /* If abfd != NULL && symndx != -1, the addend of the relocation
88214571Sdim       that should be added to the symbol value.  */
89214571Sdim    bfd_vma addend;
90214571Sdim    /* If abfd != NULL && symndx == -1, the hash table entry
91214571Sdim       corresponding to a global symbol in the got (or, local, if
92214571Sdim       h->forced_local).  */
93214571Sdim    struct score_elf_link_hash_entry *h;
94214571Sdim  } d;
95214571Sdim
96214571Sdim  /* The offset from the beginning of the .got section to the entry
97214571Sdim     corresponding to this symbol+addend.  If it's a global symbol
98214571Sdim     whose offset is yet to be decided, it's going to be -1.  */
99214571Sdim  long gotidx;
100214571Sdim};
101214571Sdim
102214571Sdim/* This structure is passed to score_elf_sort_hash_table_f when sorting
103214571Sdim   the dynamic symbols.  */
104214571Sdim
105214571Sdimstruct score_elf_hash_sort_data
106214571Sdim{
107214571Sdim  /* The symbol in the global GOT with the lowest dynamic symbol table index.  */
108214571Sdim  struct elf_link_hash_entry *low;
109214571Sdim  /* The least dynamic symbol table index corresponding to a symbol with a GOT entry.  */
110214571Sdim  long min_got_dynindx;
111214571Sdim  /* The greatest dynamic symbol table index corresponding to a symbol
112214571Sdim     with a GOT entry that is not referenced (e.g., a dynamic symbol
113214571Sdim     with dynamic relocations pointing to it from non-primary GOTs).  */
114214571Sdim  long max_unref_got_dynindx;
115214571Sdim  /* The greatest dynamic symbol table index not corresponding to a
116214571Sdim     symbol without a GOT entry.  */
117214571Sdim  long max_non_got_dynindx;
118214571Sdim};
119214571Sdim
120214571Sdimstruct score_got_info
121214571Sdim{
122214571Sdim  /* The global symbol in the GOT with the lowest index in the dynamic
123214571Sdim     symbol table.  */
124214571Sdim  struct elf_link_hash_entry *global_gotsym;
125214571Sdim  /* The number of global .got entries.  */
126214571Sdim  unsigned int global_gotno;
127214571Sdim  /* The number of local .got entries.  */
128214571Sdim  unsigned int local_gotno;
129214571Sdim  /* The number of local .got entries we have used.  */
130214571Sdim  unsigned int assigned_gotno;
131214571Sdim  /* A hash table holding members of the got.  */
132214571Sdim  struct htab *got_entries;
133214571Sdim  /* In multi-got links, a pointer to the next got (err, rather, most
134214571Sdim     of the time, it points to the previous got).  */
135214571Sdim  struct score_got_info *next;
136214571Sdim};
137214571Sdim
138214571Sdim/* A structure used to count GOT entries, for GOT entry or ELF symbol table traversal.  */
139214571Sdimstruct _score_elf_section_data
140214571Sdim{
141214571Sdim  struct bfd_elf_section_data elf;
142214571Sdim  union
143214571Sdim  {
144214571Sdim    struct score_got_info *got_info;
145214571Sdim    bfd_byte *tdata;
146214571Sdim  }
147214571Sdim  u;
148214571Sdim};
149214571Sdim
150214571Sdim#define score_elf_section_data(sec) \
151214571Sdim  ((struct _score_elf_section_data *) elf_section_data (sec))
152214571Sdim
153214571Sdim/* The size of a symbol-table entry.  */
154214571Sdim#define SCORE_ELF_SYM_SIZE(abfd)  \
155214571Sdim  (get_elf_backend_data (abfd)->s->sizeof_sym)
156214571Sdim
157214571Sdim/* In case we're on a 32-bit machine, construct a 64-bit "-1" value
158214571Sdim   from smaller values.  Start with zero, widen, *then* decrement.  */
159214571Sdim#define MINUS_ONE (((bfd_vma)0) - 1)
160214571Sdim#define MINUS_TWO (((bfd_vma)0) - 2)
161214571Sdim
162214571Sdim#define PDR_SIZE 32
163214571Sdim
164214571Sdim
165214571Sdim/* The number of local .got entries we reserve.  */
166214571Sdim#define SCORE_RESERVED_GOTNO (2)
167214571Sdim#define ELF_DYNAMIC_INTERPRETER     "/usr/lib/ld.so.1"
168214571Sdim
169214571Sdim/* The offset of $gp from the beginning of the .got section.  */
170214571Sdim#define ELF_SCORE_GP_OFFSET(abfd) (0x3ff0)
171214571Sdim/* The maximum size of the GOT for it to be addressable using 15-bit offsets from $gp.  */
172214571Sdim#define SCORE_ELF_GOT_MAX_SIZE(abfd) (ELF_SCORE_GP_OFFSET(abfd) + 0x3fff)
173214571Sdim
174214571Sdim#define SCORE_ELF_STUB_SECTION_NAME  (".SCORE.stub")
175214571Sdim#define SCORE_FUNCTION_STUB_SIZE (16)
176214571Sdim
177214571Sdim#define STUB_LW	     0xc3bcc010     /* lw r29, [r28, -0x3ff0]  */
178214571Sdim#define STUB_MOVE    0x8363bc56     /* mv r27, r3  */
179214571Sdim#define STUB_LI16    0x87548000     /* ori r26, .dynsym_index  */
180214571Sdim#define STUB_BRL     0x801dbc09     /* brl r29  */
181214571Sdim
182214571Sdim#define SCORE_ELF_GOT_SIZE(abfd)   \
183214571Sdim  (get_elf_backend_data (abfd)->s->arch_size / 8)
184214571Sdim
185214571Sdim#define SCORE_ELF_ADD_DYNAMIC_ENTRY(info, tag, val) \
186214571Sdim        (_bfd_elf_add_dynamic_entry (info, (bfd_vma) tag, (bfd_vma) val))
187214571Sdim
188214571Sdim/* The size of an external dynamic table entry.  */
189214571Sdim#define SCORE_ELF_DYN_SIZE(abfd) \
190214571Sdim  (get_elf_backend_data (abfd)->s->sizeof_dyn)
191214571Sdim
192214571Sdim/* The size of an external REL relocation.  */
193214571Sdim#define SCORE_ELF_REL_SIZE(abfd) \
194214571Sdim  (get_elf_backend_data (abfd)->s->sizeof_rel)
195214571Sdim
196214571Sdim/* The default alignment for sections, as a power of two.  */
197214571Sdim#define SCORE_ELF_LOG_FILE_ALIGN(abfd)\
198214571Sdim  (get_elf_backend_data (abfd)->s->log_file_align)
199214571Sdim
200214571Sdim#ifndef NUM_ELEM
201214571Sdim#define NUM_ELEM(a)  (sizeof (a) / (sizeof (a)[0]))
202214571Sdim#endif
203214571Sdim
204214571Sdimstatic bfd_byte *hi16_rel_addr;
205214571Sdim
206214571Sdim/* This will be used when we sort the dynamic relocation records.  */
207214571Sdimstatic bfd *reldyn_sorting_bfd;
208214571Sdim
209214571Sdim/* SCORE ELF uses two common sections.  One is the usual one, and the
210214571Sdim   other is for small objects.  All the small objects are kept
211214571Sdim   together, and then referenced via the gp pointer, which yields
212214571Sdim   faster assembler code.  This is what we use for the small common
213214571Sdim   section.  This approach is copied from ecoff.c.  */
214214571Sdimstatic asection score_elf_scom_section;
215214571Sdimstatic asymbol  score_elf_scom_symbol;
216214571Sdimstatic asymbol  *score_elf_scom_symbol_ptr;
217214571Sdim
218214571Sdimstatic bfd_reloc_status_type
219214571Sdimscore_elf_hi16_reloc (bfd *abfd ATTRIBUTE_UNUSED,
220214571Sdim		      arelent *reloc_entry,
221214571Sdim		      asymbol *symbol ATTRIBUTE_UNUSED,
222214571Sdim		      void * data,
223214571Sdim		      asection *input_section ATTRIBUTE_UNUSED,
224214571Sdim		      bfd *output_bfd ATTRIBUTE_UNUSED,
225214571Sdim		      char **error_message ATTRIBUTE_UNUSED)
226214571Sdim{
227214571Sdim  hi16_rel_addr = (bfd_byte *) data + reloc_entry->address;
228214571Sdim  return bfd_reloc_ok;
229214571Sdim}
230214571Sdim
231214571Sdimstatic bfd_reloc_status_type
232214571Sdimscore_elf_lo16_reloc (bfd *abfd,
233214571Sdim		      arelent *reloc_entry,
234214571Sdim		      asymbol *symbol ATTRIBUTE_UNUSED,
235214571Sdim		      void * data,
236214571Sdim		      asection *input_section,
237214571Sdim		      bfd *output_bfd ATTRIBUTE_UNUSED,
238214571Sdim		      char **error_message ATTRIBUTE_UNUSED)
239214571Sdim{
240214571Sdim  bfd_vma addend = 0, offset = 0;
241214571Sdim  unsigned long val;
242214571Sdim  unsigned long hi16_offset, hi16_value, uvalue;
243214571Sdim
244214571Sdim  hi16_value = bfd_get_32 (abfd, hi16_rel_addr);
245214571Sdim  hi16_offset = ((((hi16_value >> 16) & 0x3) << 15) | (hi16_value & 0x7fff)) >> 1;
246214571Sdim  addend = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
247214571Sdim  offset = ((((addend >> 16) & 0x3) << 15) | (addend & 0x7fff)) >> 1;
248214571Sdim  val = reloc_entry->addend;
249214571Sdim  if (reloc_entry->address > input_section->size)
250214571Sdim    return bfd_reloc_outofrange;
251214571Sdim  uvalue = ((hi16_offset << 16) | (offset & 0xffff)) + val;
252214571Sdim  hi16_offset = (uvalue >> 16) << 1;
253214571Sdim  hi16_value = (hi16_value & ~0x37fff) | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000);
254214571Sdim  bfd_put_32 (abfd, hi16_value, hi16_rel_addr);
255214571Sdim  offset = (uvalue & 0xffff) << 1;
256214571Sdim  addend = (addend & ~0x37fff) | (offset & 0x7fff) | ((offset << 1) & 0x30000);
257214571Sdim  bfd_put_32 (abfd, addend, (bfd_byte *) data + reloc_entry->address);
258214571Sdim  return bfd_reloc_ok;
259214571Sdim}
260214571Sdim
261214571Sdim/* Set the GP value for OUTPUT_BFD.  Returns FALSE if this is a
262214571Sdim   dangerous relocation.  */
263214571Sdim
264214571Sdimstatic bfd_boolean
265214571Sdimscore_elf_assign_gp (bfd *output_bfd, bfd_vma *pgp)
266214571Sdim{
267214571Sdim  unsigned int count;
268214571Sdim  asymbol **sym;
269214571Sdim  unsigned int i;
270214571Sdim
271214571Sdim  /* If we've already figured out what GP will be, just return it.  */
272214571Sdim  *pgp = _bfd_get_gp_value (output_bfd);
273214571Sdim  if (*pgp)
274214571Sdim    return TRUE;
275214571Sdim
276214571Sdim  count = bfd_get_symcount (output_bfd);
277214571Sdim  sym = bfd_get_outsymbols (output_bfd);
278214571Sdim
279214571Sdim  /* The linker script will have created a symbol named `_gp' with the
280214571Sdim     appropriate value.  */
281214571Sdim  if (sym == NULL)
282214571Sdim    i = count;
283214571Sdim  else
284214571Sdim    {
285214571Sdim      for (i = 0; i < count; i++, sym++)
286214571Sdim	{
287214571Sdim	  const char *name;
288214571Sdim
289214571Sdim	  name = bfd_asymbol_name (*sym);
290214571Sdim	  if (*name == '_' && strcmp (name, "_gp") == 0)
291214571Sdim	    {
292214571Sdim	      *pgp = bfd_asymbol_value (*sym);
293214571Sdim	      _bfd_set_gp_value (output_bfd, *pgp);
294214571Sdim	      break;
295214571Sdim	    }
296214571Sdim	}
297214571Sdim    }
298214571Sdim
299214571Sdim  if (i >= count)
300214571Sdim    {
301214571Sdim      /* Only get the error once.  */
302214571Sdim      *pgp = 4;
303214571Sdim      _bfd_set_gp_value (output_bfd, *pgp);
304214571Sdim      return FALSE;
305214571Sdim    }
306214571Sdim
307214571Sdim  return TRUE;
308214571Sdim}
309214571Sdim
310214571Sdim/* We have to figure out the gp value, so that we can adjust the
311214571Sdim   symbol value correctly.  We look up the symbol _gp in the output
312214571Sdim   BFD.  If we can't find it, we're stuck.  We cache it in the ELF
313214571Sdim   target data.  We don't need to adjust the symbol value for an
314214571Sdim   external symbol if we are producing relocatable output.  */
315214571Sdim
316214571Sdimstatic bfd_reloc_status_type
317214571Sdimscore_elf_final_gp (bfd *output_bfd,
318214571Sdim		    asymbol *symbol,
319214571Sdim		    bfd_boolean relocatable,
320214571Sdim 		    char **error_message,
321214571Sdim		    bfd_vma *pgp)
322214571Sdim{
323214571Sdim  if (bfd_is_und_section (symbol->section)
324214571Sdim      && ! relocatable)
325214571Sdim    {
326214571Sdim      *pgp = 0;
327214571Sdim      return bfd_reloc_undefined;
328214571Sdim    }
329214571Sdim
330214571Sdim  *pgp = _bfd_get_gp_value (output_bfd);
331214571Sdim  if (*pgp == 0
332214571Sdim      && (! relocatable
333214571Sdim	  || (symbol->flags & BSF_SECTION_SYM) != 0))
334214571Sdim    {
335214571Sdim      if (relocatable)
336214571Sdim	{
337214571Sdim	  /* Make up a value.  */
338214571Sdim	  *pgp = symbol->section->output_section->vma + 0x4000;
339214571Sdim	  _bfd_set_gp_value (output_bfd, *pgp);
340214571Sdim	}
341214571Sdim      else if (!score_elf_assign_gp (output_bfd, pgp))
342214571Sdim	{
343214571Sdim	    *error_message =
344214571Sdim	      (char *) _("GP relative relocation when _gp not defined");
345214571Sdim	    return bfd_reloc_dangerous;
346214571Sdim	}
347214571Sdim    }
348214571Sdim
349214571Sdim  return bfd_reloc_ok;
350214571Sdim}
351214571Sdim
352214571Sdimstatic bfd_reloc_status_type
353214571Sdimscore_elf_gprel15_with_gp (bfd *abfd,
354214571Sdim			   asymbol *symbol,
355214571Sdim			   arelent *reloc_entry,
356214571Sdim			   asection *input_section,
357214571Sdim			   bfd_boolean relocateable,
358214571Sdim			   void * data,
359214571Sdim			   bfd_vma gp ATTRIBUTE_UNUSED)
360214571Sdim{
361214571Sdim  bfd_vma relocation;
362214571Sdim  unsigned long insn;
363214571Sdim
364214571Sdim  if (bfd_is_com_section (symbol->section))
365214571Sdim    relocation = 0;
366214571Sdim  else
367214571Sdim    relocation = symbol->value;
368214571Sdim
369214571Sdim  relocation += symbol->section->output_section->vma;
370214571Sdim  relocation += symbol->section->output_offset;
371214571Sdim  if (reloc_entry->address > input_section->size)
372214571Sdim    return bfd_reloc_outofrange;
373214571Sdim
374214571Sdim  insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
375214571Sdim  if (((reloc_entry->addend & 0xffffc000) != 0)
376214571Sdim      && ((reloc_entry->addend & 0xffffc000) != 0xffffc000))
377214571Sdim    return bfd_reloc_overflow;
378214571Sdim
379214571Sdim  insn = (insn & ~0x7fff) | (reloc_entry->addend & 0x7fff);
380214571Sdim  bfd_put_32 (abfd, insn, (bfd_byte *) data + reloc_entry->address);
381214571Sdim  if (relocateable)
382214571Sdim    reloc_entry->address += input_section->output_offset;
383214571Sdim
384214571Sdim  return bfd_reloc_ok;
385214571Sdim}
386214571Sdim
387214571Sdimstatic bfd_reloc_status_type
388214571Sdimgprel32_with_gp (bfd *abfd, asymbol *symbol, arelent *reloc_entry,
389214571Sdim		 asection *input_section, bfd_boolean relocatable,
390214571Sdim		 void *data, bfd_vma gp)
391214571Sdim{
392214571Sdim  bfd_vma relocation;
393214571Sdim  bfd_vma val;
394214571Sdim
395214571Sdim  if (bfd_is_com_section (symbol->section))
396214571Sdim    relocation = 0;
397214571Sdim  else
398214571Sdim    relocation = symbol->value;
399214571Sdim
400214571Sdim  relocation += symbol->section->output_section->vma;
401214571Sdim  relocation += symbol->section->output_offset;
402214571Sdim
403214571Sdim  if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
404214571Sdim    return bfd_reloc_outofrange;
405214571Sdim
406214571Sdim  /* Set val to the offset into the section or symbol.  */
407214571Sdim  val = reloc_entry->addend;
408214571Sdim
409214571Sdim  if (reloc_entry->howto->partial_inplace)
410214571Sdim    val += bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
411214571Sdim
412214571Sdim  /* Adjust val for the final section location and GP value.  If we
413214571Sdim     are producing relocatable output, we don't want to do this for
414214571Sdim     an external symbol.  */
415214571Sdim  if (! relocatable
416214571Sdim      || (symbol->flags & BSF_SECTION_SYM) != 0)
417214571Sdim    val += relocation - gp;
418214571Sdim
419214571Sdim  if (reloc_entry->howto->partial_inplace)
420214571Sdim    bfd_put_32 (abfd, val, (bfd_byte *) data + reloc_entry->address);
421214571Sdim  else
422214571Sdim    reloc_entry->addend = val;
423214571Sdim
424214571Sdim  if (relocatable)
425214571Sdim    reloc_entry->address += input_section->output_offset;
426214571Sdim
427214571Sdim  return bfd_reloc_ok;
428214571Sdim}
429214571Sdim
430214571Sdimstatic bfd_reloc_status_type
431214571Sdimscore_elf_gprel15_reloc (bfd *abfd,
432214571Sdim			 arelent *reloc_entry,
433214571Sdim			 asymbol *symbol,
434214571Sdim			 void * data,
435214571Sdim			 asection *input_section,
436214571Sdim			 bfd *output_bfd,
437214571Sdim			 char **error_message)
438214571Sdim{
439214571Sdim  bfd_boolean relocateable;
440214571Sdim  bfd_reloc_status_type ret;
441214571Sdim  bfd_vma gp;
442214571Sdim
443214571Sdim  if (output_bfd != (bfd *) NULL
444214571Sdim      && (symbol->flags & BSF_SECTION_SYM) == 0 && reloc_entry->addend == 0)
445214571Sdim    {
446214571Sdim      reloc_entry->address += input_section->output_offset;
447214571Sdim      return bfd_reloc_ok;
448214571Sdim    }
449214571Sdim  if (output_bfd != (bfd *) NULL)
450214571Sdim    relocateable = TRUE;
451214571Sdim  else
452214571Sdim    {
453214571Sdim      relocateable = FALSE;
454214571Sdim      output_bfd = symbol->section->output_section->owner;
455214571Sdim    }
456214571Sdim
457214571Sdim  ret = score_elf_final_gp (output_bfd, symbol, relocateable, error_message, &gp);
458214571Sdim  if (ret != bfd_reloc_ok)
459214571Sdim    return ret;
460214571Sdim
461214571Sdim  return score_elf_gprel15_with_gp (abfd, symbol, reloc_entry,
462214571Sdim                                         input_section, relocateable, data, gp);
463214571Sdim}
464214571Sdim
465214571Sdim/* Do a R_SCORE_GPREL32 relocation.  This is a 32 bit value which must
466214571Sdim   become the offset from the gp register.  */
467214571Sdim
468214571Sdimstatic bfd_reloc_status_type
469214571Sdimscore_elf_gprel32_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
470214571Sdim			void *data, asection *input_section, bfd *output_bfd,
471214571Sdim			char **error_message)
472214571Sdim{
473214571Sdim  bfd_boolean relocatable;
474214571Sdim  bfd_reloc_status_type ret;
475214571Sdim  bfd_vma gp;
476214571Sdim
477214571Sdim  /* R_SCORE_GPREL32 relocations are defined for local symbols only.  */
478214571Sdim  if (output_bfd != NULL
479214571Sdim      && (symbol->flags & BSF_SECTION_SYM) == 0
480214571Sdim      && (symbol->flags & BSF_LOCAL) != 0)
481214571Sdim    {
482214571Sdim      *error_message = (char *)
483214571Sdim	_("32bits gp relative relocation occurs for an external symbol");
484214571Sdim      return bfd_reloc_outofrange;
485214571Sdim    }
486214571Sdim
487214571Sdim  if (output_bfd != NULL)
488214571Sdim    relocatable = TRUE;
489214571Sdim  else
490214571Sdim    {
491214571Sdim      relocatable = FALSE;
492214571Sdim      output_bfd = symbol->section->output_section->owner;
493214571Sdim    }
494214571Sdim
495214571Sdim  ret = score_elf_final_gp (output_bfd, symbol, relocatable, error_message, &gp);
496214571Sdim  if (ret != bfd_reloc_ok)
497214571Sdim    return ret;
498214571Sdim
499214571Sdim  gp = 0;   /* FIXME.  */
500214571Sdim  return gprel32_with_gp (abfd, symbol, reloc_entry, input_section,
501214571Sdim			  relocatable, data, gp);
502214571Sdim}
503214571Sdim
504214571Sdim/* A howto special_function for R_SCORE_GOT15 relocations.  This is just
505214571Sdim   like any other 16-bit relocation when applied to global symbols, but is
506214571Sdim   treated in the same as R_SCORE_HI16 when applied to local symbols.  */
507214571Sdim
508214571Sdimstatic bfd_reloc_status_type
509214571Sdimscore_elf_got15_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
510214571Sdim		       void *data, asection *input_section,
511214571Sdim		       bfd *output_bfd, char **error_message)
512214571Sdim{
513214571Sdim  if ((symbol->flags & (BSF_GLOBAL | BSF_WEAK)) != 0
514214571Sdim      || bfd_is_und_section (bfd_get_section (symbol))
515214571Sdim      || bfd_is_com_section (bfd_get_section (symbol)))
516214571Sdim    /* The relocation is against a global symbol.  */
517214571Sdim    return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
518214571Sdim				  input_section, output_bfd,
519214571Sdim				  error_message);
520214571Sdim
521214571Sdim  return score_elf_hi16_reloc (abfd, reloc_entry, symbol, data,
522214571Sdim			       input_section, output_bfd, error_message);
523214571Sdim}
524214571Sdim
525214571Sdimstatic bfd_reloc_status_type
526214571Sdimscore_elf_got_lo16_reloc (bfd *abfd,
527214571Sdim		          arelent *reloc_entry,
528214571Sdim		          asymbol *symbol ATTRIBUTE_UNUSED,
529214571Sdim		          void * data,
530214571Sdim		          asection *input_section,
531214571Sdim		          bfd *output_bfd ATTRIBUTE_UNUSED,
532214571Sdim		          char **error_message ATTRIBUTE_UNUSED)
533214571Sdim{
534214571Sdim  bfd_vma addend = 0, offset = 0;
535214571Sdim  signed long val;
536214571Sdim  signed long hi16_offset, hi16_value, uvalue;
537214571Sdim
538214571Sdim  hi16_value = bfd_get_32 (abfd, hi16_rel_addr);
539214571Sdim  hi16_offset = ((((hi16_value >> 16) & 0x3) << 15) | (hi16_value & 0x7fff)) >> 1;
540214571Sdim  addend = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
541214571Sdim  offset = ((((addend >> 16) & 0x3) << 15) | (addend & 0x7fff)) >> 1;
542214571Sdim  val = reloc_entry->addend;
543214571Sdim  if (reloc_entry->address > input_section->size)
544214571Sdim    return bfd_reloc_outofrange;
545214571Sdim  uvalue = ((hi16_offset << 16) | (offset & 0xffff)) + val;
546214571Sdim  if ((uvalue > -0x8000) && (uvalue < 0x7fff))
547214571Sdim    hi16_offset = 0;
548214571Sdim  else
549214571Sdim    hi16_offset = (uvalue >> 16) & 0x7fff;
550214571Sdim  hi16_value = (hi16_value & ~0x37fff) | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000);
551214571Sdim  bfd_put_32 (abfd, hi16_value, hi16_rel_addr);
552214571Sdim  offset = (uvalue & 0xffff) << 1;
553214571Sdim  addend = (addend & ~0x37fff) | (offset & 0x7fff) | ((offset << 1) & 0x30000);
554214571Sdim  bfd_put_32 (abfd, addend, (bfd_byte *) data + reloc_entry->address);
555214571Sdim  return bfd_reloc_ok;
556214571Sdim}
557214571Sdim
558214571Sdimstatic reloc_howto_type elf32_score_howto_table[] =
559214571Sdim{
560214571Sdim  /* No relocation.  */
561214571Sdim  HOWTO (R_SCORE_NONE,          /* type */
562214571Sdim         0,                     /* rightshift */
563214571Sdim         0,                     /* size (0 = byte, 1 = short, 2 = long) */
564214571Sdim         0,                     /* bitsize */
565214571Sdim         FALSE,                 /* pc_relative */
566214571Sdim         0,                     /* bitpos */
567214571Sdim         complain_overflow_dont,/* complain_on_overflow */
568214571Sdim         bfd_elf_generic_reloc, /* special_function */
569214571Sdim         "R_SCORE_NONE",        /* name */
570214571Sdim         FALSE,                 /* partial_inplace */
571214571Sdim         0,                     /* src_mask */
572214571Sdim         0,                     /* dst_mask */
573214571Sdim         FALSE),                /* pcrel_offset */
574214571Sdim
575214571Sdim  /* R_SCORE_HI16 */
576214571Sdim  HOWTO (R_SCORE_HI16,          /* type */
577214571Sdim         0,                     /* rightshift */
578214571Sdim         2,                     /* size (0 = byte, 1 = short, 2 = long) */
579214571Sdim         16,                    /* bitsize */
580214571Sdim         FALSE,                 /* pc_relative */
581214571Sdim         1,                     /* bitpos */
582214571Sdim         complain_overflow_dont,/* complain_on_overflow */
583214571Sdim	 score_elf_hi16_reloc,  /* special_function */
584214571Sdim         "R_SCORE_HI16",        /* name */
585214571Sdim         TRUE,                  /* partial_inplace */
586214571Sdim         0x37fff,               /* src_mask */
587214571Sdim         0x37fff,               /* dst_mask */
588214571Sdim         FALSE),                /* pcrel_offset */
589214571Sdim
590214571Sdim  /* R_SCORE_LO16 */
591214571Sdim  HOWTO (R_SCORE_LO16,          /* type */
592214571Sdim         0,                     /* rightshift */
593214571Sdim         2,                     /* size (0 = byte, 1 = short, 2 = long) */
594214571Sdim         16,                    /* bitsize */
595214571Sdim         FALSE,                 /* pc_relative */
596214571Sdim         1,                     /* bitpos */
597214571Sdim         complain_overflow_dont,/* complain_on_overflow */
598214571Sdim         score_elf_lo16_reloc,  /* special_function */
599214571Sdim         "R_SCORE_LO16",        /* name */
600214571Sdim         TRUE,                  /* partial_inplace */
601214571Sdim         0x37fff,               /* src_mask */
602214571Sdim         0x37fff,               /* dst_mask */
603214571Sdim         FALSE),                /* pcrel_offset */
604214571Sdim
605214571Sdim  /*  R_SCORE_DUMMY1 */
606214571Sdim  HOWTO (R_SCORE_DUMMY1,        /* type */
607214571Sdim         0,                     /* rightshift */
608214571Sdim         2,                     /* size (0 = byte, 1 = short, 2 = long) */
609214571Sdim         16,                    /* bitsize */
610214571Sdim         FALSE,                 /* pc_relative */
611214571Sdim         1,                     /* bitpos */
612214571Sdim         complain_overflow_dont,/* complain_on_overflow */
613214571Sdim         bfd_elf_generic_reloc, /* special_function */
614214571Sdim         "R_SCORE_DUMMY1",      /* name */
615214571Sdim         TRUE,                  /* partial_inplace */
616214571Sdim         0x0000ffff,            /* src_mask */
617214571Sdim         0x0000ffff,            /* dst_mask */
618214571Sdim         FALSE),                /* pcrel_offset */
619214571Sdim
620214571Sdim  /*R_SCORE_24 */
621214571Sdim  HOWTO (R_SCORE_24,            /* type */
622214571Sdim         1,                     /* rightshift */
623214571Sdim         2,                     /* size (0 = byte, 1 = short, 2 = long) */
624214571Sdim         24,                    /* bitsize */
625214571Sdim         FALSE,                 /* pc_relative */
626214571Sdim         1,                     /* bitpos */
627214571Sdim         complain_overflow_dont,/* complain_on_overflow */
628214571Sdim         bfd_elf_generic_reloc, /* special_function */
629214571Sdim         "R_SCORE_24",          /* name */
630214571Sdim         FALSE,                 /* partial_inplace */
631214571Sdim         0x3ff7fff,             /* src_mask */
632214571Sdim         0x3ff7fff,             /* dst_mask */
633214571Sdim         FALSE),                /* pcrel_offset */
634214571Sdim
635214571Sdim  /*R_SCORE_PC19 */
636214571Sdim  HOWTO (R_SCORE_PC19,          /* type */
637214571Sdim         1,                     /* rightshift */
638214571Sdim         2,                     /* size (0 = byte, 1 = short, 2 = long) */
639214571Sdim         19,                    /* bitsize */
640214571Sdim         TRUE,                  /* pc_relative */
641214571Sdim         1,                     /* bitpos */
642214571Sdim         complain_overflow_dont,/* complain_on_overflow */
643214571Sdim         bfd_elf_generic_reloc, /* special_function */
644214571Sdim         "R_SCORE_PC19",        /* name */
645214571Sdim         FALSE,                 /* partial_inplace */
646214571Sdim         0x3ff03fe,             /* src_mask */
647214571Sdim         0x3ff03fe,             /* dst_mask */
648214571Sdim         FALSE),                /* pcrel_offset */
649214571Sdim
650214571Sdim  /*R_SCORE16_11 */
651214571Sdim  HOWTO (R_SCORE16_11,          /* type */
652214571Sdim         1,                     /* rightshift */
653214571Sdim         1,                     /* size (0 = byte, 1 = short, 2 = long) */
654214571Sdim         11,                    /* bitsize */
655214571Sdim         FALSE,                 /* pc_relative */
656214571Sdim         1,                     /* bitpos */
657214571Sdim         complain_overflow_dont,/* complain_on_overflow */
658214571Sdim         bfd_elf_generic_reloc, /* special_function */
659214571Sdim         "R_SCORE16_11",        /* name */
660214571Sdim         FALSE,                 /* partial_inplace */
661214571Sdim         0x000000ffe,           /* src_mask */
662214571Sdim         0x000000ffe,           /* dst_mask */
663214571Sdim         FALSE),                /* pcrel_offset */
664214571Sdim
665214571Sdim  /* R_SCORE16_PC8 */
666214571Sdim  HOWTO (R_SCORE16_PC8,         /* type */
667214571Sdim         1,                     /* rightshift */
668214571Sdim         1,                     /* size (0 = byte, 1 = short, 2 = long) */
669214571Sdim         8,                     /* bitsize */
670214571Sdim         TRUE,                  /* pc_relative */
671214571Sdim         0,                     /* bitpos */
672214571Sdim         complain_overflow_dont,/* complain_on_overflow */
673214571Sdim         bfd_elf_generic_reloc, /* special_function */
674214571Sdim         "R_SCORE16_PC8",       /* name */
675214571Sdim         FALSE,                 /* partial_inplace */
676214571Sdim         0x000000ff,            /* src_mask */
677214571Sdim         0x000000ff,            /* dst_mask */
678214571Sdim         FALSE),                /* pcrel_offset */
679214571Sdim
680214571Sdim  /* 32 bit absolute */
681214571Sdim  HOWTO (R_SCORE_ABS32,         /* type  8 */
682214571Sdim         0,                     /* rightshift */
683214571Sdim         2,                     /* size (0 = byte, 1 = short, 2 = long) */
684214571Sdim         32,                    /* bitsize */
685214571Sdim         FALSE,                 /* pc_relative */
686214571Sdim         0,                     /* bitpos */
687214571Sdim         complain_overflow_bitfield,    /* complain_on_overflow */
688214571Sdim         bfd_elf_generic_reloc, /* special_function */
689214571Sdim         "R_SCORE_ABS32",       /* name */
690214571Sdim         FALSE,                 /* partial_inplace */
691214571Sdim         0xffffffff,            /* src_mask */
692214571Sdim         0xffffffff,            /* dst_mask */
693214571Sdim         FALSE),                /* pcrel_offset */
694214571Sdim
695214571Sdim  /* 16 bit absolute */
696214571Sdim  HOWTO (R_SCORE_ABS16,         /* type 11 */
697214571Sdim         0,                     /* rightshift */
698214571Sdim         1,                     /* size (0 = byte, 1 = short, 2 = long) */
699214571Sdim         16,                    /* bitsize */
700214571Sdim         FALSE,                 /* pc_relative */
701214571Sdim         0,                     /* bitpos */
702214571Sdim         complain_overflow_bitfield,    /* complain_on_overflow */
703214571Sdim         bfd_elf_generic_reloc, /* special_function */
704214571Sdim         "R_SCORE_ABS16",       /* name */
705214571Sdim         FALSE,                 /* partial_inplace */
706214571Sdim         0x0000ffff,            /* src_mask */
707214571Sdim         0x0000ffff,            /* dst_mask */
708214571Sdim         FALSE),                /* pcrel_offset */
709214571Sdim
710214571Sdim  /* R_SCORE_DUMMY2 */
711214571Sdim  HOWTO (R_SCORE_DUMMY2,        /* type */
712214571Sdim         0,                     /* rightshift */
713214571Sdim         2,                     /* size (0 = byte, 1 = short, 2 = long) */
714214571Sdim         16,                    /* bitsize */
715214571Sdim         FALSE,                 /* pc_relative */
716214571Sdim         0,                     /* bitpos */
717214571Sdim         complain_overflow_dont,/* complain_on_overflow */
718214571Sdim         bfd_elf_generic_reloc, /* special_function */
719214571Sdim         "R_SCORE_DUMMY2",      /* name */
720214571Sdim         TRUE,                  /* partial_inplace */
721214571Sdim         0x00007fff,            /* src_mask */
722214571Sdim         0x00007fff,            /* dst_mask */
723214571Sdim         FALSE),                /* pcrel_offset */
724214571Sdim
725214571Sdim  /* R_SCORE_GP15 */
726214571Sdim  HOWTO (R_SCORE_GP15,          /* type */
727214571Sdim         0,                     /* rightshift */
728214571Sdim         2,                     /* size (0 = byte, 1 = short, 2 = long) */
729214571Sdim         16,                    /* bitsize */
730214571Sdim         FALSE,                 /* pc_relative */
731214571Sdim         0,                     /* bitpos */
732214571Sdim         complain_overflow_dont,/* complain_on_overflow */
733214571Sdim         score_elf_gprel15_reloc,/* special_function */
734214571Sdim         "R_SCORE_GP15",        /* name */
735214571Sdim         TRUE,                  /* partial_inplace */
736214571Sdim         0x00007fff,            /* src_mask */
737214571Sdim         0x00007fff,            /* dst_mask */
738214571Sdim         FALSE),                /* pcrel_offset */
739214571Sdim
740214571Sdim  /* GNU extension to record C++ vtable hierarchy.  */
741214571Sdim  HOWTO (R_SCORE_GNU_VTINHERIT, /* type */
742214571Sdim         0,                     /* rightshift */
743214571Sdim         2,                     /* size (0 = byte, 1 = short, 2 = long) */
744214571Sdim         0,                     /* bitsize */
745214571Sdim         FALSE,                 /* pc_relative */
746214571Sdim         0,                     /* bitpos */
747214571Sdim         complain_overflow_dont,/* complain_on_overflow */
748214571Sdim         NULL,                  /* special_function */
749214571Sdim         "R_SCORE_GNU_VTINHERIT",       /* name */
750214571Sdim         FALSE,                 /* partial_inplace */
751214571Sdim         0,                     /* src_mask */
752214571Sdim         0,                     /* dst_mask */
753214571Sdim         FALSE),                /* pcrel_offset */
754214571Sdim
755214571Sdim  /* GNU extension to record C++ vtable member usage */
756214571Sdim  HOWTO (R_SCORE_GNU_VTENTRY,   /* type */
757214571Sdim         0,                     /* rightshift */
758214571Sdim         2,                     /* size (0 = byte, 1 = short, 2 = long) */
759214571Sdim         0,                     /* bitsize */
760214571Sdim         FALSE,                 /* pc_relative */
761214571Sdim         0,                     /* bitpos */
762214571Sdim         complain_overflow_dont,/* complain_on_overflow */
763214571Sdim         _bfd_elf_rel_vtable_reloc_fn,  /* special_function */
764214571Sdim         "R_SCORE_GNU_VTENTRY", /* name */
765214571Sdim         FALSE,                 /* partial_inplace */
766214571Sdim         0,                     /* src_mask */
767214571Sdim         0,                     /* dst_mask */
768214571Sdim         FALSE),                /* pcrel_offset */
769214571Sdim
770214571Sdim  /* Reference to global offset table.  */
771214571Sdim  HOWTO (R_SCORE_GOT15,         /* type */
772214571Sdim         0,                     /* rightshift */
773214571Sdim         2,                     /* size (0 = byte, 1 = short, 2 = long) */
774214571Sdim         16,                    /* bitsize */
775214571Sdim         FALSE,                 /* pc_relative */
776214571Sdim         0,                     /* bitpos */
777214571Sdim         complain_overflow_signed,      /* complain_on_overflow */
778214571Sdim         score_elf_got15_reloc, /* special_function */
779214571Sdim         "R_SCORE_GOT15",       /* name */
780214571Sdim         TRUE,                  /* partial_inplace */
781214571Sdim         0x00007fff,            /* src_mask */
782214571Sdim         0x00007fff,            /* dst_mask */
783214571Sdim         FALSE),                /* pcrel_offset */
784214571Sdim
785214571Sdim  /* Low 16 bits of displacement in global offset table.  */
786214571Sdim  HOWTO (R_SCORE_GOT_LO16,      /* type */
787214571Sdim         0,                     /* rightshift */
788214571Sdim         2,                     /* size (0 = byte, 1 = short, 2 = long) */
789214571Sdim         16,                    /* bitsize */
790214571Sdim         FALSE,                 /* pc_relative */
791214571Sdim         1,                     /* bitpos */
792214571Sdim         complain_overflow_dont,/* complain_on_overflow */
793214571Sdim         score_elf_got_lo16_reloc, /* special_function */
794214571Sdim         "R_SCORE_GOT_LO16",    /* name */
795214571Sdim         TRUE,                  /* partial_inplace */
796214571Sdim         0x37ffe,               /* src_mask */
797214571Sdim         0x37ffe,               /* dst_mask */
798214571Sdim         FALSE),                /* pcrel_offset */
799214571Sdim
800214571Sdim  /* 15 bit call through global offset table.  */
801214571Sdim  HOWTO (R_SCORE_CALL15,        /* type */
802214571Sdim         0,                     /* rightshift */
803214571Sdim         2,                     /* size (0 = byte, 1 = short, 2 = long) */
804214571Sdim         16,                    /* bitsize */
805214571Sdim         FALSE,                 /* pc_relative */
806214571Sdim         0,                     /* bitpos */
807214571Sdim         complain_overflow_signed, /* complain_on_overflow */
808214571Sdim         bfd_elf_generic_reloc, /* special_function */
809214571Sdim         "R_SCORE_CALL15",      /* name */
810214571Sdim         TRUE,                  /* partial_inplace */
811214571Sdim         0x0000ffff,            /* src_mask */
812214571Sdim         0x0000ffff,            /* dst_mask */
813214571Sdim         FALSE),                /* pcrel_offset */
814214571Sdim
815214571Sdim  /* 32 bit GP relative reference.  */
816214571Sdim  HOWTO (R_SCORE_GPREL32,       /* type */
817214571Sdim         0,                     /* rightshift */
818214571Sdim         2,                     /* size (0 = byte, 1 = short, 2 = long) */
819214571Sdim         32,                    /* bitsize */
820214571Sdim         FALSE,                 /* pc_relative */
821214571Sdim         0,                     /* bitpos */
822214571Sdim         complain_overflow_dont,/* complain_on_overflow */
823214571Sdim         score_elf_gprel32_reloc, /* special_function */
824214571Sdim         "R_SCORE_GPREL32",     /* name */
825214571Sdim         TRUE,                  /* partial_inplace */
826214571Sdim         0xffffffff,            /* src_mask */
827214571Sdim         0xffffffff,            /* dst_mask */
828214571Sdim         FALSE),                /* pcrel_offset */
829214571Sdim
830214571Sdim  /* 32 bit symbol relative relocation.  */
831214571Sdim  HOWTO (R_SCORE_REL32,         /* type */
832214571Sdim	 0,                     /* rightshift */
833214571Sdim	 2,                     /* size (0 = byte, 1 = short, 2 = long) */
834214571Sdim	 32,                    /* bitsize */
835214571Sdim	 FALSE,                 /* pc_relative */
836214571Sdim	 0,                     /* bitpos */
837214571Sdim	 complain_overflow_dont,/* complain_on_overflow */
838214571Sdim	 bfd_elf_generic_reloc, /* special_function */
839214571Sdim	 "R_SCORE_REL32",       /* name */
840214571Sdim	 TRUE,                  /* partial_inplace */
841214571Sdim	 0xffffffff,            /* src_mask */
842214571Sdim	 0xffffffff,            /* dst_mask */
843214571Sdim	 FALSE),                /* pcrel_offset */
844214571Sdim
845214571Sdim  /* R_SCORE_DUMMY_HI16 */
846214571Sdim  HOWTO (R_SCORE_DUMMY_HI16,    /* type */
847214571Sdim         0,                     /* rightshift */
848214571Sdim         2,                     /* size (0 = byte, 1 = short, 2 = long) */
849214571Sdim         16,                    /* bitsize */
850214571Sdim         FALSE,                 /* pc_relative */
851214571Sdim         1,                     /* bitpos */
852214571Sdim         complain_overflow_dont,/* complain_on_overflow */
853214571Sdim	 score_elf_hi16_reloc,  /* special_function */
854214571Sdim         "R_SCORE_DUMMY_HI16",  /* name */
855214571Sdim         TRUE,                  /* partial_inplace */
856214571Sdim         0x37fff,               /* src_mask */
857214571Sdim         0x37fff,               /* dst_mask */
858214571Sdim         FALSE),                /* pcrel_offset */
859214571Sdim};
860214571Sdim
861214571Sdimstruct score_reloc_map
862214571Sdim{
863214571Sdim  bfd_reloc_code_real_type bfd_reloc_val;
864214571Sdim  unsigned char elf_reloc_val;
865214571Sdim};
866214571Sdim
867214571Sdimstatic const struct score_reloc_map elf32_score_reloc_map[] =
868214571Sdim{
869214571Sdim  {BFD_RELOC_NONE,               R_SCORE_NONE},
870214571Sdim  {BFD_RELOC_HI16_S,             R_SCORE_HI16},
871214571Sdim  {BFD_RELOC_LO16,               R_SCORE_LO16},
872214571Sdim  {BFD_RELOC_SCORE_DUMMY1,       R_SCORE_DUMMY1},
873214571Sdim  {BFD_RELOC_SCORE_JMP,          R_SCORE_24},
874214571Sdim  {BFD_RELOC_SCORE_BRANCH,       R_SCORE_PC19},
875214571Sdim  {BFD_RELOC_SCORE16_JMP,        R_SCORE16_11},
876214571Sdim  {BFD_RELOC_SCORE16_BRANCH,     R_SCORE16_PC8},
877214571Sdim  {BFD_RELOC_32,                 R_SCORE_ABS32},
878214571Sdim  {BFD_RELOC_16,                 R_SCORE_ABS16},
879214571Sdim  {BFD_RELOC_SCORE_DUMMY2,       R_SCORE_DUMMY2},
880214571Sdim  {BFD_RELOC_SCORE_GPREL15,      R_SCORE_GP15},
881214571Sdim  {BFD_RELOC_VTABLE_INHERIT,     R_SCORE_GNU_VTINHERIT},
882214571Sdim  {BFD_RELOC_VTABLE_ENTRY,       R_SCORE_GNU_VTENTRY},
883214571Sdim  {BFD_RELOC_SCORE_GOT15,        R_SCORE_GOT15},
884214571Sdim  {BFD_RELOC_SCORE_GOT_LO16,     R_SCORE_GOT_LO16},
885214571Sdim  {BFD_RELOC_SCORE_CALL15,       R_SCORE_CALL15},
886214571Sdim  {BFD_RELOC_GPREL32,            R_SCORE_GPREL32},
887214571Sdim  {BFD_RELOC_32_PCREL,           R_SCORE_REL32},
888214571Sdim  {BFD_RELOC_SCORE_DUMMY_HI16,   R_SCORE_DUMMY_HI16},
889214571Sdim};
890214571Sdim
891214571Sdim/* got_entries only match if they're identical, except for gotidx, so
892214571Sdim   use all fields to compute the hash, and compare the appropriate
893214571Sdim   union members.  */
894214571Sdim
895214571Sdimstatic hashval_t
896214571Sdimscore_elf_got_entry_hash (const void *entry_)
897214571Sdim{
898214571Sdim  const struct score_got_entry *entry = (struct score_got_entry *)entry_;
899214571Sdim
900214571Sdim  return entry->symndx
901214571Sdim    + (!entry->abfd ? entry->d.address : entry->abfd->id);
902214571Sdim}
903214571Sdim
904214571Sdimstatic int
905214571Sdimscore_elf_got_entry_eq (const void *entry1, const void *entry2)
906214571Sdim{
907214571Sdim  const struct score_got_entry *e1 = (struct score_got_entry *)entry1;
908214571Sdim  const struct score_got_entry *e2 = (struct score_got_entry *)entry2;
909214571Sdim
910214571Sdim  return e1->abfd == e2->abfd && e1->symndx == e2->symndx
911214571Sdim    && (! e1->abfd ? e1->d.address == e2->d.address
912214571Sdim	: e1->symndx >= 0 ? e1->d.addend == e2->d.addend
913214571Sdim	: e1->d.h == e2->d.h);
914214571Sdim}
915214571Sdim
916214571Sdim/* If H needs a GOT entry, assign it the highest available dynamic
917214571Sdim   index.  Otherwise, assign it the lowest available dynamic
918214571Sdim   index.  */
919214571Sdim
920214571Sdimstatic bfd_boolean
921214571Sdimscore_elf_sort_hash_table_f (struct score_elf_link_hash_entry *h, void *data)
922214571Sdim{
923214571Sdim  struct score_elf_hash_sort_data *hsd = data;
924214571Sdim
925214571Sdim  if (h->root.root.type == bfd_link_hash_warning)
926214571Sdim    h = (struct score_elf_link_hash_entry *) h->root.root.u.i.link;
927214571Sdim
928214571Sdim  /* Symbols without dynamic symbol table entries aren't interesting at all.  */
929214571Sdim  if (h->root.dynindx == -1)
930214571Sdim    return TRUE;
931214571Sdim
932214571Sdim  /* Global symbols that need GOT entries that are not explicitly
933214571Sdim     referenced are marked with got offset 2.  Those that are
934214571Sdim     referenced get a 1, and those that don't need GOT entries get
935214571Sdim     -1.  */
936214571Sdim  if (h->root.got.offset == 2)
937214571Sdim    {
938214571Sdim      if (hsd->max_unref_got_dynindx == hsd->min_got_dynindx)
939214571Sdim	hsd->low = (struct elf_link_hash_entry *) h;
940214571Sdim      h->root.dynindx = hsd->max_unref_got_dynindx++;
941214571Sdim    }
942214571Sdim  else if (h->root.got.offset != 1)
943214571Sdim    h->root.dynindx = hsd->max_non_got_dynindx++;
944214571Sdim  else
945214571Sdim    {
946214571Sdim      h->root.dynindx = --hsd->min_got_dynindx;
947214571Sdim      hsd->low = (struct elf_link_hash_entry *) h;
948214571Sdim    }
949214571Sdim
950214571Sdim  return TRUE;
951214571Sdim}
952214571Sdim
953214571Sdimstatic asection *
954214571Sdimscore_elf_got_section (bfd *abfd, bfd_boolean maybe_excluded)
955214571Sdim{
956214571Sdim  asection *sgot = bfd_get_section_by_name (abfd, ".got");
957214571Sdim
958214571Sdim  if (sgot == NULL || (! maybe_excluded && (sgot->flags & SEC_EXCLUDE) != 0))
959214571Sdim    return NULL;
960214571Sdim  return sgot;
961214571Sdim}
962214571Sdim
963214571Sdim/* Returns the GOT information associated with the link indicated by
964214571Sdim   INFO.  If SGOTP is non-NULL, it is filled in with the GOT section.  */
965214571Sdim
966214571Sdimstatic struct score_got_info *
967214571Sdimscore_elf_got_info (bfd *abfd, asection **sgotp)
968214571Sdim{
969214571Sdim  asection *sgot;
970214571Sdim  struct score_got_info *g;
971214571Sdim
972214571Sdim  sgot = score_elf_got_section (abfd, TRUE);
973214571Sdim  BFD_ASSERT (sgot != NULL);
974214571Sdim  BFD_ASSERT (elf_section_data (sgot) != NULL);
975214571Sdim  g = score_elf_section_data (sgot)->u.got_info;
976214571Sdim  BFD_ASSERT (g != NULL);
977214571Sdim
978214571Sdim  if (sgotp)
979214571Sdim    *sgotp = sgot;
980214571Sdim  return g;
981214571Sdim}
982214571Sdim
983214571Sdim/* Sort the dynamic symbol table so that symbols that need GOT entries
984214571Sdim   appear towards the end.  This reduces the amount of GOT space
985214571Sdim   required.  MAX_LOCAL is used to set the number of local symbols
986214571Sdim   known to be in the dynamic symbol table.  During
987214571Sdim   _bfd_score_elf_size_dynamic_sections, this value is 1.  Afterward, the
988214571Sdim   section symbols are added and the count is higher.  */
989214571Sdim
990214571Sdimstatic bfd_boolean
991214571Sdimscore_elf_sort_hash_table (struct bfd_link_info *info,
992214571Sdim			   unsigned long max_local)
993214571Sdim{
994214571Sdim  struct score_elf_hash_sort_data hsd;
995214571Sdim  struct score_got_info *g;
996214571Sdim  bfd *dynobj;
997214571Sdim
998214571Sdim  dynobj = elf_hash_table (info)->dynobj;
999214571Sdim
1000214571Sdim  g = score_elf_got_info (dynobj, NULL);
1001214571Sdim
1002214571Sdim  hsd.low = NULL;
1003214571Sdim  hsd.max_unref_got_dynindx =
1004214571Sdim    hsd.min_got_dynindx = elf_hash_table (info)->dynsymcount
1005214571Sdim    /* In the multi-got case, assigned_gotno of the master got_info
1006214571Sdim       indicate the number of entries that aren't referenced in the
1007214571Sdim       primary GOT, but that must have entries because there are
1008214571Sdim       dynamic relocations that reference it.  Since they aren't
1009214571Sdim       referenced, we move them to the end of the GOT, so that they
1010214571Sdim       don't prevent other entries that are referenced from getting
1011214571Sdim       too large offsets.  */
1012214571Sdim    - (g->next ? g->assigned_gotno : 0);
1013214571Sdim  hsd.max_non_got_dynindx = max_local;
1014214571Sdim  score_elf_link_hash_traverse (((struct score_elf_link_hash_table *)
1015214571Sdim				 elf_hash_table (info)),
1016214571Sdim			         score_elf_sort_hash_table_f,
1017214571Sdim			         &hsd);
1018214571Sdim
1019214571Sdim  /* There should have been enough room in the symbol table to
1020214571Sdim     accommodate both the GOT and non-GOT symbols.  */
1021214571Sdim  BFD_ASSERT (hsd.max_non_got_dynindx <= hsd.min_got_dynindx);
1022214571Sdim  BFD_ASSERT ((unsigned long)hsd.max_unref_got_dynindx
1023214571Sdim	      <= elf_hash_table (info)->dynsymcount);
1024214571Sdim
1025214571Sdim  /* Now we know which dynamic symbol has the lowest dynamic symbol
1026214571Sdim     table index in the GOT.  */
1027214571Sdim  g->global_gotsym = hsd.low;
1028214571Sdim
1029214571Sdim  return TRUE;
1030214571Sdim}
1031214571Sdim
1032214571Sdim/* Create an entry in an score ELF linker hash table.  */
1033214571Sdim
1034214571Sdimstatic struct bfd_hash_entry *
1035214571Sdimscore_elf_link_hash_newfunc (struct bfd_hash_entry *entry,
1036214571Sdim			     struct bfd_hash_table *table,
1037214571Sdim			     const char *string)
1038214571Sdim{
1039214571Sdim  struct score_elf_link_hash_entry *ret = (struct score_elf_link_hash_entry *)entry;
1040214571Sdim
1041214571Sdim  /* Allocate the structure if it has not already been allocated by a subclass.  */
1042214571Sdim  if (ret == NULL)
1043214571Sdim    ret = bfd_hash_allocate (table, sizeof (struct score_elf_link_hash_entry));
1044214571Sdim  if (ret == NULL)
1045214571Sdim    return (struct bfd_hash_entry *)ret;
1046214571Sdim
1047214571Sdim  /* Call the allocation method of the superclass.  */
1048214571Sdim  ret = ((struct score_elf_link_hash_entry *)
1049214571Sdim         _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *)ret, table, string));
1050214571Sdim
1051214571Sdim  if (ret != NULL)
1052214571Sdim    {
1053214571Sdim      ret->possibly_dynamic_relocs = 0;
1054214571Sdim      ret->readonly_reloc = FALSE;
1055214571Sdim      ret->no_fn_stub = FALSE;
1056214571Sdim      ret->forced_local = FALSE;
1057214571Sdim    }
1058214571Sdim
1059214571Sdim  return (struct bfd_hash_entry *)ret;
1060214571Sdim}
1061214571Sdim
1062214571Sdim/* Returns the first relocation of type r_type found, beginning with
1063214571Sdim   RELOCATION.  RELEND is one-past-the-end of the relocation table.  */
1064214571Sdim
1065214571Sdimstatic const Elf_Internal_Rela *
1066214571Sdimscore_elf_next_relocation (bfd *abfd ATTRIBUTE_UNUSED, unsigned int r_type,
1067214571Sdim	 		   const Elf_Internal_Rela *relocation,
1068214571Sdim			   const Elf_Internal_Rela *relend)
1069214571Sdim{
1070214571Sdim  while (relocation < relend)
1071214571Sdim    {
1072214571Sdim      if (ELF32_R_TYPE (relocation->r_info) == r_type)
1073214571Sdim	return relocation;
1074214571Sdim
1075214571Sdim      ++relocation;
1076214571Sdim    }
1077214571Sdim
1078214571Sdim  /* We didn't find it.  */
1079214571Sdim  bfd_set_error (bfd_error_bad_value);
1080214571Sdim  return NULL;
1081214571Sdim}
1082214571Sdim
1083214571Sdim/* This function is called via qsort() to sort the dynamic relocation
1084214571Sdim   entries by increasing r_symndx value.  */
1085214571Sdim
1086214571Sdimstatic int
1087214571Sdimscore_elf_sort_dynamic_relocs (const void *arg1, const void *arg2)
1088214571Sdim{
1089214571Sdim  Elf_Internal_Rela int_reloc1;
1090214571Sdim  Elf_Internal_Rela int_reloc2;
1091214571Sdim
1092214571Sdim  bfd_elf32_swap_reloc_in (reldyn_sorting_bfd, arg1, &int_reloc1);
1093214571Sdim  bfd_elf32_swap_reloc_in (reldyn_sorting_bfd, arg2, &int_reloc2);
1094214571Sdim
1095214571Sdim  return (ELF32_R_SYM (int_reloc1.r_info) - ELF32_R_SYM (int_reloc2.r_info));
1096214571Sdim}
1097214571Sdim
1098214571Sdim/* Return whether a relocation is against a local symbol.  */
1099214571Sdim
1100214571Sdimstatic bfd_boolean
1101214571Sdimscore_elf_local_relocation_p (bfd *input_bfd,
1102214571Sdim			      const Elf_Internal_Rela *relocation,
1103214571Sdim			      asection **local_sections,
1104214571Sdim			      bfd_boolean check_forced)
1105214571Sdim{
1106214571Sdim  unsigned long r_symndx;
1107214571Sdim  Elf_Internal_Shdr *symtab_hdr;
1108214571Sdim  struct score_elf_link_hash_entry *h;
1109214571Sdim  size_t extsymoff;
1110214571Sdim
1111214571Sdim  r_symndx = ELF32_R_SYM (relocation->r_info);
1112214571Sdim  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
1113214571Sdim  extsymoff = (elf_bad_symtab (input_bfd)) ? 0 : symtab_hdr->sh_info;
1114214571Sdim
1115214571Sdim  if (r_symndx < extsymoff)
1116214571Sdim    return TRUE;
1117214571Sdim  if (elf_bad_symtab (input_bfd) && local_sections[r_symndx] != NULL)
1118214571Sdim    return TRUE;
1119214571Sdim
1120214571Sdim  if (check_forced)
1121214571Sdim    {
1122214571Sdim      /* Look up the hash table to check whether the symbol was forced local.  */
1123214571Sdim      h = (struct score_elf_link_hash_entry *)
1124214571Sdim	elf_sym_hashes (input_bfd) [r_symndx - extsymoff];
1125214571Sdim      /* Find the real hash-table entry for this symbol.  */
1126214571Sdim      while (h->root.root.type == bfd_link_hash_indirect
1127214571Sdim	     || h->root.root.type == bfd_link_hash_warning)
1128214571Sdim	h = (struct score_elf_link_hash_entry *) h->root.root.u.i.link;
1129214571Sdim      if (h->root.forced_local)
1130214571Sdim	return TRUE;
1131214571Sdim    }
1132214571Sdim
1133214571Sdim  return FALSE;
1134214571Sdim}
1135214571Sdim
1136214571Sdim/* Returns the dynamic relocation section for DYNOBJ.  */
1137214571Sdim
1138214571Sdimstatic asection *
1139214571Sdimscore_elf_rel_dyn_section (bfd *dynobj, bfd_boolean create_p)
1140214571Sdim{
1141214571Sdim  static const char dname[] = ".rel.dyn";
1142214571Sdim  asection *sreloc;
1143214571Sdim
1144214571Sdim  sreloc = bfd_get_section_by_name (dynobj, dname);
1145214571Sdim  if (sreloc == NULL && create_p)
1146214571Sdim    {
1147214571Sdim      sreloc = bfd_make_section_with_flags (dynobj, dname,
1148214571Sdim                                            (SEC_ALLOC
1149214571Sdim                                             | SEC_LOAD
1150214571Sdim                                             | SEC_HAS_CONTENTS
1151214571Sdim                                             | SEC_IN_MEMORY
1152214571Sdim                                             | SEC_LINKER_CREATED
1153214571Sdim                                             | SEC_READONLY));
1154214571Sdim      if (sreloc == NULL
1155214571Sdim	  || ! bfd_set_section_alignment (dynobj, sreloc,
1156214571Sdim					  SCORE_ELF_LOG_FILE_ALIGN (dynobj)))
1157214571Sdim	return NULL;
1158214571Sdim    }
1159214571Sdim  return sreloc;
1160214571Sdim}
1161214571Sdim
1162214571Sdimstatic void
1163214571Sdimscore_elf_allocate_dynamic_relocations (bfd *abfd, unsigned int n)
1164214571Sdim{
1165214571Sdim  asection *s;
1166214571Sdim
1167214571Sdim  s = score_elf_rel_dyn_section (abfd, FALSE);
1168214571Sdim  BFD_ASSERT (s != NULL);
1169214571Sdim
1170214571Sdim  if (s->size == 0)
1171214571Sdim    {
1172214571Sdim      /* Make room for a null element.  */
1173214571Sdim      s->size += SCORE_ELF_REL_SIZE (abfd);
1174214571Sdim      ++s->reloc_count;
1175214571Sdim    }
1176214571Sdim  s->size += n * SCORE_ELF_REL_SIZE (abfd);
1177214571Sdim}
1178214571Sdim
1179214571Sdim/* Create a rel.dyn relocation for the dynamic linker to resolve.  REL
1180214571Sdim   is the original relocation, which is now being transformed into a
1181214571Sdim   dynamic relocation.  The ADDENDP is adjusted if necessary; the
1182214571Sdim   caller should store the result in place of the original addend.  */
1183214571Sdim
1184214571Sdimstatic bfd_boolean
1185214571Sdimscore_elf_create_dynamic_relocation (bfd *output_bfd,
1186214571Sdim				     struct bfd_link_info *info,
1187214571Sdim				     const Elf_Internal_Rela *rel,
1188214571Sdim				     struct score_elf_link_hash_entry *h,
1189214571Sdim				     bfd_vma symbol,
1190214571Sdim				     bfd_vma *addendp, asection *input_section)
1191214571Sdim{
1192214571Sdim  Elf_Internal_Rela outrel[3];
1193214571Sdim  asection *sreloc;
1194214571Sdim  bfd *dynobj;
1195214571Sdim  int r_type;
1196214571Sdim  long indx;
1197214571Sdim  bfd_boolean defined_p;
1198214571Sdim
1199214571Sdim  r_type = ELF32_R_TYPE (rel->r_info);
1200214571Sdim  dynobj = elf_hash_table (info)->dynobj;
1201214571Sdim  sreloc = score_elf_rel_dyn_section (dynobj, FALSE);
1202214571Sdim  BFD_ASSERT (sreloc != NULL);
1203214571Sdim  BFD_ASSERT (sreloc->contents != NULL);
1204214571Sdim  BFD_ASSERT (sreloc->reloc_count * SCORE_ELF_REL_SIZE (output_bfd) < sreloc->size);
1205214571Sdim
1206214571Sdim  outrel[0].r_offset =
1207214571Sdim    _bfd_elf_section_offset (output_bfd, info, input_section, rel[0].r_offset);
1208214571Sdim  outrel[1].r_offset =
1209214571Sdim    _bfd_elf_section_offset (output_bfd, info, input_section, rel[1].r_offset);
1210214571Sdim  outrel[2].r_offset =
1211214571Sdim    _bfd_elf_section_offset (output_bfd, info, input_section, rel[2].r_offset);
1212214571Sdim
1213214571Sdim  if (outrel[0].r_offset == MINUS_ONE)
1214214571Sdim    /* The relocation field has been deleted.  */
1215214571Sdim    return TRUE;
1216214571Sdim
1217214571Sdim  if (outrel[0].r_offset == MINUS_TWO)
1218214571Sdim    {
1219214571Sdim      /* The relocation field has been converted into a relative value of
1220214571Sdim	 some sort.  Functions like _bfd_elf_write_section_eh_frame expect
1221214571Sdim	 the field to be fully relocated, so add in the symbol's value.  */
1222214571Sdim      *addendp += symbol;
1223214571Sdim      return TRUE;
1224214571Sdim    }
1225214571Sdim
1226214571Sdim  /* We must now calculate the dynamic symbol table index to use
1227214571Sdim     in the relocation.  */
1228214571Sdim  if (h != NULL
1229214571Sdim      && (! info->symbolic || !h->root.def_regular)
1230214571Sdim      /* h->root.dynindx may be -1 if this symbol was marked to
1231214571Sdim	 become local.  */
1232214571Sdim      && h->root.dynindx != -1)
1233214571Sdim    {
1234214571Sdim      indx = h->root.dynindx;
1235214571Sdim	/* ??? glibc's ld.so just adds the final GOT entry to the
1236214571Sdim	   relocation field.  It therefore treats relocs against
1237214571Sdim	   defined symbols in the same way as relocs against
1238214571Sdim	   undefined symbols.  */
1239214571Sdim      defined_p = FALSE;
1240214571Sdim    }
1241214571Sdim  else
1242214571Sdim    {
1243214571Sdim      indx = 0;
1244214571Sdim      defined_p = TRUE;
1245214571Sdim    }
1246214571Sdim
1247214571Sdim  /* If the relocation was previously an absolute relocation and
1248214571Sdim     this symbol will not be referred to by the relocation, we must
1249214571Sdim     adjust it by the value we give it in the dynamic symbol table.
1250214571Sdim     Otherwise leave the job up to the dynamic linker.  */
1251214571Sdim  if (defined_p && r_type != R_SCORE_REL32)
1252214571Sdim    *addendp += symbol;
1253214571Sdim
1254214571Sdim  /* The relocation is always an REL32 relocation because we don't
1255214571Sdim     know where the shared library will wind up at load-time.  */
1256214571Sdim  outrel[0].r_info = ELF32_R_INFO ((unsigned long) indx, R_SCORE_REL32);
1257214571Sdim
1258214571Sdim  /* For strict adherence to the ABI specification, we should
1259214571Sdim     generate a R_SCORE_64 relocation record by itself before the
1260214571Sdim     _REL32/_64 record as well, such that the addend is read in as
1261214571Sdim     a 64-bit value (REL32 is a 32-bit relocation, after all).
1262214571Sdim     However, since none of the existing ELF64 SCORE dynamic
1263214571Sdim     loaders seems to care, we don't waste space with these
1264214571Sdim     artificial relocations.  If this turns out to not be true,
1265214571Sdim     score_elf_allocate_dynamic_relocations() should be tweaked so
1266214571Sdim     as to make room for a pair of dynamic relocations per
1267214571Sdim     invocation if ABI_64_P, and here we should generate an
1268214571Sdim     additional relocation record with R_SCORE_64 by itself for a
1269214571Sdim     NULL symbol before this relocation record.  */
1270214571Sdim  outrel[1].r_info = ELF32_R_INFO (0, R_SCORE_NONE);
1271214571Sdim  outrel[2].r_info = ELF32_R_INFO (0, R_SCORE_NONE);
1272214571Sdim
1273214571Sdim  /* Adjust the output offset of the relocation to reference the
1274214571Sdim     correct location in the output file.  */
1275214571Sdim  outrel[0].r_offset += (input_section->output_section->vma
1276214571Sdim			 + input_section->output_offset);
1277214571Sdim  outrel[1].r_offset += (input_section->output_section->vma
1278214571Sdim			 + input_section->output_offset);
1279214571Sdim  outrel[2].r_offset += (input_section->output_section->vma
1280214571Sdim			 + input_section->output_offset);
1281214571Sdim
1282214571Sdim  /* Put the relocation back out.  We have to use the special
1283214571Sdim     relocation outputter in the 64-bit case since the 64-bit
1284214571Sdim     relocation format is non-standard.  */
1285214571Sdim  bfd_elf32_swap_reloc_out
1286214571Sdim      (output_bfd, &outrel[0],
1287214571Sdim       (sreloc->contents + sreloc->reloc_count * sizeof (Elf32_External_Rel)));
1288214571Sdim
1289214571Sdim  /* We've now added another relocation.  */
1290214571Sdim  ++sreloc->reloc_count;
1291214571Sdim
1292214571Sdim  /* Make sure the output section is writable.  The dynamic linker
1293214571Sdim     will be writing to it.  */
1294214571Sdim  elf_section_data (input_section->output_section)->this_hdr.sh_flags |= SHF_WRITE;
1295214571Sdim
1296214571Sdim  return TRUE;
1297214571Sdim}
1298214571Sdim
1299214571Sdimstatic bfd_boolean
1300214571Sdimscore_elf_create_got_section (bfd *abfd,
1301214571Sdim                              struct bfd_link_info *info,
1302214571Sdim			      bfd_boolean maybe_exclude)
1303214571Sdim{
1304214571Sdim  flagword flags;
1305214571Sdim  asection *s;
1306214571Sdim  struct elf_link_hash_entry *h;
1307214571Sdim  struct bfd_link_hash_entry *bh;
1308214571Sdim  struct score_got_info *g;
1309214571Sdim  bfd_size_type amt;
1310214571Sdim
1311214571Sdim  /* This function may be called more than once.  */
1312214571Sdim  s = score_elf_got_section (abfd, TRUE);
1313214571Sdim  if (s)
1314214571Sdim    {
1315214571Sdim      if (! maybe_exclude)
1316214571Sdim	s->flags &= ~SEC_EXCLUDE;
1317214571Sdim      return TRUE;
1318214571Sdim    }
1319214571Sdim
1320214571Sdim  flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
1321214571Sdim
1322214571Sdim  if (maybe_exclude)
1323214571Sdim    flags |= SEC_EXCLUDE;
1324214571Sdim
1325214571Sdim  /* We have to use an alignment of 2**4 here because this is hardcoded
1326214571Sdim     in the function stub generation and in the linker script.  */
1327214571Sdim  s = bfd_make_section_with_flags (abfd, ".got", flags);
1328214571Sdim   if (s == NULL
1329214571Sdim      || ! bfd_set_section_alignment (abfd, s, 4))
1330214571Sdim    return FALSE;
1331214571Sdim
1332214571Sdim  /* Define the symbol _GLOBAL_OFFSET_TABLE_.  We don't do this in the
1333214571Sdim     linker script because we don't want to define the symbol if we
1334214571Sdim     are not creating a global offset table.  */
1335214571Sdim  bh = NULL;
1336214571Sdim  if (! (_bfd_generic_link_add_one_symbol
1337214571Sdim	 (info, abfd, "_GLOBAL_OFFSET_TABLE_", BSF_GLOBAL, s,
1338214571Sdim	  0, NULL, FALSE, get_elf_backend_data (abfd)->collect, &bh)))
1339214571Sdim    return FALSE;
1340214571Sdim
1341214571Sdim  h = (struct elf_link_hash_entry *) bh;
1342214571Sdim  h->non_elf = 0;
1343214571Sdim  h->def_regular = 1;
1344214571Sdim  h->type = STT_OBJECT;
1345214571Sdim
1346214571Sdim  if (info->shared && ! bfd_elf_link_record_dynamic_symbol (info, h))
1347214571Sdim    return FALSE;
1348214571Sdim
1349214571Sdim  amt = sizeof (struct score_got_info);
1350214571Sdim  g = bfd_alloc (abfd, amt);
1351214571Sdim  if (g == NULL)
1352214571Sdim    return FALSE;
1353214571Sdim
1354214571Sdim  g->global_gotsym = NULL;
1355214571Sdim  g->global_gotno = 0;
1356214571Sdim
1357214571Sdim  g->local_gotno = SCORE_RESERVED_GOTNO;
1358214571Sdim  g->assigned_gotno = SCORE_RESERVED_GOTNO;
1359214571Sdim  g->next = NULL;
1360214571Sdim
1361214571Sdim  g->got_entries = htab_try_create (1, score_elf_got_entry_hash,
1362214571Sdim				    score_elf_got_entry_eq, NULL);
1363214571Sdim  if (g->got_entries == NULL)
1364214571Sdim    return FALSE;
1365214571Sdim  score_elf_section_data (s)->u.got_info = g;
1366214571Sdim  score_elf_section_data (s)->elf.this_hdr.sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_SCORE_GPREL;
1367214571Sdim
1368214571Sdim  return TRUE;
1369214571Sdim}
1370214571Sdim
1371214571Sdim/* Calculate the %high function.  */
1372214571Sdim
1373214571Sdimstatic bfd_vma
1374214571Sdimscore_elf_high (bfd_vma value)
1375214571Sdim{
1376214571Sdim  return ((value + (bfd_vma) 0x8000) >> 16) & 0xffff;
1377214571Sdim}
1378214571Sdim
1379214571Sdim/* Create a local GOT entry for VALUE.  Return the index of the entry,
1380214571Sdim   or -1 if it could not be created.  */
1381214571Sdim
1382214571Sdimstatic struct score_got_entry *
1383214571Sdimscore_elf_create_local_got_entry (bfd *abfd,
1384214571Sdim                                  bfd *ibfd ATTRIBUTE_UNUSED,
1385214571Sdim				  struct score_got_info *gg,
1386214571Sdim				  asection *sgot, bfd_vma value,
1387214571Sdim				  unsigned long r_symndx ATTRIBUTE_UNUSED,
1388214571Sdim				  struct score_elf_link_hash_entry *h ATTRIBUTE_UNUSED,
1389214571Sdim				  int r_type ATTRIBUTE_UNUSED)
1390214571Sdim{
1391214571Sdim  struct score_got_entry entry, **loc;
1392214571Sdim  struct score_got_info *g;
1393214571Sdim
1394214571Sdim  entry.abfd = NULL;
1395214571Sdim  entry.symndx = -1;
1396214571Sdim  entry.d.address = value;
1397214571Sdim
1398214571Sdim  g = gg;
1399214571Sdim  loc = (struct score_got_entry **) htab_find_slot (g->got_entries, &entry, INSERT);
1400214571Sdim  if (*loc)
1401214571Sdim    return *loc;
1402214571Sdim
1403214571Sdim  entry.gotidx = SCORE_ELF_GOT_SIZE (abfd) * g->assigned_gotno++;
1404214571Sdim
1405214571Sdim  *loc = bfd_alloc (abfd, sizeof entry);
1406214571Sdim
1407214571Sdim  if (! *loc)
1408214571Sdim    return NULL;
1409214571Sdim
1410214571Sdim  memcpy (*loc, &entry, sizeof entry);
1411214571Sdim
1412214571Sdim  if (g->assigned_gotno >= g->local_gotno)
1413214571Sdim    {
1414214571Sdim      (*loc)->gotidx = -1;
1415214571Sdim      /* We didn't allocate enough space in the GOT.  */
1416214571Sdim      (*_bfd_error_handler)
1417214571Sdim	(_("not enough GOT space for local GOT entries"));
1418214571Sdim      bfd_set_error (bfd_error_bad_value);
1419214571Sdim      return NULL;
1420214571Sdim    }
1421214571Sdim
1422214571Sdim  bfd_put_32 (abfd, value, (sgot->contents + entry.gotidx));
1423214571Sdim
1424214571Sdim  return *loc;
1425214571Sdim}
1426214571Sdim
1427214571Sdim/* Find a GOT entry whose higher-order 16 bits are the same as those
1428214571Sdim   for value.  Return the index into the GOT for this entry.  */
1429214571Sdim
1430214571Sdimstatic bfd_vma
1431214571Sdimscore_elf_got16_entry (bfd *abfd, bfd *ibfd, struct bfd_link_info *info,
1432214571Sdim		      bfd_vma value, bfd_boolean external)
1433214571Sdim{
1434214571Sdim  asection *sgot;
1435214571Sdim  struct score_got_info *g;
1436214571Sdim  struct score_got_entry *entry;
1437214571Sdim
1438214571Sdim  if (!external)
1439214571Sdim    {
1440214571Sdim      /* Although the ABI says that it is "the high-order 16 bits" that we
1441214571Sdim	 want, it is really the %high value.  The complete value is
1442214571Sdim	 calculated with a `addiu' of a LO16 relocation, just as with a
1443214571Sdim	 HI16/LO16 pair.  */
1444214571Sdim      value = score_elf_high (value) << 16;
1445214571Sdim    }
1446214571Sdim
1447214571Sdim  g = score_elf_got_info (elf_hash_table (info)->dynobj, &sgot);
1448214571Sdim
1449214571Sdim  entry = score_elf_create_local_got_entry (abfd, ibfd, g, sgot, value, 0, NULL,
1450214571Sdim					    R_SCORE_GOT15);
1451214571Sdim  if (entry)
1452214571Sdim    return entry->gotidx;
1453214571Sdim  else
1454214571Sdim    return MINUS_ONE;
1455214571Sdim}
1456214571Sdim
1457214571Sdimstatic void
1458214571Sdim_bfd_score_elf_hide_symbol (struct bfd_link_info *info,
1459214571Sdim			    struct elf_link_hash_entry *entry,
1460214571Sdim			    bfd_boolean force_local)
1461214571Sdim{
1462214571Sdim  bfd *dynobj;
1463214571Sdim  asection *got;
1464214571Sdim  struct score_got_info *g;
1465214571Sdim  struct score_elf_link_hash_entry *h;
1466214571Sdim
1467214571Sdim  h = (struct score_elf_link_hash_entry *) entry;
1468214571Sdim  if (h->forced_local)
1469214571Sdim    return;
1470214571Sdim  h->forced_local = TRUE;
1471214571Sdim
1472214571Sdim  dynobj = elf_hash_table (info)->dynobj;
1473214571Sdim  if (dynobj != NULL && force_local)
1474214571Sdim    {
1475214571Sdim      got = score_elf_got_section (dynobj, FALSE);
1476214571Sdim      if (got == NULL)
1477214571Sdim	return;
1478214571Sdim      g = score_elf_section_data (got)->u.got_info;
1479214571Sdim
1480214571Sdim      if (g->next)
1481214571Sdim	{
1482214571Sdim	  struct score_got_entry e;
1483214571Sdim	  struct score_got_info *gg = g;
1484214571Sdim
1485214571Sdim	  /* Since we're turning what used to be a global symbol into a
1486214571Sdim	     local one, bump up the number of local entries of each GOT
1487214571Sdim	     that had an entry for it.  This will automatically decrease
1488214571Sdim	     the number of global entries, since global_gotno is actually
1489214571Sdim	     the upper limit of global entries.  */
1490214571Sdim	  e.abfd = dynobj;
1491214571Sdim	  e.symndx = -1;
1492214571Sdim	  e.d.h = h;
1493214571Sdim
1494214571Sdim	  for (g = g->next; g != gg; g = g->next)
1495214571Sdim	    if (htab_find (g->got_entries, &e))
1496214571Sdim	      {
1497214571Sdim		BFD_ASSERT (g->global_gotno > 0);
1498214571Sdim		g->local_gotno++;
1499214571Sdim		g->global_gotno--;
1500214571Sdim	      }
1501214571Sdim
1502214571Sdim	  /* If this was a global symbol forced into the primary GOT, we
1503214571Sdim	     no longer need an entry for it.  We can't release the entry
1504214571Sdim	     at this point, but we must at least stop counting it as one
1505214571Sdim	     of the symbols that required a forced got entry.  */
1506214571Sdim	  if (h->root.got.offset == 2)
1507214571Sdim	    {
1508214571Sdim	      BFD_ASSERT (gg->assigned_gotno > 0);
1509214571Sdim	      gg->assigned_gotno--;
1510214571Sdim	    }
1511214571Sdim	}
1512214571Sdim      else if (g->global_gotno == 0 && g->global_gotsym == NULL)
1513214571Sdim	/* If we haven't got through GOT allocation yet, just bump up the
1514214571Sdim	      number of local entries, as this symbol won't be counted as
1515214571Sdim	      global.  */
1516214571Sdim	g->local_gotno++;
1517214571Sdim      else if (h->root.got.offset == 1)
1518214571Sdim	{
1519214571Sdim	  /* If we're past non-multi-GOT allocation and this symbol had
1520214571Sdim	          been marked for a global got entry, give it a local entry
1521214571Sdim		  instead.  */
1522214571Sdim	  BFD_ASSERT (g->global_gotno > 0);
1523214571Sdim	  g->local_gotno++;
1524214571Sdim	  g->global_gotno--;
1525214571Sdim	}
1526214571Sdim    }
1527214571Sdim
1528214571Sdim  _bfd_elf_link_hash_hide_symbol (info, &h->root, force_local);
1529214571Sdim}
1530214571Sdim
1531214571Sdim/* If H is a symbol that needs a global GOT entry, but has a dynamic
1532214571Sdim   symbol table index lower than any we've seen to date, record it for
1533214571Sdim   posterity.  */
1534214571Sdim
1535214571Sdimstatic bfd_boolean
1536214571Sdimscore_elf_record_global_got_symbol (struct elf_link_hash_entry *h,
1537214571Sdim	 			    bfd *abfd,
1538214571Sdim                                    struct bfd_link_info *info,
1539214571Sdim				    struct score_got_info *g)
1540214571Sdim{
1541214571Sdim  struct score_got_entry entry, **loc;
1542214571Sdim
1543214571Sdim  /* A global symbol in the GOT must also be in the dynamic symbol table.  */
1544214571Sdim  if (h->dynindx == -1)
1545214571Sdim    {
1546214571Sdim      switch (ELF_ST_VISIBILITY (h->other))
1547214571Sdim	{
1548214571Sdim	case STV_INTERNAL:
1549214571Sdim	case STV_HIDDEN:
1550214571Sdim	  _bfd_score_elf_hide_symbol (info, h, TRUE);
1551214571Sdim	  break;
1552214571Sdim	}
1553214571Sdim      if (!bfd_elf_link_record_dynamic_symbol (info, h))
1554214571Sdim	return FALSE;
1555214571Sdim    }
1556214571Sdim
1557214571Sdim  entry.abfd = abfd;
1558214571Sdim  entry.symndx = -1;
1559214571Sdim  entry.d.h = (struct score_elf_link_hash_entry *)h;
1560214571Sdim
1561214571Sdim  loc = (struct score_got_entry **)htab_find_slot (g->got_entries, &entry, INSERT);
1562214571Sdim
1563214571Sdim  /* If we've already marked this entry as needing GOT space, we don't
1564214571Sdim     need to do it again.  */
1565214571Sdim  if (*loc)
1566214571Sdim    return TRUE;
1567214571Sdim
1568214571Sdim  *loc = bfd_alloc (abfd, sizeof entry);
1569214571Sdim  if (! *loc)
1570214571Sdim    return FALSE;
1571214571Sdim
1572214571Sdim  entry.gotidx = -1;
1573214571Sdim
1574214571Sdim  memcpy (*loc, &entry, sizeof (entry));
1575214571Sdim
1576214571Sdim  if (h->got.offset != MINUS_ONE)
1577214571Sdim    return TRUE;
1578214571Sdim
1579214571Sdim  /* By setting this to a value other than -1, we are indicating that
1580214571Sdim     there needs to be a GOT entry for H.  Avoid using zero, as the
1581214571Sdim     generic ELF copy_indirect_symbol tests for <= 0.  */
1582214571Sdim  h->got.offset = 1;
1583214571Sdim
1584214571Sdim  return TRUE;
1585214571Sdim}
1586214571Sdim
1587214571Sdim/* Reserve space in G for a GOT entry containing the value of symbol
1588214571Sdim   SYMNDX in input bfd ABDF, plus ADDEND.  */
1589214571Sdim
1590214571Sdimstatic bfd_boolean
1591214571Sdimscore_elf_record_local_got_symbol (bfd *abfd,
1592214571Sdim                                   long symndx,
1593214571Sdim                                   bfd_vma addend,
1594214571Sdim	  			   struct score_got_info *g)
1595214571Sdim{
1596214571Sdim  struct score_got_entry entry, **loc;
1597214571Sdim
1598214571Sdim  entry.abfd = abfd;
1599214571Sdim  entry.symndx = symndx;
1600214571Sdim  entry.d.addend = addend;
1601214571Sdim  loc = (struct score_got_entry **)htab_find_slot (g->got_entries, &entry, INSERT);
1602214571Sdim
1603214571Sdim  if (*loc)
1604214571Sdim    return TRUE;
1605214571Sdim
1606214571Sdim  entry.gotidx = g->local_gotno++;
1607214571Sdim
1608214571Sdim  *loc = bfd_alloc (abfd, sizeof(entry));
1609214571Sdim  if (! *loc)
1610214571Sdim    return FALSE;
1611214571Sdim
1612214571Sdim  memcpy (*loc, &entry, sizeof (entry));
1613214571Sdim
1614214571Sdim  return TRUE;
1615214571Sdim}
1616214571Sdim
1617214571Sdim/* Returns the GOT offset at which the indicated address can be found.
1618214571Sdim   If there is not yet a GOT entry for this value, create one.
1619214571Sdim   Returns -1 if no satisfactory GOT offset can be found.  */
1620214571Sdim
1621214571Sdimstatic bfd_vma
1622214571Sdimscore_elf_local_got_index (bfd *abfd, bfd *ibfd, struct bfd_link_info *info,
1623214571Sdim			  bfd_vma value, unsigned long r_symndx,
1624214571Sdim			  struct score_elf_link_hash_entry *h, int r_type)
1625214571Sdim{
1626214571Sdim  asection *sgot;
1627214571Sdim  struct score_got_info *g;
1628214571Sdim  struct score_got_entry *entry;
1629214571Sdim
1630214571Sdim  g = score_elf_got_info (elf_hash_table (info)->dynobj, &sgot);
1631214571Sdim
1632214571Sdim  entry = score_elf_create_local_got_entry (abfd, ibfd, g, sgot, value,
1633214571Sdim		 			    r_symndx, h, r_type);
1634214571Sdim  if (!entry)
1635214571Sdim    return MINUS_ONE;
1636214571Sdim
1637214571Sdim  else
1638214571Sdim    return entry->gotidx;
1639214571Sdim}
1640214571Sdim
1641214571Sdim/* Returns the GOT index for the global symbol indicated by H.  */
1642214571Sdim
1643214571Sdimstatic bfd_vma
1644214571Sdimscore_elf_global_got_index (bfd *abfd, struct elf_link_hash_entry *h)
1645214571Sdim{
1646214571Sdim  bfd_vma index;
1647214571Sdim  asection *sgot;
1648214571Sdim  struct score_got_info *g;
1649214571Sdim  long global_got_dynindx = 0;
1650214571Sdim
1651214571Sdim  g = score_elf_got_info (abfd, &sgot);
1652214571Sdim  if (g->global_gotsym != NULL)
1653214571Sdim    global_got_dynindx = g->global_gotsym->dynindx;
1654214571Sdim
1655214571Sdim  /* Once we determine the global GOT entry with the lowest dynamic
1656214571Sdim     symbol table index, we must put all dynamic symbols with greater
1657214571Sdim     indices into the GOT.  That makes it easy to calculate the GOT
1658214571Sdim     offset.  */
1659214571Sdim  BFD_ASSERT (h->dynindx >= global_got_dynindx);
1660214571Sdim  index = ((h->dynindx - global_got_dynindx + g->local_gotno) * SCORE_ELF_GOT_SIZE (abfd));
1661214571Sdim  BFD_ASSERT (index < sgot->size);
1662214571Sdim
1663214571Sdim  return index;
1664214571Sdim}
1665214571Sdim
1666214571Sdim/* Returns the offset for the entry at the INDEXth position in the GOT.  */
1667214571Sdim
1668214571Sdimstatic bfd_vma
1669214571Sdimscore_elf_got_offset_from_index (bfd *dynobj, bfd *output_bfd,
1670214571Sdim	 			 bfd *input_bfd ATTRIBUTE_UNUSED, bfd_vma index)
1671214571Sdim{
1672214571Sdim  asection *sgot;
1673214571Sdim  bfd_vma gp;
1674214571Sdim  struct score_got_info *g;
1675214571Sdim
1676214571Sdim  g = score_elf_got_info (dynobj, &sgot);
1677214571Sdim  gp = _bfd_get_gp_value (output_bfd);
1678214571Sdim
1679214571Sdim  return sgot->output_section->vma + sgot->output_offset + index - gp;
1680214571Sdim}
1681214571Sdim
1682214571Sdim/* Follow indirect and warning hash entries so that each got entry
1683214571Sdim   points to the final symbol definition.  P must point to a pointer
1684214571Sdim   to the hash table we're traversing.  Since this traversal may
1685214571Sdim   modify the hash table, we set this pointer to NULL to indicate
1686214571Sdim   we've made a potentially-destructive change to the hash table, so
1687214571Sdim   the traversal must be restarted.  */
1688214571Sdimstatic int
1689214571Sdimscore_elf_resolve_final_got_entry (void **entryp, void *p)
1690214571Sdim{
1691214571Sdim  struct score_got_entry *entry = (struct score_got_entry *)*entryp;
1692214571Sdim  htab_t got_entries = *(htab_t *)p;
1693214571Sdim
1694214571Sdim  if (entry->abfd != NULL && entry->symndx == -1)
1695214571Sdim    {
1696214571Sdim      struct score_elf_link_hash_entry *h = entry->d.h;
1697214571Sdim
1698214571Sdim      while (h->root.root.type == bfd_link_hash_indirect
1699214571Sdim	     || h->root.root.type == bfd_link_hash_warning)
1700214571Sdim	h = (struct score_elf_link_hash_entry *) h->root.root.u.i.link;
1701214571Sdim
1702214571Sdim      if (entry->d.h == h)
1703214571Sdim	return 1;
1704214571Sdim
1705214571Sdim      entry->d.h = h;
1706214571Sdim
1707214571Sdim      /* If we can't find this entry with the new bfd hash, re-insert
1708214571Sdim	 it, and get the traversal restarted.  */
1709214571Sdim      if (! htab_find (got_entries, entry))
1710214571Sdim	{
1711214571Sdim	  htab_clear_slot (got_entries, entryp);
1712214571Sdim	  entryp = htab_find_slot (got_entries, entry, INSERT);
1713214571Sdim	  if (! *entryp)
1714214571Sdim	    *entryp = entry;
1715214571Sdim	  /* Abort the traversal, since the whole table may have
1716214571Sdim	     moved, and leave it up to the parent to restart the
1717214571Sdim	     process.  */
1718214571Sdim	  *(htab_t *)p = NULL;
1719214571Sdim	  return 0;
1720214571Sdim	}
1721214571Sdim      /* We might want to decrement the global_gotno count, but it's
1722214571Sdim	 either too early or too late for that at this point.  */
1723214571Sdim    }
1724214571Sdim
1725214571Sdim  return 1;
1726214571Sdim}
1727214571Sdim
1728214571Sdim/* Turn indirect got entries in a got_entries table into their final locations.  */
1729214571Sdimstatic void
1730214571Sdimscore_elf_resolve_final_got_entries (struct score_got_info *g)
1731214571Sdim{
1732214571Sdim  htab_t got_entries;
1733214571Sdim
1734214571Sdim  do
1735214571Sdim    {
1736214571Sdim      got_entries = g->got_entries;
1737214571Sdim
1738214571Sdim      htab_traverse (got_entries,
1739214571Sdim		     score_elf_resolve_final_got_entry,
1740214571Sdim		     &got_entries);
1741214571Sdim    }
1742214571Sdim  while (got_entries == NULL);
1743214571Sdim}
1744214571Sdim
1745214571Sdim/* Add INCREMENT to the reloc (of type HOWTO) at ADDRESS. for -r  */
1746214571Sdim
1747214571Sdimstatic void
1748214571Sdimscore_elf_add_to_rel (bfd *abfd,
1749214571Sdim		      bfd_byte *address,
1750214571Sdim		      reloc_howto_type *howto,
1751214571Sdim		      bfd_signed_vma increment)
1752214571Sdim{
1753214571Sdim  bfd_signed_vma addend;
1754214571Sdim  bfd_vma contents;
1755214571Sdim  unsigned long offset;
1756214571Sdim  unsigned long r_type = howto->type;
1757214571Sdim  unsigned long hi16_addend, hi16_offset, hi16_value, uvalue;
1758214571Sdim
1759214571Sdim  contents = bfd_get_32 (abfd, address);
1760214571Sdim  /* Get the (signed) value from the instruction.  */
1761214571Sdim  addend = contents & howto->src_mask;
1762214571Sdim  if (addend & ((howto->src_mask + 1) >> 1))
1763214571Sdim    {
1764214571Sdim      bfd_signed_vma mask;
1765214571Sdim
1766214571Sdim      mask = -1;
1767214571Sdim      mask &= ~howto->src_mask;
1768214571Sdim      addend |= mask;
1769214571Sdim    }
1770214571Sdim  /* Add in the increment, (which is a byte value).  */
1771214571Sdim  switch (r_type)
1772214571Sdim    {
1773214571Sdim    case R_SCORE_PC19:
1774214571Sdim      offset =
1775214571Sdim        (((contents & howto->src_mask) & 0x3ff0000) >> 6) | ((contents & howto->src_mask) & 0x3ff);
1776214571Sdim      offset += increment;
1777214571Sdim      contents =
1778214571Sdim        (contents & ~howto->
1779214571Sdim         src_mask) | (((offset << 6) & howto->src_mask) & 0x3ff0000) | (offset & 0x3ff);
1780214571Sdim      bfd_put_32 (abfd, contents, address);
1781214571Sdim      break;
1782214571Sdim    case R_SCORE_HI16:
1783214571Sdim      break;
1784214571Sdim    case R_SCORE_LO16:
1785214571Sdim      hi16_addend = bfd_get_32 (abfd, address - 4);
1786214571Sdim      hi16_offset = ((((hi16_addend >> 16) & 0x3) << 15) | (hi16_addend & 0x7fff)) >> 1;
1787214571Sdim      offset = ((((contents >> 16) & 0x3) << 15) | (contents & 0x7fff)) >> 1;
1788214571Sdim      offset = (hi16_offset << 16) | (offset & 0xffff);
1789214571Sdim      uvalue = increment + offset;
1790214571Sdim      hi16_offset = (uvalue >> 16) << 1;
1791214571Sdim      hi16_value = (hi16_addend & (~(howto->dst_mask)))
1792214571Sdim        | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000);
1793214571Sdim      bfd_put_32 (abfd, hi16_value, address - 4);
1794214571Sdim      offset = (uvalue & 0xffff) << 1;
1795214571Sdim      contents = (contents & (~(howto->dst_mask))) | (offset & 0x7fff) | ((offset << 1) & 0x30000);
1796214571Sdim      bfd_put_32 (abfd, contents, address);
1797214571Sdim      break;
1798214571Sdim    case R_SCORE_24:
1799214571Sdim      offset =
1800214571Sdim        (((contents & howto->src_mask) >> 1) & 0x1ff8000) | ((contents & howto->src_mask) & 0x7fff);
1801214571Sdim      offset += increment;
1802214571Sdim      contents =
1803214571Sdim        (contents & ~howto->
1804214571Sdim         src_mask) | (((offset << 1) & howto->src_mask) & 0x3ff0000) | (offset & 0x7fff);
1805214571Sdim      bfd_put_32 (abfd, contents, address);
1806214571Sdim      break;
1807214571Sdim    case R_SCORE16_11:
1808214571Sdim
1809214571Sdim      contents = bfd_get_16 (abfd, address);
1810214571Sdim      offset = contents & howto->src_mask;
1811214571Sdim      offset += increment;
1812214571Sdim      contents = (contents & ~howto->src_mask) | (offset & howto->src_mask);
1813214571Sdim      bfd_put_16 (abfd, contents, address);
1814214571Sdim
1815214571Sdim      break;
1816214571Sdim    case R_SCORE16_PC8:
1817214571Sdim
1818214571Sdim      contents = bfd_get_16 (abfd, address);
1819214571Sdim      offset = (contents & howto->src_mask) + ((increment >> 1) & 0xff);
1820214571Sdim      contents = (contents & (~howto->src_mask)) | (offset & howto->src_mask);
1821214571Sdim      bfd_put_16 (abfd, contents, address);
1822214571Sdim
1823214571Sdim      break;
1824214571Sdim    default:
1825214571Sdim      addend += increment;
1826214571Sdim      contents = (contents & ~howto->dst_mask) | (addend & howto->dst_mask);
1827214571Sdim      bfd_put_32 (abfd, contents, address);
1828214571Sdim      break;
1829214571Sdim    }
1830214571Sdim}
1831214571Sdim
1832214571Sdim/* Perform a relocation as part of a final link.  */
1833214571Sdim
1834214571Sdimstatic bfd_reloc_status_type
1835214571Sdimscore_elf_final_link_relocate (reloc_howto_type *howto,
1836214571Sdim			       bfd *input_bfd,
1837214571Sdim			       bfd *output_bfd,
1838214571Sdim			       asection *input_section,
1839214571Sdim			       bfd_byte *contents,
1840214571Sdim			       Elf_Internal_Rela *rel,
1841214571Sdim			       Elf_Internal_Rela *relocs,
1842214571Sdim			       bfd_vma symbol,
1843214571Sdim			       struct bfd_link_info *info,
1844214571Sdim			       const char *sym_name ATTRIBUTE_UNUSED,
1845214571Sdim			       int sym_flags ATTRIBUTE_UNUSED,
1846214571Sdim			       struct score_elf_link_hash_entry *h,
1847214571Sdim	                       asection **local_sections,
1848214571Sdim                               bfd_boolean gp_disp_p)
1849214571Sdim{
1850214571Sdim  unsigned long r_type;
1851214571Sdim  unsigned long r_symndx;
1852214571Sdim  bfd_byte *hit_data = contents + rel->r_offset;
1853214571Sdim  bfd_vma addend;
1854214571Sdim  /* The final GP value to be used for the relocatable, executable, or
1855214571Sdim     shared object file being produced.  */
1856214571Sdim  bfd_vma gp = MINUS_ONE;
1857214571Sdim  /* The place (section offset or address) of the storage unit being relocated.  */
1858214571Sdim  bfd_vma rel_addr;
1859214571Sdim  /* The value of GP used to create the relocatable object.  */
1860214571Sdim  bfd_vma gp0 = MINUS_ONE;
1861214571Sdim  /* The offset into the global offset table at which the address of the relocation entry
1862214571Sdim     symbol, adjusted by the addend, resides during execution.  */
1863214571Sdim  bfd_vma g = MINUS_ONE;
1864214571Sdim  /* TRUE if the symbol referred to by this relocation is a local symbol.  */
1865214571Sdim  bfd_boolean local_p;
1866214571Sdim  /* The eventual value we will relocate.  */
1867214571Sdim  bfd_vma value = symbol;
1868214571Sdim  unsigned long hi16_addend, hi16_offset, hi16_value, uvalue, offset, abs_value = 0;
1869214571Sdim
1870214571Sdim  if (elf_gp (output_bfd) == 0)
1871214571Sdim    {
1872214571Sdim      struct bfd_link_hash_entry *bh;
1873214571Sdim      asection *o;
1874214571Sdim
1875214571Sdim      bh = bfd_link_hash_lookup (info->hash, "_gp", 0, 0, 1);
1876214571Sdim      if (bh != (struct bfd_link_hash_entry *)NULL && bh->type == bfd_link_hash_defined)
1877214571Sdim        elf_gp (output_bfd) = (bh->u.def.value
1878214571Sdim                               + bh->u.def.section->output_section->vma
1879214571Sdim                               + bh->u.def.section->output_offset);
1880214571Sdim      else if (info->relocatable)
1881214571Sdim        {
1882214571Sdim          bfd_vma lo = -1;
1883214571Sdim
1884214571Sdim          /* Find the GP-relative section with the lowest offset.  */
1885214571Sdim          for (o = output_bfd->sections; o != (asection *) NULL; o = o->next)
1886214571Sdim            if (o->vma < lo)
1887214571Sdim              lo = o->vma;
1888214571Sdim          /* And calculate GP relative to that.  */
1889214571Sdim          elf_gp (output_bfd) = lo + ELF_SCORE_GP_OFFSET (input_bfd);
1890214571Sdim        }
1891214571Sdim      else
1892214571Sdim        {
1893214571Sdim          /* If the relocate_section function needs to do a reloc
1894214571Sdim             involving the GP value, it should make a reloc_dangerous
1895214571Sdim             callback to warn that GP is not defined.  */
1896214571Sdim        }
1897214571Sdim    }
1898214571Sdim
1899214571Sdim  /* Parse the relocation.  */
1900214571Sdim  r_symndx = ELF32_R_SYM (rel->r_info);
1901214571Sdim  r_type = ELF32_R_TYPE (rel->r_info);
1902214571Sdim  rel_addr = (input_section->output_section->vma + input_section->output_offset + rel->r_offset);
1903214571Sdim  local_p = score_elf_local_relocation_p (input_bfd, rel, local_sections, TRUE);
1904214571Sdim
1905214571Sdim  if (r_type == R_SCORE_GOT15)
1906214571Sdim    {
1907214571Sdim      const Elf_Internal_Rela *relend;
1908214571Sdim      const Elf_Internal_Rela *lo16_rel;
1909214571Sdim      const struct elf_backend_data *bed;
1910214571Sdim      bfd_vma lo_value = 0;
1911214571Sdim
1912214571Sdim      bed = get_elf_backend_data (output_bfd);
1913214571Sdim      relend = relocs + input_section->reloc_count * bed->s->int_rels_per_ext_rel;
1914214571Sdim      lo16_rel = score_elf_next_relocation (input_bfd, R_SCORE_GOT_LO16, rel, relend);
1915214571Sdim      if ((local_p) && (lo16_rel != NULL))
1916214571Sdim	{
1917214571Sdim	  bfd_vma tmp = 0;
1918214571Sdim	  tmp = bfd_get_32 (input_bfd, contents + lo16_rel->r_offset);
1919214571Sdim	  lo_value = (((tmp >> 16) & 0x3) << 14) | ((tmp & 0x7fff) >> 1);
1920214571Sdim	}
1921214571Sdim      addend = lo_value;
1922214571Sdim    }
1923214571Sdim  else
1924214571Sdim    {
1925214571Sdim      addend = (bfd_get_32 (input_bfd, hit_data) >> howto->bitpos) & howto->src_mask;
1926214571Sdim    }
1927214571Sdim
1928214571Sdim  /* If we haven't already determined the GOT offset, or the GP value,
1929214571Sdim     and we're going to need it, get it now.  */
1930214571Sdim  switch (r_type)
1931214571Sdim    {
1932214571Sdim    case R_SCORE_CALL15:
1933214571Sdim    case R_SCORE_GOT15:
1934214571Sdim      if (!local_p)
1935214571Sdim        {
1936214571Sdim          g = score_elf_global_got_index (elf_hash_table (info)->dynobj,
1937214571Sdim                                          (struct elf_link_hash_entry *) h);
1938214571Sdim          if ((! elf_hash_table(info)->dynamic_sections_created
1939214571Sdim               || (info->shared
1940214571Sdim                   && (info->symbolic || h->root.dynindx == -1)
1941214571Sdim                   && h->root.def_regular)))
1942214571Sdim            {
1943214571Sdim              /* This is a static link or a -Bsymbolic link.  The
1944214571Sdim                 symbol is defined locally, or was forced to be local.
1945214571Sdim                 We must initialize this entry in the GOT.  */
1946214571Sdim              bfd *tmpbfd = elf_hash_table (info)->dynobj;
1947214571Sdim              asection *sgot = score_elf_got_section (tmpbfd, FALSE);
1948214571Sdim              bfd_put_32 (tmpbfd, value, sgot->contents + g);
1949214571Sdim            }
1950214571Sdim        }
1951214571Sdim      else if (r_type == R_SCORE_GOT15 || r_type == R_SCORE_CALL15)
1952214571Sdim        {
1953214571Sdim	  /* There's no need to create a local GOT entry here; the
1954214571Sdim	     calculation for a local GOT15 entry does not involve G.  */
1955214571Sdim	  ;
1956214571Sdim	}
1957214571Sdim      else
1958214571Sdim        {
1959214571Sdim	  g = score_elf_local_got_index (output_bfd, input_bfd, info,
1960214571Sdim                                         symbol + addend, r_symndx, h, r_type);
1961214571Sdim  	  if (g == MINUS_ONE)
1962214571Sdim	    return bfd_reloc_outofrange;
1963214571Sdim        }
1964214571Sdim
1965214571Sdim      /* Convert GOT indices to actual offsets.  */
1966214571Sdim      g = score_elf_got_offset_from_index (elf_hash_table (info)->dynobj,
1967214571Sdim					   output_bfd, input_bfd, g);
1968214571Sdim      break;
1969214571Sdim
1970214571Sdim    case R_SCORE_HI16:
1971214571Sdim    case R_SCORE_LO16:
1972214571Sdim    case R_SCORE_GPREL32:
1973214571Sdim      gp0 = _bfd_get_gp_value (input_bfd);
1974214571Sdim      gp = _bfd_get_gp_value (output_bfd);
1975214571Sdim      break;
1976214571Sdim
1977214571Sdim    case R_SCORE_GP15:
1978214571Sdim      gp = _bfd_get_gp_value (output_bfd);
1979214571Sdim
1980214571Sdim    default:
1981214571Sdim      break;
1982214571Sdim    }
1983214571Sdim
1984214571Sdim  switch (r_type)
1985214571Sdim    {
1986214571Sdim    case R_SCORE_NONE:
1987214571Sdim      return bfd_reloc_ok;
1988214571Sdim
1989214571Sdim    case R_SCORE_ABS32:
1990214571Sdim    case R_SCORE_REL32:
1991214571Sdim      if ((info->shared
1992214571Sdim	   || (elf_hash_table (info)->dynamic_sections_created
1993214571Sdim	       && h != NULL
1994214571Sdim	       && h->root.def_dynamic
1995214571Sdim	       && !h->root.def_regular))
1996214571Sdim	   && r_symndx != 0
1997214571Sdim	   && (input_section->flags & SEC_ALLOC) != 0)
1998214571Sdim	{
1999214571Sdim	  /* If we're creating a shared library, or this relocation is against a symbol
2000214571Sdim             in a shared library, then we can't know where the symbol will end up.
2001214571Sdim             So, we create a relocation record in the output, and leave the job up
2002214571Sdim             to the dynamic linker.  */
2003214571Sdim	  value = addend;
2004214571Sdim	  if (!score_elf_create_dynamic_relocation (output_bfd, info, rel, h,
2005214571Sdim						    symbol, &value,
2006214571Sdim						    input_section))
2007214571Sdim	    return bfd_reloc_undefined;
2008214571Sdim	}
2009214571Sdim      else
2010214571Sdim	{
2011214571Sdim	  if (r_type != R_SCORE_REL32)
2012214571Sdim	    value = symbol + addend;
2013214571Sdim	  else
2014214571Sdim	    value = addend;
2015214571Sdim	}
2016214571Sdim      value &= howto->dst_mask;
2017214571Sdim      bfd_put_32 (input_bfd, value, hit_data);
2018214571Sdim      return bfd_reloc_ok;
2019214571Sdim
2020214571Sdim    case R_SCORE_ABS16:
2021214571Sdim      value += addend;
2022214571Sdim      if ((long)value > 0x7fff || (long)value < -0x8000)
2023214571Sdim        return bfd_reloc_overflow;
2024214571Sdim      bfd_put_16 (input_bfd, value, hit_data);
2025214571Sdim      return bfd_reloc_ok;
2026214571Sdim
2027214571Sdim    case R_SCORE_24:
2028214571Sdim      addend = bfd_get_32 (input_bfd, hit_data);
2029214571Sdim      offset = (((addend & howto->src_mask) >> 1) & 0x1ff8000) | ((addend & howto->src_mask) & 0x7fff);
2030214571Sdim      if ((offset & 0x1000000) != 0)
2031214571Sdim        offset |= 0xfe000000;
2032214571Sdim      value += offset;
2033214571Sdim      addend = (addend & ~howto->src_mask)
2034214571Sdim                | (((value << 1) & howto->src_mask) & 0x3ff0000) | (value & 0x7fff);
2035214571Sdim      bfd_put_32 (input_bfd, addend, hit_data);
2036214571Sdim      return bfd_reloc_ok;
2037214571Sdim
2038214571Sdim    case R_SCORE_PC19:
2039214571Sdim      addend = bfd_get_32 (input_bfd, hit_data);
2040214571Sdim      offset = (((addend & howto->src_mask) & 0x3ff0000) >> 6) | ((addend & howto->src_mask) & 0x3ff);
2041214571Sdim      if ((offset & 0x80000) != 0)
2042214571Sdim        offset |= 0xfff00000;
2043214571Sdim      abs_value = value = value - rel_addr + offset;
2044214571Sdim      /* exceed 20 bit : overflow.  */
2045214571Sdim      if ((abs_value & 0x80000000) == 0x80000000)
2046214571Sdim        abs_value = 0xffffffff - value + 1;
2047214571Sdim      if ((abs_value & 0xfff80000) != 0)
2048214571Sdim        return bfd_reloc_overflow;
2049214571Sdim      addend = (addend & ~howto->src_mask)
2050214571Sdim                | (((value << 6) & howto->src_mask) & 0x3ff0000) | (value & 0x3ff);
2051214571Sdim      bfd_put_32 (input_bfd, addend, hit_data);
2052214571Sdim      return bfd_reloc_ok;
2053214571Sdim
2054214571Sdim    case R_SCORE16_11:
2055214571Sdim      addend = bfd_get_16 (input_bfd, hit_data);
2056214571Sdim      offset = addend & howto->src_mask;
2057214571Sdim      if ((offset & 0x800) != 0)        /* Offset is negative.  */
2058214571Sdim        offset |= 0xfffff000;
2059214571Sdim      value += offset;
2060214571Sdim      addend = (addend & ~howto->src_mask) | (value & howto->src_mask);
2061214571Sdim      bfd_put_16 (input_bfd, addend, hit_data);
2062214571Sdim      return bfd_reloc_ok;
2063214571Sdim
2064214571Sdim    case R_SCORE16_PC8:
2065214571Sdim      addend = bfd_get_16 (input_bfd, hit_data);
2066214571Sdim      offset = (addend & howto->src_mask) << 1;
2067214571Sdim      if ((offset & 0x100) != 0)        /* Offset is negative.  */
2068214571Sdim        offset |= 0xfffffe00;
2069214571Sdim      abs_value = value = value - rel_addr + offset;
2070214571Sdim      /* Sign bit + exceed 9 bit.  */
2071214571Sdim      if (((value & 0xffffff00) != 0) && ((value & 0xffffff00) != 0xffffff00))
2072214571Sdim        return bfd_reloc_overflow;
2073214571Sdim      value >>= 1;
2074214571Sdim      addend = (addend & ~howto->src_mask) | (value & howto->src_mask);
2075214571Sdim      bfd_put_16 (input_bfd, addend, hit_data);
2076214571Sdim      return bfd_reloc_ok;
2077214571Sdim
2078214571Sdim    case R_SCORE_HI16:
2079214571Sdim      return bfd_reloc_ok;
2080214571Sdim
2081214571Sdim    case R_SCORE_LO16:
2082214571Sdim      hi16_addend = bfd_get_32 (input_bfd, hit_data - 4);
2083214571Sdim      hi16_offset = ((((hi16_addend >> 16) & 0x3) << 15) | (hi16_addend & 0x7fff)) >> 1;
2084214571Sdim      addend = bfd_get_32 (input_bfd, hit_data);
2085214571Sdim      offset = ((((addend >> 16) & 0x3) << 15) | (addend & 0x7fff)) >> 1;
2086214571Sdim      offset = (hi16_offset << 16) | (offset & 0xffff);
2087214571Sdim
2088214571Sdim      if (!gp_disp_p)
2089214571Sdim	uvalue = value + offset;
2090214571Sdim      else
2091214571Sdim	uvalue = offset + gp - rel_addr + 4;
2092214571Sdim
2093214571Sdim      hi16_offset = (uvalue >> 16) << 1;
2094214571Sdim      hi16_value = (hi16_addend & (~(howto->dst_mask)))
2095214571Sdim                        | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000);
2096214571Sdim      bfd_put_32 (input_bfd, hi16_value, hit_data - 4);
2097214571Sdim      offset = (uvalue & 0xffff) << 1;
2098214571Sdim      value = (addend & (~(howto->dst_mask))) | (offset & 0x7fff) | ((offset << 1) & 0x30000);
2099214571Sdim      bfd_put_32 (input_bfd, value, hit_data);
2100214571Sdim      return bfd_reloc_ok;
2101214571Sdim
2102214571Sdim    case R_SCORE_GP15:
2103214571Sdim      addend = bfd_get_32 (input_bfd, hit_data);
2104214571Sdim      offset = addend & 0x7fff;
2105214571Sdim      if ((offset & 0x4000) == 0x4000)
2106214571Sdim        offset |= 0xffffc000;
2107214571Sdim      value = value + offset - gp;
2108214571Sdim      if (((value & 0xffffc000) != 0) && ((value & 0xffffc000) != 0xffffc000))
2109214571Sdim        return bfd_reloc_overflow;
2110214571Sdim      value = (addend & ~howto->src_mask) | (value & howto->src_mask);
2111214571Sdim      bfd_put_32 (input_bfd, value, hit_data);
2112214571Sdim      return bfd_reloc_ok;
2113214571Sdim
2114214571Sdim    case R_SCORE_GOT15:
2115214571Sdim    case R_SCORE_CALL15:
2116214571Sdim      if (local_p)
2117214571Sdim	{
2118214571Sdim	  bfd_boolean forced;
2119214571Sdim
2120214571Sdim	  /* The special case is when the symbol is forced to be local.  We need the
2121214571Sdim             full address in the GOT since no R_SCORE_GOT_LO16 relocation follows.  */
2122214571Sdim	  forced = ! score_elf_local_relocation_p (input_bfd, rel,
2123214571Sdim						   local_sections, FALSE);
2124214571Sdim	  value = score_elf_got16_entry (output_bfd, input_bfd, info,
2125214571Sdim					 symbol + addend, forced);
2126214571Sdim	  if (value == MINUS_ONE)
2127214571Sdim	    return bfd_reloc_outofrange;
2128214571Sdim	  value = score_elf_got_offset_from_index (elf_hash_table (info)->dynobj,
2129214571Sdim						   output_bfd, input_bfd, value);
2130214571Sdim	}
2131214571Sdim      else
2132214571Sdim	{
2133214571Sdim	  value = g;
2134214571Sdim	}
2135214571Sdim
2136214571Sdim      if ((long) value > 0x3fff || (long) value < -0x4000)
2137214571Sdim        return bfd_reloc_overflow;
2138214571Sdim
2139214571Sdim      addend = bfd_get_32 (input_bfd, hit_data);
2140214571Sdim      value = (addend & ~howto->dst_mask) | (value & howto->dst_mask);
2141214571Sdim      bfd_put_32 (input_bfd, value, hit_data);
2142214571Sdim      return bfd_reloc_ok;
2143214571Sdim
2144214571Sdim    case R_SCORE_GPREL32:
2145214571Sdim      value = (addend + symbol - gp);
2146214571Sdim      value &= howto->dst_mask;
2147214571Sdim      bfd_put_32 (input_bfd, value, hit_data);
2148214571Sdim      return bfd_reloc_ok;
2149214571Sdim
2150214571Sdim    case R_SCORE_GOT_LO16:
2151214571Sdim      addend = bfd_get_32 (input_bfd, hit_data);
2152214571Sdim      value = (((addend >> 16) & 0x3) << 14) | ((addend & 0x7fff) >> 1);
2153214571Sdim      value += symbol;
2154214571Sdim      value = (addend & (~(howto->dst_mask))) | ((value & 0x3fff) << 1)
2155214571Sdim               | (((value >> 14) & 0x3) << 16);
2156214571Sdim
2157214571Sdim      bfd_put_32 (input_bfd, value, hit_data);
2158214571Sdim      return bfd_reloc_ok;
2159214571Sdim
2160214571Sdim    case R_SCORE_DUMMY_HI16:
2161214571Sdim      return bfd_reloc_ok;
2162214571Sdim
2163214571Sdim    case R_SCORE_GNU_VTINHERIT:
2164214571Sdim    case R_SCORE_GNU_VTENTRY:
2165214571Sdim      /* We don't do anything with these at present.  */
2166214571Sdim      return bfd_reloc_continue;
2167214571Sdim
2168214571Sdim    default:
2169214571Sdim      return bfd_reloc_notsupported;
2170214571Sdim    }
2171214571Sdim}
2172214571Sdim
2173214571Sdim/* Score backend functions.  */
2174214571Sdim
2175214571Sdimstatic void
2176214571Sdim_bfd_score_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED,
2177214571Sdim			  arelent *bfd_reloc,
2178214571Sdim			  Elf_Internal_Rela *elf_reloc)
2179214571Sdim{
2180214571Sdim  unsigned int r_type;
2181214571Sdim
2182214571Sdim  r_type = ELF32_R_TYPE (elf_reloc->r_info);
2183214571Sdim  if (r_type >= NUM_ELEM (elf32_score_howto_table))
2184214571Sdim    bfd_reloc->howto = NULL;
2185214571Sdim  else
2186214571Sdim    bfd_reloc->howto = &elf32_score_howto_table[r_type];
2187214571Sdim}
2188214571Sdim
2189214571Sdim/* Relocate an score ELF section.  */
2190214571Sdim
2191214571Sdimstatic bfd_boolean
2192214571Sdim_bfd_score_elf_relocate_section (bfd *output_bfd,
2193214571Sdim			         struct bfd_link_info *info,
2194214571Sdim			         bfd *input_bfd,
2195214571Sdim			         asection *input_section,
2196214571Sdim			         bfd_byte *contents,
2197214571Sdim			         Elf_Internal_Rela *relocs,
2198214571Sdim			         Elf_Internal_Sym *local_syms,
2199214571Sdim			         asection **local_sections)
2200214571Sdim{
2201214571Sdim  Elf_Internal_Shdr *symtab_hdr;
2202214571Sdim  struct elf_link_hash_entry **sym_hashes;
2203214571Sdim  Elf_Internal_Rela *rel;
2204214571Sdim  Elf_Internal_Rela *relend;
2205214571Sdim  const char *name;
2206214571Sdim  unsigned long offset;
2207214571Sdim  unsigned long hi16_addend, hi16_offset, hi16_value, uvalue;
2208214571Sdim  size_t extsymoff;
2209214571Sdim  bfd_boolean gp_disp_p = FALSE;
2210214571Sdim
2211214571Sdim  /* Sort dynsym.  */
2212214571Sdim  if (elf_hash_table (info)->dynamic_sections_created)
2213214571Sdim    {
2214214571Sdim      bfd_size_type dynsecsymcount = 0;
2215214571Sdim      if (info->shared)
2216214571Sdim	{
2217214571Sdim	  asection * p;
2218214571Sdim	  const struct elf_backend_data *bed = get_elf_backend_data (output_bfd);
2219214571Sdim
2220214571Sdim	  for (p = output_bfd->sections; p ; p = p->next)
2221214571Sdim	    if ((p->flags & SEC_EXCLUDE) == 0
2222214571Sdim		&& (p->flags & SEC_ALLOC) != 0
2223214571Sdim		&& !(*bed->elf_backend_omit_section_dynsym) (output_bfd, info, p))
2224214571Sdim	      ++ dynsecsymcount;
2225214571Sdim	}
2226214571Sdim
2227214571Sdim      if (!score_elf_sort_hash_table (info, dynsecsymcount + 1))
2228214571Sdim	return FALSE;
2229214571Sdim    }
2230214571Sdim
2231214571Sdim  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
2232214571Sdim  extsymoff = (elf_bad_symtab (input_bfd)) ? 0 : symtab_hdr->sh_info;
2233214571Sdim  sym_hashes = elf_sym_hashes (input_bfd);
2234214571Sdim  rel = relocs;
2235214571Sdim  relend = relocs + input_section->reloc_count;
2236214571Sdim  for (; rel < relend; rel++)
2237214571Sdim    {
2238214571Sdim      int r_type;
2239214571Sdim      reloc_howto_type *howto;
2240214571Sdim      unsigned long r_symndx;
2241214571Sdim      Elf_Internal_Sym *sym;
2242214571Sdim      asection *sec;
2243214571Sdim      struct score_elf_link_hash_entry *h;
2244214571Sdim      bfd_vma relocation = 0;
2245214571Sdim      bfd_reloc_status_type r;
2246214571Sdim      arelent bfd_reloc;
2247214571Sdim
2248214571Sdim      r_symndx = ELF32_R_SYM (rel->r_info);
2249214571Sdim      r_type = ELF32_R_TYPE (rel->r_info);
2250214571Sdim
2251214571Sdim      _bfd_score_info_to_howto (input_bfd, &bfd_reloc, (Elf_Internal_Rela *) rel);
2252214571Sdim      howto = bfd_reloc.howto;
2253214571Sdim
2254214571Sdim      h = NULL;
2255214571Sdim      sym = NULL;
2256214571Sdim      sec = NULL;
2257214571Sdim
2258214571Sdim      if (r_symndx < extsymoff)
2259214571Sdim        {
2260214571Sdim          sym = local_syms + r_symndx;
2261214571Sdim          sec = local_sections[r_symndx];
2262214571Sdim          relocation = (sec->output_section->vma
2263214571Sdim			+ sec->output_offset
2264214571Sdim			+ sym->st_value);
2265214571Sdim          name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, sec);
2266214571Sdim
2267214571Sdim          if (!info->relocatable
2268214571Sdim	      && (sec->flags & SEC_MERGE) != 0
2269214571Sdim	      && ELF_ST_TYPE (sym->st_info) == STT_SECTION)
2270214571Sdim            {
2271214571Sdim              asection *msec;
2272214571Sdim              bfd_vma addend, value;
2273214571Sdim
2274214571Sdim              switch (r_type)
2275214571Sdim                {
2276214571Sdim                case R_SCORE_HI16:
2277214571Sdim                  break;
2278214571Sdim                case R_SCORE_LO16:
2279214571Sdim                  hi16_addend = bfd_get_32 (input_bfd, contents + rel->r_offset - 4);
2280214571Sdim                  hi16_offset = ((((hi16_addend >> 16) & 0x3) << 15) | (hi16_addend & 0x7fff)) >> 1;
2281214571Sdim                  value = bfd_get_32 (input_bfd, contents + rel->r_offset);
2282214571Sdim                  offset = ((((value >> 16) & 0x3) << 15) | (value & 0x7fff)) >> 1;
2283214571Sdim                  addend = (hi16_offset << 16) | (offset & 0xffff);
2284214571Sdim                  msec = sec;
2285214571Sdim                  addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend);
2286214571Sdim                  addend -= relocation;
2287214571Sdim                  addend += msec->output_section->vma + msec->output_offset;
2288214571Sdim                  uvalue = addend;
2289214571Sdim                  hi16_offset = (uvalue >> 16) << 1;
2290214571Sdim                  hi16_value = (hi16_addend & (~(howto->dst_mask)))
2291214571Sdim                    | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000);
2292214571Sdim                  bfd_put_32 (input_bfd, hi16_value, contents + rel->r_offset - 4);
2293214571Sdim                  offset = (uvalue & 0xffff) << 1;
2294214571Sdim                  value = (value & (~(howto->dst_mask)))
2295214571Sdim                    | (offset & 0x7fff) | ((offset << 1) & 0x30000);
2296214571Sdim                  bfd_put_32 (input_bfd, value, contents + rel->r_offset);
2297214571Sdim                  break;
2298214571Sdim                case R_SCORE_GOT_LO16:
2299214571Sdim                  value = bfd_get_32 (input_bfd, contents + rel->r_offset);
2300214571Sdim                  addend = (((value >> 16) & 0x3) << 14) | ((value & 0x7fff) >> 1);
2301214571Sdim                  msec = sec;
2302214571Sdim                  addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend) - relocation;
2303214571Sdim                  addend += msec->output_section->vma + msec->output_offset;
2304214571Sdim                  value = (value & (~(howto->dst_mask))) | ((addend & 0x3fff) << 1)
2305214571Sdim                           | (((addend >> 14) & 0x3) << 16);
2306214571Sdim
2307214571Sdim                  bfd_put_32 (input_bfd, value, contents + rel->r_offset);
2308214571Sdim                  break;
2309214571Sdim                default:
2310214571Sdim                  value = bfd_get_32 (input_bfd, contents + rel->r_offset);
2311214571Sdim                  /* Get the (signed) value from the instruction.  */
2312214571Sdim                  addend = value & howto->src_mask;
2313214571Sdim                  if (addend & ((howto->src_mask + 1) >> 1))
2314214571Sdim                    {
2315214571Sdim                      bfd_signed_vma mask;
2316214571Sdim
2317214571Sdim                      mask = -1;
2318214571Sdim                      mask &= ~howto->src_mask;
2319214571Sdim                      addend |= mask;
2320214571Sdim                    }
2321214571Sdim                  msec = sec;
2322214571Sdim                  addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend) - relocation;
2323214571Sdim                  addend += msec->output_section->vma + msec->output_offset;
2324214571Sdim                  value = (value & ~howto->dst_mask) | (addend & howto->dst_mask);
2325214571Sdim                  bfd_put_32 (input_bfd, value, contents + rel->r_offset);
2326214571Sdim                  break;
2327214571Sdim                }
2328214571Sdim            }
2329214571Sdim        }
2330214571Sdim      else
2331214571Sdim        {
2332214571Sdim	  /* For global symbols we look up the symbol in the hash-table.  */
2333214571Sdim	  h = ((struct score_elf_link_hash_entry *)
2334214571Sdim	       elf_sym_hashes (input_bfd) [r_symndx - extsymoff]);
2335214571Sdim	  /* Find the real hash-table entry for this symbol.  */
2336214571Sdim	  while (h->root.root.type == bfd_link_hash_indirect
2337214571Sdim		 || h->root.root.type == bfd_link_hash_warning)
2338214571Sdim	    h = (struct score_elf_link_hash_entry *) h->root.root.u.i.link;
2339214571Sdim
2340214571Sdim	  /* Record the name of this symbol, for our caller.  */
2341214571Sdim	  name = h->root.root.root.string;
2342214571Sdim
2343214571Sdim	  /* See if this is the special GP_DISP_LABEL symbol.  Note that such a
2344214571Sdim	     symbol must always be a global symbol.  */
2345214571Sdim	  if (strcmp (name, GP_DISP_LABEL) == 0)
2346214571Sdim	    {
2347214571Sdim	      /* Relocations against GP_DISP_LABEL are permitted only with
2348214571Sdim		 R_SCORE_HI16 and R_SCORE_LO16 relocations.  */
2349214571Sdim	      if (r_type != R_SCORE_HI16 && r_type != R_SCORE_LO16)
2350214571Sdim		return bfd_reloc_notsupported;
2351214571Sdim
2352214571Sdim	      gp_disp_p = TRUE;
2353214571Sdim	    }
2354214571Sdim
2355214571Sdim	  /* If this symbol is defined, calculate its address.  Note that
2356214571Sdim	      GP_DISP_LABEL is a magic symbol, always implicitly defined by the
2357214571Sdim	      linker, so it's inappropriate to check to see whether or not
2358214571Sdim	      its defined.  */
2359214571Sdim	  else if ((h->root.root.type == bfd_link_hash_defined
2360214571Sdim		    || h->root.root.type == bfd_link_hash_defweak)
2361214571Sdim		   && h->root.root.u.def.section)
2362214571Sdim	    {
2363214571Sdim	      sec = h->root.root.u.def.section;
2364214571Sdim	      if (sec->output_section)
2365214571Sdim		relocation = (h->root.root.u.def.value
2366214571Sdim			      + sec->output_section->vma
2367214571Sdim			      + sec->output_offset);
2368214571Sdim	      else
2369214571Sdim		{
2370214571Sdim		  relocation = h->root.root.u.def.value;
2371214571Sdim		}
2372214571Sdim	    }
2373214571Sdim	  else if (h->root.root.type == bfd_link_hash_undefweak)
2374214571Sdim	    /* We allow relocations against undefined weak symbols, giving
2375214571Sdim	       it the value zero, so that you can undefined weak functions
2376214571Sdim	       and check to see if they exist by looking at their addresses.  */
2377214571Sdim	    relocation = 0;
2378214571Sdim	  else if (info->unresolved_syms_in_objects == RM_IGNORE
2379214571Sdim		   && ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT)
2380214571Sdim	    relocation = 0;
2381214571Sdim	  else if (strcmp (name, "_DYNAMIC_LINK") == 0)
2382214571Sdim	    {
2383214571Sdim	      /* If this is a dynamic link, we should have created a _DYNAMIC_LINK symbol
2384214571Sdim	         in _bfd_score_elf_create_dynamic_sections.  Otherwise, we should define
2385214571Sdim                 the symbol with a value of 0.  */
2386214571Sdim	      BFD_ASSERT (! info->shared);
2387214571Sdim	      BFD_ASSERT (bfd_get_section_by_name (output_bfd, ".dynamic") == NULL);
2388214571Sdim	      relocation = 0;
2389214571Sdim	    }
2390214571Sdim	  else if (!info->relocatable)
2391214571Sdim	    {
2392214571Sdim	      if (! ((*info->callbacks->undefined_symbol)
2393214571Sdim		     (info, h->root.root.root.string, input_bfd,
2394214571Sdim		      input_section, rel->r_offset,
2395214571Sdim		      (info->unresolved_syms_in_objects == RM_GENERATE_ERROR)
2396214571Sdim		      || ELF_ST_VISIBILITY (h->root.other))))
2397214571Sdim		return bfd_reloc_undefined;
2398214571Sdim	      relocation = 0;
2399214571Sdim	    }
2400214571Sdim        }
2401214571Sdim
2402214571Sdim      if (sec != NULL && elf_discarded_section (sec))
2403214571Sdim	{
2404214571Sdim	  /* For relocs against symbols from removed linkonce sections,
2405214571Sdim	     or sections discarded by a linker script, we just want the
2406214571Sdim	     section contents zeroed.  Avoid any special processing.  */
2407214571Sdim	  _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
2408214571Sdim	  rel->r_info = 0;
2409214571Sdim	  rel->r_addend = 0;
2410214571Sdim	  continue;
2411214571Sdim	}
2412214571Sdim
2413214571Sdim      if (info->relocatable)
2414214571Sdim        {
2415214571Sdim          /* This is a relocatable link.  We don't have to change
2416214571Sdim             anything, unless the reloc is against a section symbol,
2417214571Sdim             in which case we have to adjust according to where the
2418214571Sdim             section symbol winds up in the output section.  */
2419214571Sdim          if (sym != NULL && ELF_ST_TYPE (sym->st_info) == STT_SECTION)
2420214571Sdim	    score_elf_add_to_rel (input_bfd, contents + rel->r_offset,
2421214571Sdim				  howto, (bfd_signed_vma) sec->output_offset);
2422214571Sdim          continue;
2423214571Sdim        }
2424214571Sdim
2425214571Sdim      r = score_elf_final_link_relocate (howto, input_bfd, output_bfd,
2426214571Sdim                                         input_section, contents, rel, relocs,
2427214571Sdim                                         relocation, info, name,
2428214571Sdim                                         (h ? ELF_ST_TYPE ((unsigned int)h->root.root.type) :
2429214571Sdim					 ELF_ST_TYPE ((unsigned int)sym->st_info)), h, local_sections,
2430214571Sdim                                         gp_disp_p);
2431214571Sdim
2432214571Sdim      if (r != bfd_reloc_ok)
2433214571Sdim        {
2434214571Sdim          const char *msg = (const char *)0;
2435214571Sdim
2436214571Sdim          switch (r)
2437214571Sdim            {
2438214571Sdim            case bfd_reloc_overflow:
2439214571Sdim              /* If the overflowing reloc was to an undefined symbol,
2440214571Sdim                 we have already printed one error message and there
2441214571Sdim                 is no point complaining again.  */
2442214571Sdim              if (((!h) || (h->root.root.type != bfd_link_hash_undefined))
2443214571Sdim                  && (!((*info->callbacks->reloc_overflow)
2444214571Sdim                        (info, NULL, name, howto->name, (bfd_vma) 0,
2445214571Sdim                         input_bfd, input_section, rel->r_offset))))
2446214571Sdim                return FALSE;
2447214571Sdim              break;
2448214571Sdim            case bfd_reloc_undefined:
2449214571Sdim              if (!((*info->callbacks->undefined_symbol)
2450214571Sdim                    (info, name, input_bfd, input_section, rel->r_offset, TRUE)))
2451214571Sdim                return FALSE;
2452214571Sdim              break;
2453214571Sdim
2454214571Sdim            case bfd_reloc_outofrange:
2455214571Sdim              msg = _("internal error: out of range error");
2456214571Sdim              goto common_error;
2457214571Sdim
2458214571Sdim            case bfd_reloc_notsupported:
2459214571Sdim              msg = _("internal error: unsupported relocation error");
2460214571Sdim              goto common_error;
2461214571Sdim
2462214571Sdim            case bfd_reloc_dangerous:
2463214571Sdim              msg = _("internal error: dangerous error");
2464214571Sdim              goto common_error;
2465214571Sdim
2466214571Sdim            default:
2467214571Sdim              msg = _("internal error: unknown error");
2468214571Sdim              /* fall through */
2469214571Sdim
2470214571Sdim            common_error:
2471214571Sdim              if (!((*info->callbacks->warning)
2472214571Sdim                    (info, msg, name, input_bfd, input_section, rel->r_offset)))
2473214571Sdim                return FALSE;
2474214571Sdim              break;
2475214571Sdim            }
2476214571Sdim        }
2477214571Sdim    }
2478214571Sdim
2479214571Sdim  return TRUE;
2480214571Sdim}
2481214571Sdim
2482214571Sdim/* Look through the relocs for a section during the first phase, and
2483214571Sdim   allocate space in the global offset table.  */
2484214571Sdim
2485214571Sdimstatic bfd_boolean
2486214571Sdim_bfd_score_elf_check_relocs (bfd *abfd,
2487214571Sdim			     struct bfd_link_info *info,
2488214571Sdim			     asection *sec,
2489214571Sdim			     const Elf_Internal_Rela *relocs)
2490214571Sdim{
2491214571Sdim  const char *name;
2492214571Sdim  bfd *dynobj;
2493214571Sdim  Elf_Internal_Shdr *symtab_hdr;
2494214571Sdim  struct elf_link_hash_entry **sym_hashes;
2495214571Sdim  struct score_got_info *g;
2496214571Sdim  size_t extsymoff;
2497214571Sdim  const Elf_Internal_Rela *rel;
2498214571Sdim  const Elf_Internal_Rela *rel_end;
2499214571Sdim  asection *sgot;
2500214571Sdim  asection *sreloc;
2501214571Sdim  const struct elf_backend_data *bed;
2502214571Sdim
2503214571Sdim  if (info->relocatable)
2504214571Sdim    return TRUE;
2505214571Sdim
2506214571Sdim  dynobj = elf_hash_table (info)->dynobj;
2507214571Sdim  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
2508214571Sdim  sym_hashes = elf_sym_hashes (abfd);
2509214571Sdim  extsymoff = (elf_bad_symtab (abfd)) ? 0 : symtab_hdr->sh_info;
2510214571Sdim
2511214571Sdim  name = bfd_get_section_name (abfd, sec);
2512214571Sdim
2513214571Sdim  if (dynobj == NULL)
2514214571Sdim    {
2515214571Sdim      sgot = NULL;
2516214571Sdim      g = NULL;
2517214571Sdim    }
2518214571Sdim  else
2519214571Sdim    {
2520214571Sdim      sgot = score_elf_got_section (dynobj, FALSE);
2521214571Sdim      if (sgot == NULL)
2522214571Sdim        g = NULL;
2523214571Sdim      else
2524214571Sdim        {
2525214571Sdim          BFD_ASSERT (score_elf_section_data (sgot) != NULL);
2526214571Sdim          g = score_elf_section_data (sgot)->u.got_info;
2527214571Sdim          BFD_ASSERT (g != NULL);
2528214571Sdim        }
2529214571Sdim    }
2530214571Sdim
2531214571Sdim  sreloc = NULL;
2532214571Sdim  bed = get_elf_backend_data (abfd);
2533214571Sdim  rel_end = relocs + sec->reloc_count * bed->s->int_rels_per_ext_rel;
2534214571Sdim  for (rel = relocs; rel < rel_end; ++rel)
2535214571Sdim    {
2536214571Sdim      unsigned long r_symndx;
2537214571Sdim      unsigned int r_type;
2538214571Sdim      struct elf_link_hash_entry *h;
2539214571Sdim
2540214571Sdim      r_symndx = ELF32_R_SYM (rel->r_info);
2541214571Sdim      r_type = ELF32_R_TYPE (rel->r_info);
2542214571Sdim
2543214571Sdim      if (r_symndx < extsymoff)
2544214571Sdim	{
2545214571Sdim          h = NULL;
2546214571Sdim	}
2547214571Sdim      else if (r_symndx >= extsymoff + NUM_SHDR_ENTRIES (symtab_hdr))
2548214571Sdim        {
2549273232Semaste          (*_bfd_error_handler) (_("%B: Malformed reloc detected for section %s"), abfd, name);
2550214571Sdim          bfd_set_error (bfd_error_bad_value);
2551214571Sdim          return FALSE;
2552214571Sdim        }
2553214571Sdim      else
2554214571Sdim        {
2555214571Sdim          h = sym_hashes[r_symndx - extsymoff];
2556214571Sdim
2557214571Sdim          /* This may be an indirect symbol created because of a version.  */
2558214571Sdim          if (h != NULL)
2559214571Sdim            {
2560214571Sdim              while (h->root.type == bfd_link_hash_indirect)
2561214571Sdim                h = (struct elf_link_hash_entry *)h->root.u.i.link;
2562214571Sdim            }
2563214571Sdim        }
2564214571Sdim
2565214571Sdim      /* Some relocs require a global offset table.  */
2566214571Sdim      if (dynobj == NULL || sgot == NULL)
2567214571Sdim        {
2568214571Sdim          switch (r_type)
2569214571Sdim            {
2570214571Sdim            case R_SCORE_GOT15:
2571214571Sdim            case R_SCORE_CALL15:
2572214571Sdim              if (dynobj == NULL)
2573214571Sdim                elf_hash_table (info)->dynobj = dynobj = abfd;
2574214571Sdim              if (!score_elf_create_got_section (dynobj, info, FALSE))
2575214571Sdim                return FALSE;
2576214571Sdim              g = score_elf_got_info (dynobj, &sgot);
2577214571Sdim              break;
2578214571Sdim            case R_SCORE_ABS32:
2579214571Sdim            case R_SCORE_REL32:
2580214571Sdim              if (dynobj == NULL && (info->shared || h != NULL) && (sec->flags & SEC_ALLOC) != 0)
2581214571Sdim                elf_hash_table (info)->dynobj = dynobj = abfd;
2582214571Sdim              break;
2583214571Sdim            default:
2584214571Sdim              break;
2585214571Sdim            }
2586214571Sdim        }
2587214571Sdim
2588214571Sdim      if (!h && (r_type == R_SCORE_GOT_LO16))
2589214571Sdim        {
2590214571Sdim	  if (! score_elf_record_local_got_symbol (abfd, r_symndx, rel->r_addend, g))
2591214571Sdim	    return FALSE;
2592214571Sdim        }
2593214571Sdim
2594214571Sdim      switch (r_type)
2595214571Sdim        {
2596214571Sdim        case R_SCORE_CALL15:
2597214571Sdim	  if (h == NULL)
2598214571Sdim	    {
2599214571Sdim	      (*_bfd_error_handler)
2600214571Sdim		(_("%B: CALL15 reloc at 0x%lx not against global symbol"),
2601214571Sdim		 abfd, (unsigned long) rel->r_offset);
2602214571Sdim	      bfd_set_error (bfd_error_bad_value);
2603214571Sdim	      return FALSE;
2604214571Sdim	    }
2605214571Sdim	  else
2606214571Sdim	    {
2607214571Sdim	      /* This symbol requires a global offset table entry.  */
2608214571Sdim	      if (! score_elf_record_global_got_symbol (h, abfd, info, g))
2609214571Sdim		return FALSE;
2610214571Sdim
2611214571Sdim	      /* We need a stub, not a plt entry for the undefined function.  But we record
2612214571Sdim                 it as if it needs plt.  See _bfd_elf_adjust_dynamic_symbol.  */
2613214571Sdim	      h->needs_plt = 1;
2614214571Sdim	      h->type = STT_FUNC;
2615214571Sdim	    }
2616214571Sdim          break;
2617214571Sdim	case R_SCORE_GOT15:
2618214571Sdim	  if (h && ! score_elf_record_global_got_symbol (h, abfd, info, g))
2619214571Sdim	    return FALSE;
2620214571Sdim	  break;
2621214571Sdim        case R_SCORE_ABS32:
2622214571Sdim        case R_SCORE_REL32:
2623214571Sdim	  if ((info->shared || h != NULL) && (sec->flags & SEC_ALLOC) != 0)
2624214571Sdim	    {
2625214571Sdim	      if (sreloc == NULL)
2626214571Sdim		{
2627214571Sdim		  sreloc = score_elf_rel_dyn_section (dynobj, TRUE);
2628214571Sdim		  if (sreloc == NULL)
2629214571Sdim		    return FALSE;
2630214571Sdim		}
2631214571Sdim#define SCORE_READONLY_SECTION (SEC_ALLOC | SEC_LOAD | SEC_READONLY)
2632214571Sdim	      if (info->shared)
2633214571Sdim		{
2634214571Sdim		  /* When creating a shared object, we must copy these reloc types into
2635214571Sdim                     the output file as R_SCORE_REL32 relocs.  We make room for this reloc
2636214571Sdim                     in the .rel.dyn reloc section.  */
2637214571Sdim		  score_elf_allocate_dynamic_relocations (dynobj, 1);
2638214571Sdim		  if ((sec->flags & SCORE_READONLY_SECTION)
2639214571Sdim		      == SCORE_READONLY_SECTION)
2640214571Sdim		    /* We tell the dynamic linker that there are
2641214571Sdim		       relocations against the text segment.  */
2642214571Sdim		    info->flags |= DF_TEXTREL;
2643214571Sdim		}
2644214571Sdim	      else
2645214571Sdim		{
2646214571Sdim		  struct score_elf_link_hash_entry *hscore;
2647214571Sdim
2648214571Sdim		  /* We only need to copy this reloc if the symbol is
2649214571Sdim                     defined in a dynamic object.  */
2650214571Sdim		  hscore = (struct score_elf_link_hash_entry *)h;
2651214571Sdim		  ++hscore->possibly_dynamic_relocs;
2652214571Sdim		  if ((sec->flags & SCORE_READONLY_SECTION)
2653214571Sdim		      == SCORE_READONLY_SECTION)
2654214571Sdim		    /* We need it to tell the dynamic linker if there
2655214571Sdim		       are relocations against the text segment.  */
2656214571Sdim		    hscore->readonly_reloc = TRUE;
2657214571Sdim		}
2658214571Sdim
2659214571Sdim	      /* Even though we don't directly need a GOT entry for this symbol,
2660214571Sdim                 a symbol must have a dynamic symbol table index greater that
2661214571Sdim                 DT_SCORE_GOTSYM if there are dynamic relocations against it.  */
2662214571Sdim	      if (h != NULL)
2663214571Sdim		{
2664214571Sdim		  if (dynobj == NULL)
2665214571Sdim		    elf_hash_table (info)->dynobj = dynobj = abfd;
2666214571Sdim		  if (! score_elf_create_got_section (dynobj, info, TRUE))
2667214571Sdim		    return FALSE;
2668214571Sdim		  g = score_elf_got_info (dynobj, &sgot);
2669214571Sdim		  if (! score_elf_record_global_got_symbol (h, abfd, info, g))
2670214571Sdim		    return FALSE;
2671214571Sdim		}
2672214571Sdim	    }
2673214571Sdim	  break;
2674214571Sdim
2675214571Sdim          /* This relocation describes the C++ object vtable hierarchy.
2676214571Sdim             Reconstruct it for later use during GC.  */
2677214571Sdim        case R_SCORE_GNU_VTINHERIT:
2678214571Sdim          if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
2679214571Sdim            return FALSE;
2680214571Sdim          break;
2681214571Sdim
2682214571Sdim          /* This relocation describes which C++ vtable entries are actually
2683214571Sdim             used.  Record for later use during GC.  */
2684214571Sdim        case R_SCORE_GNU_VTENTRY:
2685214571Sdim          if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset))
2686214571Sdim            return FALSE;
2687214571Sdim          break;
2688214571Sdim        default:
2689214571Sdim          break;
2690214571Sdim        }
2691214571Sdim
2692214571Sdim      /* We must not create a stub for a symbol that has relocations
2693214571Sdim         related to taking the function's address.  */
2694214571Sdim      switch (r_type)
2695214571Sdim	{
2696214571Sdim	default:
2697214571Sdim	  if (h != NULL)
2698214571Sdim	    {
2699214571Sdim	      struct score_elf_link_hash_entry *sh;
2700214571Sdim
2701214571Sdim	      sh = (struct score_elf_link_hash_entry *) h;
2702214571Sdim	      sh->no_fn_stub = TRUE;
2703214571Sdim	    }
2704214571Sdim	  break;
2705214571Sdim	case R_SCORE_CALL15:
2706214571Sdim	  break;
2707214571Sdim	}
2708214571Sdim    }
2709214571Sdim
2710214571Sdim  return TRUE;
2711214571Sdim}
2712214571Sdim
2713214571Sdimstatic bfd_boolean
2714214571Sdim_bfd_score_elf_add_symbol_hook (bfd *abfd,
2715214571Sdim				struct bfd_link_info *info ATTRIBUTE_UNUSED,
2716214571Sdim				Elf_Internal_Sym *sym,
2717214571Sdim				const char **namep ATTRIBUTE_UNUSED,
2718214571Sdim				flagword *flagsp ATTRIBUTE_UNUSED,
2719214571Sdim				asection **secp,
2720214571Sdim				bfd_vma *valp)
2721214571Sdim{
2722214571Sdim  switch (sym->st_shndx)
2723214571Sdim    {
2724214571Sdim    case SHN_COMMON:
2725214571Sdim      if (sym->st_size > elf_gp_size (abfd))
2726214571Sdim        break;
2727214571Sdim      /* Fall through.  */
2728214571Sdim    case SHN_SCORE_SCOMMON:
2729214571Sdim      *secp = bfd_make_section_old_way (abfd, ".scommon");
2730214571Sdim      (*secp)->flags |= SEC_IS_COMMON;
2731214571Sdim      *valp = sym->st_size;
2732214571Sdim      break;
2733214571Sdim    }
2734214571Sdim
2735214571Sdim  return TRUE;
2736214571Sdim}
2737214571Sdim
2738214571Sdimstatic void
2739214571Sdim_bfd_score_elf_symbol_processing (bfd *abfd, asymbol *asym)
2740214571Sdim{
2741214571Sdim  elf_symbol_type *elfsym;
2742214571Sdim
2743214571Sdim  elfsym = (elf_symbol_type *) asym;
2744214571Sdim  switch (elfsym->internal_elf_sym.st_shndx)
2745214571Sdim    {
2746214571Sdim    case SHN_COMMON:
2747214571Sdim      if (asym->value > elf_gp_size (abfd))
2748214571Sdim        break;
2749214571Sdim      /* Fall through.  */
2750214571Sdim    case SHN_SCORE_SCOMMON:
2751214571Sdim      if (score_elf_scom_section.name == NULL)
2752214571Sdim        {
2753214571Sdim          /* Initialize the small common section.  */
2754214571Sdim          score_elf_scom_section.name = ".scommon";
2755214571Sdim          score_elf_scom_section.flags = SEC_IS_COMMON;
2756214571Sdim          score_elf_scom_section.output_section = &score_elf_scom_section;
2757214571Sdim          score_elf_scom_section.symbol = &score_elf_scom_symbol;
2758214571Sdim          score_elf_scom_section.symbol_ptr_ptr = &score_elf_scom_symbol_ptr;
2759214571Sdim          score_elf_scom_symbol.name = ".scommon";
2760214571Sdim          score_elf_scom_symbol.flags = BSF_SECTION_SYM;
2761214571Sdim          score_elf_scom_symbol.section = &score_elf_scom_section;
2762214571Sdim          score_elf_scom_symbol_ptr = &score_elf_scom_symbol;
2763214571Sdim        }
2764214571Sdim      asym->section = &score_elf_scom_section;
2765214571Sdim      asym->value = elfsym->internal_elf_sym.st_size;
2766214571Sdim      break;
2767214571Sdim    }
2768214571Sdim}
2769214571Sdim
2770214571Sdimstatic bfd_boolean
2771214571Sdim_bfd_score_elf_link_output_symbol_hook (struct bfd_link_info *info ATTRIBUTE_UNUSED,
2772214571Sdim     const char *name ATTRIBUTE_UNUSED,
2773214571Sdim     Elf_Internal_Sym *sym,
2774214571Sdim     asection *input_sec,
2775214571Sdim     struct elf_link_hash_entry *h ATTRIBUTE_UNUSED)
2776214571Sdim{
2777214571Sdim  /* If we see a common symbol, which implies a relocatable link, then
2778214571Sdim     if a symbol was small common in an input file, mark it as small
2779214571Sdim     common in the output file.  */
2780214571Sdim  if (sym->st_shndx == SHN_COMMON && strcmp (input_sec->name, ".scommon") == 0)
2781214571Sdim    sym->st_shndx = SHN_SCORE_SCOMMON;
2782214571Sdim
2783214571Sdim  return TRUE;
2784214571Sdim}
2785214571Sdim
2786214571Sdimstatic bfd_boolean
2787214571Sdim_bfd_score_elf_section_from_bfd_section (bfd *abfd ATTRIBUTE_UNUSED,
2788214571Sdim					 asection *sec,
2789214571Sdim					 int *retval)
2790214571Sdim{
2791214571Sdim  if (strcmp (bfd_get_section_name (abfd, sec), ".scommon") == 0)
2792214571Sdim    {
2793214571Sdim      *retval = SHN_SCORE_SCOMMON;
2794214571Sdim      return TRUE;
2795214571Sdim    }
2796214571Sdim
2797214571Sdim  return FALSE;
2798214571Sdim}
2799214571Sdim
2800214571Sdim/* Adjust a symbol defined by a dynamic object and referenced by a
2801214571Sdim   regular object.  The current definition is in some section of the
2802214571Sdim   dynamic object, but we're not including those sections.  We have to
2803214571Sdim   change the definition to something the rest of the link can understand.  */
2804214571Sdim
2805214571Sdimstatic bfd_boolean
2806214571Sdim_bfd_score_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
2807214571Sdim				      struct elf_link_hash_entry *h)
2808214571Sdim{
2809214571Sdim  bfd *dynobj;
2810214571Sdim  struct score_elf_link_hash_entry *hscore;
2811214571Sdim  asection *s;
2812214571Sdim
2813214571Sdim  dynobj = elf_hash_table (info)->dynobj;
2814214571Sdim
2815214571Sdim  /* Make sure we know what is going on here.  */
2816214571Sdim  BFD_ASSERT (dynobj != NULL
2817214571Sdim              && (h->needs_plt
2818214571Sdim                  || h->u.weakdef != NULL
2819214571Sdim                  || (h->def_dynamic && h->ref_regular && !h->def_regular)));
2820214571Sdim
2821214571Sdim  /* If this symbol is defined in a dynamic object, we need to copy
2822214571Sdim     any R_SCORE_ABS32 or R_SCORE_REL32 relocs against it into the output
2823214571Sdim     file.  */
2824214571Sdim  hscore = (struct score_elf_link_hash_entry *)h;
2825214571Sdim  if (!info->relocatable
2826214571Sdim      && hscore->possibly_dynamic_relocs != 0
2827214571Sdim      && (h->root.type == bfd_link_hash_defweak || !h->def_regular))
2828214571Sdim    {
2829214571Sdim      score_elf_allocate_dynamic_relocations (dynobj, hscore->possibly_dynamic_relocs);
2830214571Sdim      if (hscore->readonly_reloc)
2831214571Sdim        /* We tell the dynamic linker that there are relocations
2832214571Sdim           against the text segment.  */
2833214571Sdim        info->flags |= DF_TEXTREL;
2834214571Sdim    }
2835214571Sdim
2836214571Sdim  /* For a function, create a stub, if allowed.  */
2837214571Sdim  if (!hscore->no_fn_stub && h->needs_plt)
2838214571Sdim    {
2839214571Sdim      if (!elf_hash_table (info)->dynamic_sections_created)
2840214571Sdim        return TRUE;
2841214571Sdim
2842214571Sdim      /* If this symbol is not defined in a regular file, then set
2843214571Sdim         the symbol to the stub location.  This is required to make
2844214571Sdim         function pointers compare as equal between the normal
2845214571Sdim         executable and the shared library.  */
2846214571Sdim      if (!h->def_regular)
2847214571Sdim        {
2848214571Sdim          /* We need .stub section.  */
2849214571Sdim          s = bfd_get_section_by_name (dynobj, SCORE_ELF_STUB_SECTION_NAME);
2850214571Sdim          BFD_ASSERT (s != NULL);
2851214571Sdim
2852214571Sdim          h->root.u.def.section = s;
2853214571Sdim          h->root.u.def.value = s->size;
2854214571Sdim
2855214571Sdim          /* XXX Write this stub address somewhere.  */
2856214571Sdim          h->plt.offset = s->size;
2857214571Sdim
2858214571Sdim          /* Make room for this stub code.  */
2859214571Sdim          s->size += SCORE_FUNCTION_STUB_SIZE;
2860214571Sdim
2861214571Sdim          /* The last half word of the stub will be filled with the index
2862214571Sdim             of this symbol in .dynsym section.  */
2863214571Sdim          return TRUE;
2864214571Sdim        }
2865214571Sdim    }
2866214571Sdim  else if ((h->type == STT_FUNC) && !h->needs_plt)
2867214571Sdim    {
2868214571Sdim      /* This will set the entry for this symbol in the GOT to 0, and
2869214571Sdim         the dynamic linker will take care of this.  */
2870214571Sdim      h->root.u.def.value = 0;
2871214571Sdim      return TRUE;
2872214571Sdim    }
2873214571Sdim
2874214571Sdim  /* If this is a weak symbol, and there is a real definition, the
2875214571Sdim     processor independent code will have arranged for us to see the
2876214571Sdim     real definition first, and we can just use the same value.  */
2877214571Sdim  if (h->u.weakdef != NULL)
2878214571Sdim    {
2879214571Sdim      BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined
2880214571Sdim                  || h->u.weakdef->root.type == bfd_link_hash_defweak);
2881214571Sdim      h->root.u.def.section = h->u.weakdef->root.u.def.section;
2882214571Sdim      h->root.u.def.value = h->u.weakdef->root.u.def.value;
2883214571Sdim      return TRUE;
2884214571Sdim    }
2885214571Sdim
2886214571Sdim  /* This is a reference to a symbol defined by a dynamic object which
2887214571Sdim     is not a function.  */
2888214571Sdim  return TRUE;
2889214571Sdim}
2890214571Sdim
2891214571Sdim/* This function is called after all the input files have been read,
2892214571Sdim   and the input sections have been assigned to output sections.  */
2893214571Sdim
2894214571Sdimstatic bfd_boolean
2895214571Sdim_bfd_score_elf_always_size_sections (bfd *output_bfd,
2896214571Sdim				     struct bfd_link_info *info)
2897214571Sdim{
2898214571Sdim  bfd *dynobj;
2899214571Sdim  asection *s;
2900214571Sdim  struct score_got_info *g;
2901214571Sdim  int i;
2902214571Sdim  bfd_size_type loadable_size = 0;
2903214571Sdim  bfd_size_type local_gotno;
2904214571Sdim  bfd *sub;
2905214571Sdim
2906214571Sdim  dynobj = elf_hash_table (info)->dynobj;
2907214571Sdim  if (dynobj == NULL)
2908214571Sdim    /* Relocatable links don't have it.  */
2909214571Sdim    return TRUE;
2910214571Sdim
2911214571Sdim  g = score_elf_got_info (dynobj, &s);
2912214571Sdim  if (s == NULL)
2913214571Sdim    return TRUE;
2914214571Sdim
2915214571Sdim  /* Calculate the total loadable size of the output.  That will give us the
2916214571Sdim     maximum number of GOT_PAGE entries required.  */
2917214571Sdim  for (sub = info->input_bfds; sub; sub = sub->link_next)
2918214571Sdim    {
2919214571Sdim      asection *subsection;
2920214571Sdim
2921214571Sdim      for (subsection = sub->sections;
2922214571Sdim	   subsection;
2923214571Sdim	   subsection = subsection->next)
2924214571Sdim	{
2925214571Sdim	  if ((subsection->flags & SEC_ALLOC) == 0)
2926214571Sdim	    continue;
2927214571Sdim	  loadable_size += ((subsection->size + 0xf)
2928214571Sdim			    &~ (bfd_size_type) 0xf);
2929214571Sdim	}
2930214571Sdim    }
2931214571Sdim
2932214571Sdim  /* There has to be a global GOT entry for every symbol with
2933214571Sdim     a dynamic symbol table index of DT_SCORE_GOTSYM or
2934214571Sdim     higher.  Therefore, it make sense to put those symbols
2935214571Sdim     that need GOT entries at the end of the symbol table.  We
2936214571Sdim     do that here.  */
2937214571Sdim  if (! score_elf_sort_hash_table (info, 1))
2938214571Sdim    return FALSE;
2939214571Sdim
2940214571Sdim  if (g->global_gotsym != NULL)
2941214571Sdim    i = elf_hash_table (info)->dynsymcount - g->global_gotsym->dynindx;
2942214571Sdim  else
2943214571Sdim    /* If there are no global symbols, or none requiring
2944214571Sdim       relocations, then GLOBAL_GOTSYM will be NULL.  */
2945214571Sdim    i = 0;
2946214571Sdim
2947214571Sdim  /* In the worst case, we'll get one stub per dynamic symbol.  */
2948214571Sdim  loadable_size += SCORE_FUNCTION_STUB_SIZE * i;
2949214571Sdim
2950214571Sdim  /* Assume there are two loadable segments consisting of
2951214571Sdim     contiguous sections.  Is 5 enough?  */
2952214571Sdim  local_gotno = (loadable_size >> 16) + 5;
2953214571Sdim
2954214571Sdim  g->local_gotno += local_gotno;
2955214571Sdim  s->size += g->local_gotno * SCORE_ELF_GOT_SIZE (output_bfd);
2956214571Sdim
2957214571Sdim  g->global_gotno = i;
2958214571Sdim  s->size += i * SCORE_ELF_GOT_SIZE (output_bfd);
2959214571Sdim
2960214571Sdim  score_elf_resolve_final_got_entries (g);
2961214571Sdim
2962214571Sdim  if (s->size > SCORE_ELF_GOT_MAX_SIZE (output_bfd))
2963214571Sdim    {
2964214571Sdim      /* Fixme. Error message or Warning message should be issued here.  */
2965214571Sdim    }
2966214571Sdim
2967214571Sdim  return TRUE;
2968214571Sdim}
2969214571Sdim
2970214571Sdim/* Set the sizes of the dynamic sections.  */
2971214571Sdim
2972214571Sdimstatic bfd_boolean
2973214571Sdim_bfd_score_elf_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
2974214571Sdim{
2975214571Sdim  bfd *dynobj;
2976214571Sdim  asection *s;
2977214571Sdim  bfd_boolean reltext;
2978214571Sdim
2979214571Sdim  dynobj = elf_hash_table (info)->dynobj;
2980214571Sdim  BFD_ASSERT (dynobj != NULL);
2981214571Sdim
2982214571Sdim  if (elf_hash_table (info)->dynamic_sections_created)
2983214571Sdim    {
2984214571Sdim      /* Set the contents of the .interp section to the interpreter.  */
2985214571Sdim      if (!info->shared)
2986214571Sdim        {
2987214571Sdim          s = bfd_get_section_by_name (dynobj, ".interp");
2988214571Sdim          BFD_ASSERT (s != NULL);
2989214571Sdim          s->size = strlen (ELF_DYNAMIC_INTERPRETER) + 1;
2990214571Sdim          s->contents = (bfd_byte *) ELF_DYNAMIC_INTERPRETER;
2991214571Sdim        }
2992214571Sdim    }
2993214571Sdim
2994214571Sdim  /* The check_relocs and adjust_dynamic_symbol entry points have
2995214571Sdim     determined the sizes of the various dynamic sections.  Allocate
2996214571Sdim     memory for them.  */
2997214571Sdim  reltext = FALSE;
2998214571Sdim  for (s = dynobj->sections; s != NULL; s = s->next)
2999214571Sdim    {
3000214571Sdim      const char *name;
3001214571Sdim
3002214571Sdim      if ((s->flags & SEC_LINKER_CREATED) == 0)
3003214571Sdim        continue;
3004214571Sdim
3005214571Sdim      /* It's OK to base decisions on the section name, because none
3006214571Sdim         of the dynobj section names depend upon the input files.  */
3007214571Sdim      name = bfd_get_section_name (dynobj, s);
3008214571Sdim
3009214571Sdim      if (CONST_STRNEQ (name, ".rel"))
3010214571Sdim        {
3011214571Sdim          if (s->size == 0)
3012214571Sdim            {
3013214571Sdim              /* We only strip the section if the output section name
3014214571Sdim                 has the same name.  Otherwise, there might be several
3015214571Sdim                 input sections for this output section.  FIXME: This
3016214571Sdim                 code is probably not needed these days anyhow, since
3017214571Sdim                 the linker now does not create empty output sections.  */
3018214571Sdim              if (s->output_section != NULL
3019214571Sdim                  && strcmp (name,
3020214571Sdim                             bfd_get_section_name (s->output_section->owner,
3021214571Sdim                                                   s->output_section)) == 0)
3022214571Sdim                s->flags |= SEC_EXCLUDE;
3023214571Sdim            }
3024214571Sdim          else
3025214571Sdim            {
3026214571Sdim              const char *outname;
3027214571Sdim              asection *target;
3028214571Sdim
3029214571Sdim              /* If this relocation section applies to a read only
3030214571Sdim                 section, then we probably need a DT_TEXTREL entry.
3031214571Sdim                 If the relocation section is .rel.dyn, we always
3032214571Sdim                 assert a DT_TEXTREL entry rather than testing whether
3033214571Sdim                 there exists a relocation to a read only section or
3034214571Sdim                 not.  */
3035214571Sdim              outname = bfd_get_section_name (output_bfd, s->output_section);
3036214571Sdim              target = bfd_get_section_by_name (output_bfd, outname + 4);
3037214571Sdim              if ((target != NULL
3038214571Sdim                   && (target->flags & SEC_READONLY) != 0
3039214571Sdim                   && (target->flags & SEC_ALLOC) != 0) || strcmp (outname, ".rel.dyn") == 0)
3040214571Sdim                reltext = TRUE;
3041214571Sdim
3042214571Sdim              /* We use the reloc_count field as a counter if we need
3043214571Sdim                 to copy relocs into the output file.  */
3044214571Sdim              if (strcmp (name, ".rel.dyn") != 0)
3045214571Sdim                s->reloc_count = 0;
3046214571Sdim            }
3047214571Sdim        }
3048214571Sdim      else if (CONST_STRNEQ (name, ".got"))
3049214571Sdim        {
3050214571Sdim	  /* _bfd_score_elf_always_size_sections() has already done
3051214571Sdim	     most of the work, but some symbols may have been mapped
3052214571Sdim	     to versions that we must now resolve in the got_entries
3053214571Sdim	     hash tables.  */
3054214571Sdim        }
3055214571Sdim      else if (strcmp (name, SCORE_ELF_STUB_SECTION_NAME) == 0)
3056214571Sdim        {
3057214571Sdim          /* IRIX rld assumes that the function stub isn't at the end
3058214571Sdim             of .text section. So put a dummy. XXX  */
3059214571Sdim          s->size += SCORE_FUNCTION_STUB_SIZE;
3060214571Sdim        }
3061214571Sdim      else if (! CONST_STRNEQ (name, ".init"))
3062214571Sdim        {
3063214571Sdim          /* It's not one of our sections, so don't allocate space.  */
3064214571Sdim          continue;
3065214571Sdim        }
3066214571Sdim
3067214571Sdim      /* Allocate memory for the section contents.  */
3068214571Sdim      s->contents = bfd_zalloc (dynobj, s->size);
3069214571Sdim      if (s->contents == NULL && s->size != 0)
3070214571Sdim        {
3071214571Sdim          bfd_set_error (bfd_error_no_memory);
3072214571Sdim          return FALSE;
3073214571Sdim        }
3074214571Sdim    }
3075214571Sdim
3076214571Sdim  if (elf_hash_table (info)->dynamic_sections_created)
3077214571Sdim    {
3078214571Sdim      /* Add some entries to the .dynamic section.  We fill in the
3079214571Sdim	 values later, in _bfd_score_elf_finish_dynamic_sections, but we
3080214571Sdim	 must add the entries now so that we get the correct size for
3081214571Sdim	 the .dynamic section.  The DT_DEBUG entry is filled in by the
3082214571Sdim	 dynamic linker and used by the debugger.  */
3083214571Sdim
3084214571Sdim      if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_DEBUG, 0))
3085214571Sdim	return FALSE;
3086214571Sdim
3087214571Sdim      if (reltext)
3088214571Sdim	info->flags |= DF_TEXTREL;
3089214571Sdim
3090214571Sdim      if ((info->flags & DF_TEXTREL) != 0)
3091214571Sdim	{
3092214571Sdim	  if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_TEXTREL, 0))
3093214571Sdim	    return FALSE;
3094214571Sdim	}
3095214571Sdim
3096214571Sdim      if (! SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_PLTGOT, 0))
3097214571Sdim	return FALSE;
3098214571Sdim
3099214571Sdim      if (score_elf_rel_dyn_section (dynobj, FALSE))
3100214571Sdim	{
3101214571Sdim	  if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_REL, 0))
3102214571Sdim	    return FALSE;
3103214571Sdim
3104214571Sdim	  if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_RELSZ, 0))
3105214571Sdim	    return FALSE;
3106214571Sdim
3107214571Sdim	  if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_RELENT, 0))
3108214571Sdim	    return FALSE;
3109214571Sdim	}
3110214571Sdim
3111214571Sdim      if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_BASE_ADDRESS, 0))
3112214571Sdim        return FALSE;
3113214571Sdim
3114214571Sdim      if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_LOCAL_GOTNO, 0))
3115214571Sdim        return FALSE;
3116214571Sdim
3117214571Sdim      if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_SYMTABNO, 0))
3118214571Sdim        return FALSE;
3119214571Sdim
3120214571Sdim      if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_UNREFEXTNO, 0))
3121214571Sdim        return FALSE;
3122214571Sdim
3123214571Sdim      if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_GOTSYM, 0))
3124214571Sdim        return FALSE;
3125214571Sdim
3126214571Sdim      if (!SCORE_ELF_ADD_DYNAMIC_ENTRY (info, DT_SCORE_HIPAGENO, 0))
3127214571Sdim	return FALSE;
3128214571Sdim    }
3129214571Sdim
3130214571Sdim  return TRUE;
3131214571Sdim}
3132214571Sdim
3133214571Sdimstatic bfd_boolean
3134214571Sdim_bfd_score_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
3135214571Sdim{
3136214571Sdim  struct elf_link_hash_entry *h;
3137214571Sdim  struct bfd_link_hash_entry *bh;
3138214571Sdim  flagword flags;
3139214571Sdim  asection *s;
3140214571Sdim
3141214571Sdim  flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
3142214571Sdim           | SEC_LINKER_CREATED | SEC_READONLY);
3143214571Sdim
3144214571Sdim  /* ABI requests the .dynamic section to be read only.  */
3145214571Sdim  s = bfd_get_section_by_name (abfd, ".dynamic");
3146214571Sdim  if (s != NULL)
3147214571Sdim    {
3148214571Sdim      if (!bfd_set_section_flags (abfd, s, flags))
3149214571Sdim        return FALSE;
3150214571Sdim    }
3151214571Sdim
3152214571Sdim  /* We need to create .got section.  */
3153214571Sdim  if (!score_elf_create_got_section (abfd, info, FALSE))
3154214571Sdim    return FALSE;
3155214571Sdim
3156214571Sdim  if (!score_elf_rel_dyn_section (elf_hash_table (info)->dynobj, TRUE))
3157214571Sdim    return FALSE;
3158214571Sdim
3159214571Sdim  /* Create .stub section.  */
3160214571Sdim  if (bfd_get_section_by_name (abfd, SCORE_ELF_STUB_SECTION_NAME) == NULL)
3161214571Sdim    {
3162214571Sdim      s = bfd_make_section_with_flags (abfd, SCORE_ELF_STUB_SECTION_NAME,
3163214571Sdim                                       flags | SEC_CODE);
3164214571Sdim      if (s == NULL
3165214571Sdim          || !bfd_set_section_alignment (abfd, s, 2))
3166214571Sdim
3167214571Sdim        return FALSE;
3168214571Sdim    }
3169214571Sdim
3170214571Sdim  if (!info->shared)
3171214571Sdim    {
3172214571Sdim      const char *name;
3173214571Sdim
3174214571Sdim      name = "_DYNAMIC_LINK";
3175214571Sdim      bh = NULL;
3176214571Sdim      if (!(_bfd_generic_link_add_one_symbol
3177214571Sdim            (info, abfd, name, BSF_GLOBAL, bfd_abs_section_ptr,
3178214571Sdim             (bfd_vma) 0, (const char *)NULL, FALSE, get_elf_backend_data (abfd)->collect, &bh)))
3179214571Sdim        return FALSE;
3180214571Sdim
3181214571Sdim      h = (struct elf_link_hash_entry *)bh;
3182214571Sdim      h->non_elf = 0;
3183214571Sdim      h->def_regular = 1;
3184214571Sdim      h->type = STT_SECTION;
3185214571Sdim
3186214571Sdim      if (!bfd_elf_link_record_dynamic_symbol (info, h))
3187214571Sdim        return FALSE;
3188214571Sdim    }
3189214571Sdim
3190214571Sdim  return TRUE;
3191214571Sdim}
3192214571Sdim
3193214571Sdim
3194214571Sdim/* Finish up dynamic symbol handling.  We set the contents of various
3195214571Sdim   dynamic sections here.  */
3196214571Sdim
3197214571Sdimstatic bfd_boolean
3198214571Sdim_bfd_score_elf_finish_dynamic_symbol (bfd *output_bfd,
3199214571Sdim				      struct bfd_link_info *info,
3200214571Sdim				      struct elf_link_hash_entry *h,
3201214571Sdim				      Elf_Internal_Sym *sym)
3202214571Sdim{
3203214571Sdim  bfd *dynobj;
3204214571Sdim  asection *sgot;
3205214571Sdim  struct score_got_info *g;
3206214571Sdim  const char *name;
3207214571Sdim
3208214571Sdim  dynobj = elf_hash_table (info)->dynobj;
3209214571Sdim
3210214571Sdim  if (h->plt.offset != MINUS_ONE)
3211214571Sdim    {
3212214571Sdim      asection *s;
3213214571Sdim      bfd_byte stub[SCORE_FUNCTION_STUB_SIZE];
3214214571Sdim
3215214571Sdim      /* This symbol has a stub.  Set it up.  */
3216214571Sdim      BFD_ASSERT (h->dynindx != -1);
3217214571Sdim
3218214571Sdim      s = bfd_get_section_by_name (dynobj, SCORE_ELF_STUB_SECTION_NAME);
3219214571Sdim      BFD_ASSERT (s != NULL);
3220214571Sdim
3221214571Sdim      /* FIXME: Can h->dynindex be more than 64K?  */
3222214571Sdim      if (h->dynindx & 0xffff0000)
3223214571Sdim	return FALSE;
3224214571Sdim
3225214571Sdim      /* Fill the stub.  */
3226214571Sdim      bfd_put_32 (output_bfd, STUB_LW, stub);
3227214571Sdim      bfd_put_32 (output_bfd, STUB_MOVE, stub + 4);
3228214571Sdim      bfd_put_32 (output_bfd, STUB_LI16 | (h->dynindx << 1), stub + 8);
3229214571Sdim      bfd_put_32 (output_bfd, STUB_BRL, stub + 12);
3230214571Sdim
3231214571Sdim      BFD_ASSERT (h->plt.offset <= s->size);
3232214571Sdim      memcpy (s->contents + h->plt.offset, stub, SCORE_FUNCTION_STUB_SIZE);
3233214571Sdim
3234214571Sdim      /* Mark the symbol as undefined.  plt.offset != -1 occurs
3235214571Sdim	 only for the referenced symbol.  */
3236214571Sdim      sym->st_shndx = SHN_UNDEF;
3237214571Sdim
3238214571Sdim      /* The run-time linker uses the st_value field of the symbol
3239214571Sdim	  to reset the global offset table entry for this external
3240214571Sdim	  to its stub address when unlinking a shared object.  */
3241214571Sdim      sym->st_value = (s->output_section->vma + s->output_offset + h->plt.offset);
3242214571Sdim    }
3243214571Sdim
3244214571Sdim  BFD_ASSERT (h->dynindx != -1 || h->forced_local);
3245214571Sdim
3246214571Sdim  sgot = score_elf_got_section (dynobj, FALSE);
3247214571Sdim  BFD_ASSERT (sgot != NULL);
3248214571Sdim  BFD_ASSERT (score_elf_section_data (sgot) != NULL);
3249214571Sdim  g = score_elf_section_data (sgot)->u.got_info;
3250214571Sdim  BFD_ASSERT (g != NULL);
3251214571Sdim
3252214571Sdim  /* Run through the global symbol table, creating GOT entries for all
3253214571Sdim     the symbols that need them.  */
3254214571Sdim  if (g->global_gotsym != NULL && h->dynindx >= g->global_gotsym->dynindx)
3255214571Sdim    {
3256214571Sdim      bfd_vma offset;
3257214571Sdim      bfd_vma value;
3258214571Sdim
3259214571Sdim      value = sym->st_value;
3260214571Sdim      offset = score_elf_global_got_index (dynobj, h);
3261214571Sdim      bfd_put_32 (output_bfd, value, sgot->contents + offset);
3262214571Sdim    }
3263214571Sdim
3264214571Sdim  /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute.  */
3265214571Sdim  name = h->root.root.string;
3266214571Sdim  if (strcmp (name, "_DYNAMIC") == 0 || strcmp (name, "_GLOBAL_OFFSET_TABLE_") == 0)
3267214571Sdim    sym->st_shndx = SHN_ABS;
3268214571Sdim  else if (strcmp (name, "_DYNAMIC_LINK") == 0)
3269214571Sdim    {
3270214571Sdim      sym->st_shndx = SHN_ABS;
3271214571Sdim      sym->st_info = ELF_ST_INFO (STB_GLOBAL, STT_SECTION);
3272214571Sdim      sym->st_value = 1;
3273214571Sdim    }
3274214571Sdim  else if (strcmp (name, GP_DISP_LABEL) == 0)
3275214571Sdim    {
3276214571Sdim      sym->st_shndx = SHN_ABS;
3277214571Sdim      sym->st_info = ELF_ST_INFO (STB_GLOBAL, STT_SECTION);
3278214571Sdim      sym->st_value = elf_gp (output_bfd);
3279214571Sdim    }
3280214571Sdim
3281214571Sdim  return TRUE;
3282214571Sdim}
3283214571Sdim
3284214571Sdim/* Finish up the dynamic sections.  */
3285214571Sdim
3286214571Sdimstatic bfd_boolean
3287214571Sdim_bfd_score_elf_finish_dynamic_sections (bfd *output_bfd,
3288214571Sdim				        struct bfd_link_info *info)
3289214571Sdim{
3290214571Sdim  bfd *dynobj;
3291214571Sdim  asection *sdyn;
3292214571Sdim  asection *sgot;
3293214571Sdim  asection *s;
3294214571Sdim  struct score_got_info *g;
3295214571Sdim
3296214571Sdim  dynobj = elf_hash_table (info)->dynobj;
3297214571Sdim
3298214571Sdim  sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
3299214571Sdim
3300214571Sdim  sgot = score_elf_got_section (dynobj, FALSE);
3301214571Sdim  if (sgot == NULL)
3302214571Sdim    g = NULL;
3303214571Sdim  else
3304214571Sdim    {
3305214571Sdim      BFD_ASSERT (score_elf_section_data (sgot) != NULL);
3306214571Sdim      g = score_elf_section_data (sgot)->u.got_info;
3307214571Sdim      BFD_ASSERT (g != NULL);
3308214571Sdim    }
3309214571Sdim
3310214571Sdim  if (elf_hash_table (info)->dynamic_sections_created)
3311214571Sdim    {
3312214571Sdim      bfd_byte *b;
3313214571Sdim
3314214571Sdim      BFD_ASSERT (sdyn != NULL);
3315214571Sdim      BFD_ASSERT (g != NULL);
3316214571Sdim
3317214571Sdim      for (b = sdyn->contents;
3318214571Sdim	   b < sdyn->contents + sdyn->size;
3319214571Sdim	   b += SCORE_ELF_DYN_SIZE (dynobj))
3320214571Sdim	{
3321214571Sdim	  Elf_Internal_Dyn dyn;
3322214571Sdim	  const char *name;
3323214571Sdim	  size_t elemsize;
3324214571Sdim	  bfd_boolean swap_out_p;
3325214571Sdim
3326214571Sdim	  /* Read in the current dynamic entry.  */
3327214571Sdim	  (*get_elf_backend_data (dynobj)->s->swap_dyn_in) (dynobj, b, &dyn);
3328214571Sdim
3329214571Sdim	  /* Assume that we're going to modify it and write it out.  */
3330214571Sdim	  swap_out_p = TRUE;
3331214571Sdim
3332214571Sdim	  switch (dyn.d_tag)
3333214571Sdim	    {
3334214571Sdim	    case DT_RELENT:
3335214571Sdim	      s = score_elf_rel_dyn_section (dynobj, FALSE);
3336214571Sdim	      BFD_ASSERT (s != NULL);
3337214571Sdim	      dyn.d_un.d_val = SCORE_ELF_REL_SIZE (dynobj);
3338214571Sdim	      break;
3339214571Sdim
3340214571Sdim	    case DT_STRSZ:
3341214571Sdim	      /* Rewrite DT_STRSZ.  */
3342214571Sdim	      dyn.d_un.d_val = _bfd_elf_strtab_size (elf_hash_table (info)->dynstr);
3343214571Sdim		    break;
3344214571Sdim
3345214571Sdim	    case DT_PLTGOT:
3346214571Sdim	      name = ".got";
3347214571Sdim	      s = bfd_get_section_by_name (output_bfd, name);
3348214571Sdim	      BFD_ASSERT (s != NULL);
3349214571Sdim	      dyn.d_un.d_ptr = s->vma;
3350214571Sdim	      break;
3351214571Sdim
3352214571Sdim	    case DT_SCORE_BASE_ADDRESS:
3353214571Sdim	      s = output_bfd->sections;
3354214571Sdim	      BFD_ASSERT (s != NULL);
3355214571Sdim	      dyn.d_un.d_ptr = s->vma & ~(bfd_vma) 0xffff;
3356214571Sdim	      break;
3357214571Sdim
3358214571Sdim	    case DT_SCORE_LOCAL_GOTNO:
3359214571Sdim	      dyn.d_un.d_val = g->local_gotno;
3360214571Sdim	      break;
3361214571Sdim
3362214571Sdim	    case DT_SCORE_UNREFEXTNO:
3363214571Sdim	      /* The index into the dynamic symbol table which is the
3364214571Sdim		 entry of the first external symbol that is not
3365214571Sdim		 referenced within the same object.  */
3366214571Sdim	      dyn.d_un.d_val = bfd_count_sections (output_bfd) + 1;
3367214571Sdim	      break;
3368214571Sdim
3369214571Sdim	    case DT_SCORE_GOTSYM:
3370214571Sdim	      if (g->global_gotsym)
3371214571Sdim		{
3372214571Sdim		  dyn.d_un.d_val = g->global_gotsym->dynindx;
3373214571Sdim		  break;
3374214571Sdim		}
3375214571Sdim	      /* In case if we don't have global got symbols we default
3376214571Sdim		  to setting DT_SCORE_GOTSYM to the same value as
3377214571Sdim		  DT_SCORE_SYMTABNO, so we just fall through.  */
3378214571Sdim
3379214571Sdim	    case DT_SCORE_SYMTABNO:
3380214571Sdim	      name = ".dynsym";
3381214571Sdim	      elemsize = SCORE_ELF_SYM_SIZE (output_bfd);
3382214571Sdim	      s = bfd_get_section_by_name (output_bfd, name);
3383214571Sdim	      BFD_ASSERT (s != NULL);
3384214571Sdim
3385214571Sdim	      dyn.d_un.d_val = s->size / elemsize;
3386214571Sdim	      break;
3387214571Sdim
3388214571Sdim	    case DT_SCORE_HIPAGENO:
3389214571Sdim	      dyn.d_un.d_val = g->local_gotno - SCORE_RESERVED_GOTNO;
3390214571Sdim	      break;
3391214571Sdim
3392214571Sdim	    default:
3393214571Sdim	      swap_out_p = FALSE;
3394214571Sdim	      break;
3395214571Sdim	    }
3396214571Sdim
3397214571Sdim	  if (swap_out_p)
3398214571Sdim	    (*get_elf_backend_data (dynobj)->s->swap_dyn_out) (dynobj, &dyn, b);
3399214571Sdim	}
3400214571Sdim    }
3401214571Sdim
3402214571Sdim  /* The first entry of the global offset table will be filled at
3403214571Sdim     runtime. The second entry will be used by some runtime loaders.
3404214571Sdim     This isn't the case of IRIX rld.  */
3405214571Sdim  if (sgot != NULL && sgot->size > 0)
3406214571Sdim    {
3407214571Sdim      bfd_put_32 (output_bfd, 0, sgot->contents);
3408214571Sdim      bfd_put_32 (output_bfd, 0x80000000, sgot->contents + SCORE_ELF_GOT_SIZE (output_bfd));
3409214571Sdim    }
3410214571Sdim
3411214571Sdim  if (sgot != NULL)
3412214571Sdim    elf_section_data (sgot->output_section)->this_hdr.sh_entsize
3413214571Sdim      = SCORE_ELF_GOT_SIZE (output_bfd);
3414214571Sdim
3415214571Sdim
3416214571Sdim  /* We need to sort the entries of the dynamic relocation section.  */
3417214571Sdim  s = score_elf_rel_dyn_section (dynobj, FALSE);
3418214571Sdim
3419214571Sdim  if (s != NULL && s->size > (bfd_vma)2 * SCORE_ELF_REL_SIZE (output_bfd))
3420214571Sdim    {
3421214571Sdim      reldyn_sorting_bfd = output_bfd;
3422214571Sdim      qsort ((Elf32_External_Rel *) s->contents + 1, s->reloc_count - 1,
3423214571Sdim	     sizeof (Elf32_External_Rel), score_elf_sort_dynamic_relocs);
3424214571Sdim    }
3425214571Sdim
3426214571Sdim  return TRUE;
3427214571Sdim}
3428214571Sdim
3429214571Sdim/* This function set up the ELF section header for a BFD section in preparation for writing
3430214571Sdim   it out.  This is where the flags and type fields are set for unusual sections.  */
3431214571Sdim
3432214571Sdimstatic bfd_boolean
3433214571Sdim_bfd_score_elf_fake_sections (bfd *abfd ATTRIBUTE_UNUSED,
3434214571Sdim			      Elf_Internal_Shdr *hdr,
3435214571Sdim			      asection *sec)
3436214571Sdim{
3437214571Sdim  const char *name;
3438214571Sdim
3439214571Sdim  name = bfd_get_section_name (abfd, sec);
3440214571Sdim
3441214571Sdim  if (strcmp (name, ".got") == 0
3442214571Sdim      || strcmp (name, ".srdata") == 0
3443214571Sdim      || strcmp (name, ".sdata") == 0
3444214571Sdim      || strcmp (name, ".sbss") == 0)
3445214571Sdim    hdr->sh_flags |= SHF_SCORE_GPREL;
3446214571Sdim
3447214571Sdim  return TRUE;
3448214571Sdim}
3449214571Sdim
3450214571Sdim/* This function do additional processing on the ELF section header before writing
3451214571Sdim   it out.  This is used to set the flags and type fields for some sections.  */
3452214571Sdim
3453214571Sdim/* assign_file_positions_except_relocs() check section flag and if it is allocatable,
3454214571Sdim   warning message will be issued.  backend_fake_section is called before
3455214571Sdim   assign_file_positions_except_relocs(); backend_section_processing after it.  so, we
3456214571Sdim   modify section flag there, but not backend_fake_section.  */
3457214571Sdim
3458214571Sdimstatic bfd_boolean
3459214571Sdim_bfd_score_elf_section_processing (bfd *abfd ATTRIBUTE_UNUSED, Elf_Internal_Shdr *hdr)
3460214571Sdim{
3461214571Sdim  if (hdr->bfd_section != NULL)
3462214571Sdim    {
3463214571Sdim      const char *name = bfd_get_section_name (abfd, hdr->bfd_section);
3464214571Sdim
3465214571Sdim      if (strcmp (name, ".sdata") == 0)
3466214571Sdim	{
3467214571Sdim	  hdr->sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_SCORE_GPREL;
3468214571Sdim	  hdr->sh_type = SHT_PROGBITS;
3469214571Sdim	}
3470214571Sdim      else if (strcmp (name, ".sbss") == 0)
3471214571Sdim	{
3472214571Sdim	  hdr->sh_flags |= SHF_ALLOC | SHF_WRITE | SHF_SCORE_GPREL;
3473214571Sdim	  hdr->sh_type = SHT_NOBITS;
3474214571Sdim	}
3475214571Sdim      else if (strcmp (name, ".srdata") == 0)
3476214571Sdim	{
3477214571Sdim	  hdr->sh_flags |= SHF_ALLOC | SHF_SCORE_GPREL;
3478214571Sdim	  hdr->sh_type = SHT_PROGBITS;
3479214571Sdim	}
3480214571Sdim    }
3481214571Sdim
3482214571Sdim  return TRUE;
3483214571Sdim}
3484214571Sdim
3485214571Sdimstatic bfd_boolean
3486214571Sdim_bfd_score_elf_write_section (bfd *output_bfd,
3487214571Sdim			      struct bfd_link_info *link_info ATTRIBUTE_UNUSED,
3488214571Sdim                              asection *sec, bfd_byte *contents)
3489214571Sdim{
3490214571Sdim  bfd_byte *to, *from, *end;
3491214571Sdim  int i;
3492214571Sdim
3493214571Sdim  if (strcmp (sec->name, ".pdr") != 0)
3494214571Sdim    return FALSE;
3495214571Sdim
3496214571Sdim  if (score_elf_section_data (sec)->u.tdata == NULL)
3497214571Sdim    return FALSE;
3498214571Sdim
3499214571Sdim  to = contents;
3500214571Sdim  end = contents + sec->size;
3501214571Sdim  for (from = contents, i = 0; from < end; from += PDR_SIZE, i++)
3502214571Sdim    {
3503214571Sdim      if ((score_elf_section_data (sec)->u.tdata)[i] == 1)
3504214571Sdim        continue;
3505214571Sdim
3506214571Sdim      if (to != from)
3507214571Sdim        memcpy (to, from, PDR_SIZE);
3508214571Sdim
3509214571Sdim      to += PDR_SIZE;
3510214571Sdim    }
3511214571Sdim  bfd_set_section_contents (output_bfd, sec->output_section, contents,
3512214571Sdim                            (file_ptr) sec->output_offset, sec->size);
3513214571Sdim
3514214571Sdim  return TRUE;
3515214571Sdim}
3516214571Sdim
3517214571Sdim/* Copy data from a SCORE ELF indirect symbol to its direct symbol, hiding the old
3518214571Sdim   indirect symbol.  Process additional relocation information.  */
3519214571Sdim
3520214571Sdimstatic void
3521214571Sdim_bfd_score_elf_copy_indirect_symbol (struct bfd_link_info *info,
3522214571Sdim				     struct elf_link_hash_entry *dir,
3523214571Sdim				     struct elf_link_hash_entry *ind)
3524214571Sdim{
3525214571Sdim  struct score_elf_link_hash_entry *dirscore, *indscore;
3526214571Sdim
3527214571Sdim  _bfd_elf_link_hash_copy_indirect (info, dir, ind);
3528214571Sdim
3529214571Sdim  if (ind->root.type != bfd_link_hash_indirect)
3530214571Sdim    return;
3531214571Sdim
3532214571Sdim  dirscore = (struct score_elf_link_hash_entry *) dir;
3533214571Sdim  indscore = (struct score_elf_link_hash_entry *) ind;
3534214571Sdim  dirscore->possibly_dynamic_relocs += indscore->possibly_dynamic_relocs;
3535214571Sdim
3536214571Sdim  if (indscore->readonly_reloc)
3537214571Sdim    dirscore->readonly_reloc = TRUE;
3538214571Sdim
3539214571Sdim  if (indscore->no_fn_stub)
3540214571Sdim    dirscore->no_fn_stub = TRUE;
3541214571Sdim}
3542214571Sdim
3543214571Sdim/* Remove information about discarded functions from other sections which mention them.  */
3544214571Sdim
3545214571Sdimstatic bfd_boolean
3546214571Sdim_bfd_score_elf_discard_info (bfd *abfd, struct elf_reloc_cookie *cookie,
3547214571Sdim                         struct bfd_link_info *info)
3548214571Sdim{
3549214571Sdim  asection *o;
3550214571Sdim  bfd_boolean ret = FALSE;
3551214571Sdim  unsigned char *tdata;
3552214571Sdim  size_t i, skip;
3553214571Sdim
3554214571Sdim  o = bfd_get_section_by_name (abfd, ".pdr");
3555214571Sdim  if ((!o) || (o->size == 0) || (o->size % PDR_SIZE != 0)
3556214571Sdim      || (o->output_section != NULL && bfd_is_abs_section (o->output_section)))
3557214571Sdim    return FALSE;
3558214571Sdim
3559214571Sdim  tdata = bfd_zmalloc (o->size / PDR_SIZE);
3560214571Sdim  if (!tdata)
3561214571Sdim    return FALSE;
3562214571Sdim
3563214571Sdim  cookie->rels = _bfd_elf_link_read_relocs (abfd, o, NULL, NULL, info->keep_memory);
3564214571Sdim  if (!cookie->rels)
3565214571Sdim    {
3566214571Sdim      free (tdata);
3567214571Sdim      return FALSE;
3568214571Sdim    }
3569214571Sdim
3570214571Sdim  cookie->rel = cookie->rels;
3571214571Sdim  cookie->relend = cookie->rels + o->reloc_count;
3572214571Sdim
3573214571Sdim  for (i = 0, skip = 0; i < o->size; i++)
3574214571Sdim    {
3575214571Sdim      if (bfd_elf_reloc_symbol_deleted_p (i * PDR_SIZE, cookie))
3576214571Sdim        {
3577214571Sdim          tdata[i] = 1;
3578214571Sdim          skip++;
3579214571Sdim        }
3580214571Sdim    }
3581214571Sdim
3582214571Sdim  if (skip != 0)
3583214571Sdim    {
3584214571Sdim      score_elf_section_data (o)->u.tdata = tdata;
3585214571Sdim      o->size -= skip * PDR_SIZE;
3586214571Sdim      ret = TRUE;
3587214571Sdim    }
3588214571Sdim  else
3589214571Sdim    free (tdata);
3590214571Sdim
3591214571Sdim  if (!info->keep_memory)
3592214571Sdim    free (cookie->rels);
3593214571Sdim
3594214571Sdim  return ret;
3595214571Sdim}
3596214571Sdim
3597214571Sdim/* Signal that discard_info() has removed the discarded relocations for this section.  */
3598214571Sdim
3599214571Sdimstatic bfd_boolean
3600214571Sdim_bfd_score_elf_ignore_discarded_relocs (asection *sec)
3601214571Sdim{
3602214571Sdim  if (strcmp (sec->name, ".pdr") == 0)
3603214571Sdim    return TRUE;
3604214571Sdim  return FALSE;
3605214571Sdim}
3606214571Sdim
3607214571Sdim/* Return the section that should be marked against GC for a given
3608214571Sdim   relocation.  */
3609214571Sdim
3610214571Sdimstatic asection *
3611214571Sdim_bfd_score_elf_gc_mark_hook (asection *sec,
3612214571Sdim			     struct bfd_link_info *info,
3613214571Sdim			     Elf_Internal_Rela *rel,
3614214571Sdim			     struct elf_link_hash_entry *h,
3615214571Sdim			     Elf_Internal_Sym *sym)
3616214571Sdim{
3617214571Sdim  if (h != NULL)
3618214571Sdim    switch (ELF32_R_TYPE (rel->r_info))
3619214571Sdim      {
3620214571Sdim      case R_SCORE_GNU_VTINHERIT:
3621214571Sdim      case R_SCORE_GNU_VTENTRY:
3622214571Sdim	return NULL;
3623214571Sdim      }
3624214571Sdim
3625214571Sdim  return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
3626214571Sdim}
3627214571Sdim
3628214571Sdim/* Support for core dump NOTE sections.  */
3629214571Sdim
3630214571Sdimstatic bfd_boolean
3631214571Sdim_bfd_score_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
3632214571Sdim{
3633214571Sdim  int offset;
3634214571Sdim  unsigned int raw_size;
3635214571Sdim
3636214571Sdim  switch (note->descsz)
3637214571Sdim    {
3638214571Sdim    default:
3639214571Sdim      return FALSE;
3640214571Sdim
3641214571Sdim    case 148:                  /* Linux/Score 32-bit.  */
3642214571Sdim      /* pr_cursig */
3643214571Sdim      elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12);
3644214571Sdim
3645214571Sdim      /* pr_pid */
3646214571Sdim      elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 24);
3647214571Sdim
3648214571Sdim      /* pr_reg */
3649214571Sdim      offset = 72;
3650214571Sdim      raw_size = 72;
3651214571Sdim
3652214571Sdim      break;
3653214571Sdim    }
3654214571Sdim
3655214571Sdim  /* Make a ".reg/999" section.  */
3656214571Sdim  return _bfd_elfcore_make_pseudosection (abfd, ".reg", raw_size, note->descpos + offset);
3657214571Sdim}
3658214571Sdim
3659214571Sdimstatic bfd_boolean
3660214571Sdim_bfd_score_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
3661214571Sdim{
3662214571Sdim  switch (note->descsz)
3663214571Sdim    {
3664214571Sdim    default:
3665214571Sdim      return FALSE;
3666214571Sdim
3667214571Sdim    case 124:                  /* Linux/Score elf_prpsinfo.  */
3668214571Sdim      elf_tdata (abfd)->core_program = _bfd_elfcore_strndup (abfd, note->descdata + 28, 16);
3669214571Sdim      elf_tdata (abfd)->core_command = _bfd_elfcore_strndup (abfd, note->descdata + 44, 80);
3670214571Sdim    }
3671214571Sdim
3672214571Sdim  /* Note that for some reason, a spurious space is tacked
3673214571Sdim     onto the end of the args in some (at least one anyway)
3674214571Sdim     implementations, so strip it off if it exists.  */
3675214571Sdim
3676214571Sdim  {
3677214571Sdim    char *command = elf_tdata (abfd)->core_command;
3678214571Sdim    int n = strlen (command);
3679214571Sdim
3680214571Sdim    if (0 < n && command[n - 1] == ' ')
3681214571Sdim      command[n - 1] = '\0';
3682214571Sdim  }
3683214571Sdim
3684214571Sdim  return TRUE;
3685214571Sdim}
3686214571Sdim
3687214571Sdim
3688214571Sdim/* Score BFD functions.  */
3689214571Sdim
3690214571Sdimstatic reloc_howto_type *
3691214571Sdimelf32_score_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, bfd_reloc_code_real_type code)
3692214571Sdim{
3693214571Sdim  unsigned int i;
3694214571Sdim
3695214571Sdim  for (i = 0; i < NUM_ELEM (elf32_score_reloc_map); i++)
3696214571Sdim    if (elf32_score_reloc_map[i].bfd_reloc_val == code)
3697214571Sdim      return &elf32_score_howto_table[elf32_score_reloc_map[i].elf_reloc_val];
3698214571Sdim
3699214571Sdim  return NULL;
3700214571Sdim}
3701214571Sdim
3702214571Sdimstatic reloc_howto_type *
3703214571Sdimelf32_score_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
3704214571Sdim			       const char *r_name)
3705214571Sdim{
3706214571Sdim  unsigned int i;
3707214571Sdim
3708214571Sdim  for (i = 0;
3709214571Sdim       i < (sizeof (elf32_score_howto_table)
3710214571Sdim	    / sizeof (elf32_score_howto_table[0]));
3711214571Sdim       i++)
3712214571Sdim    if (elf32_score_howto_table[i].name != NULL
3713214571Sdim	&& strcasecmp (elf32_score_howto_table[i].name, r_name) == 0)
3714214571Sdim      return &elf32_score_howto_table[i];
3715214571Sdim
3716214571Sdim  return NULL;
3717214571Sdim}
3718214571Sdim
3719214571Sdim/* Create a score elf linker hash table.  */
3720214571Sdim
3721214571Sdimstatic struct bfd_link_hash_table *
3722214571Sdimelf32_score_link_hash_table_create (bfd *abfd)
3723214571Sdim{
3724214571Sdim  struct score_elf_link_hash_table *ret;
3725214571Sdim  bfd_size_type amt = sizeof (struct score_elf_link_hash_table);
3726214571Sdim
3727214571Sdim  ret = bfd_malloc (amt);
3728214571Sdim  if (ret == NULL)
3729214571Sdim    return NULL;
3730214571Sdim
3731214571Sdim  if (!_bfd_elf_link_hash_table_init (&ret->root, abfd, score_elf_link_hash_newfunc,
3732214571Sdim				      sizeof (struct score_elf_link_hash_entry)))
3733214571Sdim    {
3734214571Sdim      free (ret);
3735214571Sdim      return NULL;
3736214571Sdim    }
3737214571Sdim
3738214571Sdim  return &ret->root.root;
3739214571Sdim}
3740214571Sdim
3741214571Sdimstatic bfd_boolean
3742214571Sdimelf32_score_print_private_bfd_data (bfd *abfd, void * ptr)
3743214571Sdim{
3744214571Sdim  FILE *file = (FILE *) ptr;
3745214571Sdim
3746214571Sdim  BFD_ASSERT (abfd != NULL && ptr != NULL);
3747214571Sdim
3748214571Sdim  /* Print normal ELF private data.  */
3749214571Sdim  _bfd_elf_print_private_bfd_data (abfd, ptr);
3750214571Sdim
3751214571Sdim  /* xgettext:c-format */
3752214571Sdim  fprintf (file, _("private flags = %lx:"), elf_elfheader (abfd)->e_flags);
3753214571Sdim  if (elf_elfheader (abfd)->e_flags & EF_SCORE_PIC)
3754214571Sdim    {
3755214571Sdim      fprintf (file, _(" [pic]"));
3756214571Sdim    }
3757214571Sdim  if (elf_elfheader (abfd)->e_flags & EF_SCORE_FIXDEP)
3758214571Sdim    {
3759214571Sdim      fprintf (file, _(" [fix dep]"));
3760214571Sdim    }
3761214571Sdim  fputc ('\n', file);
3762214571Sdim
3763214571Sdim  return TRUE;
3764214571Sdim}
3765214571Sdim
3766214571Sdimstatic bfd_boolean
3767214571Sdimelf32_score_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
3768214571Sdim{
3769214571Sdim  flagword in_flags;
3770214571Sdim  flagword out_flags;
3771214571Sdim
3772214571Sdim  if (!_bfd_generic_verify_endian_match (ibfd, obfd))
3773214571Sdim    return FALSE;
3774214571Sdim
3775214571Sdim  in_flags  = elf_elfheader (ibfd)->e_flags;
3776214571Sdim  out_flags = elf_elfheader (obfd)->e_flags;
3777214571Sdim
3778214571Sdim  if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
3779214571Sdim      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
3780214571Sdim    return TRUE;
3781214571Sdim
3782214571Sdim  in_flags = elf_elfheader (ibfd)->e_flags;
3783214571Sdim  out_flags = elf_elfheader (obfd)->e_flags;
3784214571Sdim
3785214571Sdim  if (! elf_flags_init (obfd))
3786214571Sdim    {
3787214571Sdim      elf_flags_init (obfd) = TRUE;
3788214571Sdim      elf_elfheader (obfd)->e_flags = in_flags;
3789214571Sdim
3790214571Sdim      if (bfd_get_arch (obfd) == bfd_get_arch (ibfd)
3791214571Sdim	  && bfd_get_arch_info (obfd)->the_default)
3792214571Sdim	{
3793214571Sdim	  return bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), bfd_get_mach (ibfd));
3794214571Sdim	}
3795214571Sdim
3796214571Sdim      return TRUE;
3797214571Sdim    }
3798214571Sdim
3799214571Sdim  if (((in_flags & EF_SCORE_PIC) != 0) != ((out_flags & EF_SCORE_PIC) != 0))
3800214571Sdim    {
3801214571Sdim      (*_bfd_error_handler) (_("%B: warning: linking PIC files with non-PIC files"), ibfd);
3802214571Sdim    }
3803214571Sdim
3804214571Sdim  /* FIXME: Maybe dependency fix compatibility should be checked here.  */
3805214571Sdim
3806214571Sdim  return TRUE;
3807214571Sdim}
3808214571Sdim
3809214571Sdimstatic bfd_boolean
3810214571Sdimelf32_score_new_section_hook (bfd *abfd, asection *sec)
3811214571Sdim{
3812214571Sdim  struct _score_elf_section_data *sdata;
3813214571Sdim  bfd_size_type amt = sizeof (*sdata);
3814214571Sdim
3815214571Sdim  sdata = bfd_zalloc (abfd, amt);
3816214571Sdim  if (sdata == NULL)
3817214571Sdim    return FALSE;
3818214571Sdim  sec->used_by_bfd = sdata;
3819214571Sdim
3820214571Sdim  return _bfd_elf_new_section_hook (abfd, sec);
3821214571Sdim}
3822214571Sdim
3823214571Sdim
3824214571Sdim#define USE_REL                         1
3825214571Sdim#define TARGET_LITTLE_SYM               bfd_elf32_littlescore_vec
3826214571Sdim#define TARGET_LITTLE_NAME              "elf32-littlescore"
3827214571Sdim#define TARGET_BIG_SYM                  bfd_elf32_bigscore_vec
3828214571Sdim#define TARGET_BIG_NAME                 "elf32-bigscore"
3829214571Sdim#define ELF_ARCH                        bfd_arch_score
3830214571Sdim#define ELF_MACHINE_CODE                EM_SCORE
3831214571Sdim#define ELF_MAXPAGESIZE                 0x8000
3832214571Sdim
3833214571Sdim#define elf_info_to_howto               0
3834214571Sdim#define elf_info_to_howto_rel           _bfd_score_info_to_howto
3835214571Sdim#define elf_backend_relocate_section    _bfd_score_elf_relocate_section
3836214571Sdim#define elf_backend_check_relocs        _bfd_score_elf_check_relocs
3837214571Sdim#define elf_backend_add_symbol_hook     _bfd_score_elf_add_symbol_hook
3838214571Sdim#define elf_backend_symbol_processing   _bfd_score_elf_symbol_processing
3839214571Sdim#define elf_backend_link_output_symbol_hook \
3840214571Sdim  _bfd_score_elf_link_output_symbol_hook
3841214571Sdim#define elf_backend_section_from_bfd_section \
3842214571Sdim  _bfd_score_elf_section_from_bfd_section
3843214571Sdim#define elf_backend_adjust_dynamic_symbol \
3844214571Sdim  _bfd_score_elf_adjust_dynamic_symbol
3845214571Sdim#define elf_backend_always_size_sections \
3846214571Sdim  _bfd_score_elf_always_size_sections
3847214571Sdim#define elf_backend_size_dynamic_sections \
3848214571Sdim  _bfd_score_elf_size_dynamic_sections
3849214571Sdim#define elf_backend_omit_section_dynsym \
3850214571Sdim  ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true)
3851214571Sdim#define elf_backend_create_dynamic_sections \
3852214571Sdim  _bfd_score_elf_create_dynamic_sections
3853214571Sdim#define elf_backend_finish_dynamic_symbol \
3854214571Sdim  _bfd_score_elf_finish_dynamic_symbol
3855214571Sdim#define elf_backend_finish_dynamic_sections \
3856214571Sdim  _bfd_score_elf_finish_dynamic_sections
3857214571Sdim#define elf_backend_fake_sections         _bfd_score_elf_fake_sections
3858214571Sdim#define elf_backend_section_processing    _bfd_score_elf_section_processing
3859214571Sdim#define elf_backend_write_section         _bfd_score_elf_write_section
3860214571Sdim#define elf_backend_copy_indirect_symbol  _bfd_score_elf_copy_indirect_symbol
3861214571Sdim#define elf_backend_hide_symbol           _bfd_score_elf_hide_symbol
3862214571Sdim#define elf_backend_discard_info          _bfd_score_elf_discard_info
3863214571Sdim#define elf_backend_ignore_discarded_relocs \
3864214571Sdim  _bfd_score_elf_ignore_discarded_relocs
3865214571Sdim#define elf_backend_gc_mark_hook          _bfd_score_elf_gc_mark_hook
3866214571Sdim#define elf_backend_grok_prstatus         _bfd_score_elf_grok_prstatus
3867214571Sdim#define elf_backend_grok_psinfo           _bfd_score_elf_grok_psinfo
3868214571Sdim#define elf_backend_can_gc_sections       1
3869214571Sdim#define elf_backend_want_plt_sym          0
3870214571Sdim#define elf_backend_got_header_size       (4 * SCORE_RESERVED_GOTNO)
3871214571Sdim#define elf_backend_plt_header_size       0
3872214571Sdim#define elf_backend_collect               TRUE
3873214571Sdim#define elf_backend_type_change_ok        TRUE
3874214571Sdim
3875214571Sdim#define bfd_elf32_bfd_reloc_type_lookup      elf32_score_reloc_type_lookup
3876214571Sdim#define bfd_elf32_bfd_reloc_name_lookup \
3877214571Sdim  elf32_score_reloc_name_lookup
3878214571Sdim#define bfd_elf32_bfd_link_hash_table_create elf32_score_link_hash_table_create
3879214571Sdim#define bfd_elf32_bfd_print_private_bfd_data elf32_score_print_private_bfd_data
3880214571Sdim#define bfd_elf32_bfd_merge_private_bfd_data elf32_score_merge_private_bfd_data
3881214571Sdim#define bfd_elf32_new_section_hook           elf32_score_new_section_hook
3882214571Sdim
3883214571Sdim#include "elf32-target.h"
3884