xref: /openbsd-src/gnu/usr.bin/binutils/bfd/elf64-mmix.c (revision cf2f2c5620d6d9a4fd01930983c4b9a1f76d7aa3)
1d2201f2fSdrahn /* MMIX-specific support for 64-bit ELF.
2*cf2f2c56Smiod    Copyright 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
3d2201f2fSdrahn    Contributed by Hans-Peter Nilsson <hp@bitrange.com>
4d2201f2fSdrahn 
5d2201f2fSdrahn This file is part of BFD, the Binary File Descriptor library.
6d2201f2fSdrahn 
7d2201f2fSdrahn This program is free software; you can redistribute it and/or modify
8d2201f2fSdrahn it under the terms of the GNU General Public License as published by
9d2201f2fSdrahn the Free Software Foundation; either version 2 of the License, or
10d2201f2fSdrahn (at your option) any later version.
11d2201f2fSdrahn 
12d2201f2fSdrahn This program is distributed in the hope that it will be useful,
13d2201f2fSdrahn but WITHOUT ANY WARRANTY; without even the implied warranty of
14d2201f2fSdrahn MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15d2201f2fSdrahn GNU General Public License for more details.
16d2201f2fSdrahn 
17d2201f2fSdrahn You should have received a copy of the GNU General Public License
18d2201f2fSdrahn along with this program; if not, write to the Free Software
19d2201f2fSdrahn Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20d2201f2fSdrahn 
21d2201f2fSdrahn /* No specific ABI or "processor-specific supplement" defined.  */
22d2201f2fSdrahn 
23d2201f2fSdrahn /* TODO:
24*cf2f2c56Smiod    - "Traditional" linker relaxation (shrinking whole sections).
25*cf2f2c56Smiod    - Merge reloc stubs jumping to same location.
26*cf2f2c56Smiod    - GETA stub relaxation (call a stub for out of range new
27*cf2f2c56Smiod      R_MMIX_GETA_STUBBABLE).  */
28d2201f2fSdrahn 
29d2201f2fSdrahn #include "bfd.h"
30d2201f2fSdrahn #include "sysdep.h"
31d2201f2fSdrahn #include "libbfd.h"
32d2201f2fSdrahn #include "elf-bfd.h"
33d2201f2fSdrahn #include "elf/mmix.h"
34d2201f2fSdrahn #include "opcode/mmix.h"
35d2201f2fSdrahn 
36d2201f2fSdrahn #define MINUS_ONE	(((bfd_vma) 0) - 1)
37d2201f2fSdrahn 
38*cf2f2c56Smiod #define MAX_PUSHJ_STUB_SIZE (5 * 4)
39*cf2f2c56Smiod 
40d2201f2fSdrahn /* Put these everywhere in new code.  */
41d2201f2fSdrahn #define FATAL_DEBUG						\
42d2201f2fSdrahn  _bfd_abort (__FILE__, __LINE__,				\
43d2201f2fSdrahn 	     "Internal: Non-debugged code (test-case missing)")
44d2201f2fSdrahn 
45d2201f2fSdrahn #define BAD_CASE(x)				\
46d2201f2fSdrahn  _bfd_abort (__FILE__, __LINE__,		\
47d2201f2fSdrahn 	     "bad case for " #x)
48d2201f2fSdrahn 
49d2201f2fSdrahn struct _mmix_elf_section_data
50d2201f2fSdrahn {
51d2201f2fSdrahn   struct bfd_elf_section_data elf;
52d2201f2fSdrahn   union
53d2201f2fSdrahn   {
54d2201f2fSdrahn     struct bpo_reloc_section_info *reloc;
55d2201f2fSdrahn     struct bpo_greg_section_info *greg;
56d2201f2fSdrahn   } bpo;
57*cf2f2c56Smiod 
58*cf2f2c56Smiod   struct pushj_stub_info
59*cf2f2c56Smiod   {
60*cf2f2c56Smiod     /* Maximum number of stubs needed for this section.  */
61*cf2f2c56Smiod     bfd_size_type n_pushj_relocs;
62*cf2f2c56Smiod 
63*cf2f2c56Smiod     /* Size of stubs after a mmix_elf_relax_section round.  */
64*cf2f2c56Smiod     bfd_size_type stubs_size_sum;
65*cf2f2c56Smiod 
66*cf2f2c56Smiod     /* Per-reloc stubs_size_sum information.  The stubs_size_sum member is the sum
67*cf2f2c56Smiod        of these.  Allocated in mmix_elf_check_common_relocs.  */
68*cf2f2c56Smiod     bfd_size_type *stub_size;
69*cf2f2c56Smiod 
70*cf2f2c56Smiod     /* Offset of next stub during relocation.  Somewhat redundant with the
71*cf2f2c56Smiod        above: error coverage is easier and we don't have to reset the
72*cf2f2c56Smiod        stubs_size_sum for relocation.  */
73*cf2f2c56Smiod     bfd_size_type stub_offset;
74*cf2f2c56Smiod   } pjs;
75d2201f2fSdrahn };
76d2201f2fSdrahn 
77d2201f2fSdrahn #define mmix_elf_section_data(sec) \
78d2201f2fSdrahn   ((struct _mmix_elf_section_data *) elf_section_data (sec))
79d2201f2fSdrahn 
80d2201f2fSdrahn /* For each section containing a base-plus-offset (BPO) reloc, we attach
81d2201f2fSdrahn    this struct as mmix_elf_section_data (section)->bpo, which is otherwise
82d2201f2fSdrahn    NULL.  */
83d2201f2fSdrahn struct bpo_reloc_section_info
84d2201f2fSdrahn   {
85d2201f2fSdrahn     /* The base is 1; this is the first number in this section.  */
86d2201f2fSdrahn     size_t first_base_plus_offset_reloc;
87d2201f2fSdrahn 
88d2201f2fSdrahn     /* Number of BPO-relocs in this section.  */
89d2201f2fSdrahn     size_t n_bpo_relocs_this_section;
90d2201f2fSdrahn 
91d2201f2fSdrahn     /* Running index, used at relocation time.  */
92d2201f2fSdrahn     size_t bpo_index;
93d2201f2fSdrahn 
94d2201f2fSdrahn     /* We don't have access to the bfd_link_info struct in
95d2201f2fSdrahn        mmix_final_link_relocate.  What we really want to get at is the
96d2201f2fSdrahn        global single struct greg_relocation, so we stash it here.  */
97d2201f2fSdrahn     asection *bpo_greg_section;
98d2201f2fSdrahn   };
99d2201f2fSdrahn 
100d2201f2fSdrahn /* Helper struct (in global context) for the one below.
101d2201f2fSdrahn    There's one of these created for every BPO reloc.  */
102d2201f2fSdrahn struct bpo_reloc_request
103d2201f2fSdrahn   {
104d2201f2fSdrahn     bfd_vma value;
105d2201f2fSdrahn 
106d2201f2fSdrahn     /* Valid after relaxation.  The base is 0; the first register number
107d2201f2fSdrahn        must be added.  The offset is in range 0..255.  */
108d2201f2fSdrahn     size_t regindex;
109d2201f2fSdrahn     size_t offset;
110d2201f2fSdrahn 
111d2201f2fSdrahn     /* The order number for this BPO reloc, corresponding to the order in
112d2201f2fSdrahn        which BPO relocs were found.  Used to create an index after reloc
113d2201f2fSdrahn        requests are sorted.  */
114d2201f2fSdrahn     size_t bpo_reloc_no;
115d2201f2fSdrahn 
116d2201f2fSdrahn     /* Set when the value is computed.  Better than coding "guard values"
117d2201f2fSdrahn        into the other members.  Is FALSE only for BPO relocs in a GC:ed
118d2201f2fSdrahn        section.  */
119d2201f2fSdrahn     bfd_boolean valid;
120d2201f2fSdrahn   };
121d2201f2fSdrahn 
122d2201f2fSdrahn /* We attach this as mmix_elf_section_data (sec)->bpo in the linker-allocated
123d2201f2fSdrahn    greg contents section (MMIX_LD_ALLOCATED_REG_CONTENTS_SECTION_NAME),
124d2201f2fSdrahn    which is linked into the register contents section
125d2201f2fSdrahn    (MMIX_REG_CONTENTS_SECTION_NAME).  This section is created by the
126d2201f2fSdrahn    linker; using the same hook as for usual with BPO relocs does not
127d2201f2fSdrahn    collide.  */
128d2201f2fSdrahn struct bpo_greg_section_info
129d2201f2fSdrahn   {
130d2201f2fSdrahn     /* After GC, this reflects the number of remaining, non-excluded
131d2201f2fSdrahn        BPO-relocs.  */
132d2201f2fSdrahn     size_t n_bpo_relocs;
133d2201f2fSdrahn 
134d2201f2fSdrahn     /* This is the number of allocated bpo_reloc_requests; the size of
135d2201f2fSdrahn        sorted_indexes.  Valid after the check.*relocs functions are called
136d2201f2fSdrahn        for all incoming sections.  It includes the number of BPO relocs in
137d2201f2fSdrahn        sections that were GC:ed.  */
138d2201f2fSdrahn     size_t n_max_bpo_relocs;
139d2201f2fSdrahn 
140d2201f2fSdrahn     /* A counter used to find out when to fold the BPO gregs, since we
141d2201f2fSdrahn        don't have a single "after-relaxation" hook.  */
142d2201f2fSdrahn     size_t n_remaining_bpo_relocs_this_relaxation_round;
143d2201f2fSdrahn 
144d2201f2fSdrahn     /* The number of linker-allocated GREGs resulting from BPO relocs.
145*cf2f2c56Smiod        This is an approximation after _bfd_mmix_before_linker_allocation
146*cf2f2c56Smiod        and supposedly accurate after mmix_elf_relax_section is called for
147*cf2f2c56Smiod        all incoming non-collected sections.  */
148d2201f2fSdrahn     size_t n_allocated_bpo_gregs;
149d2201f2fSdrahn 
150d2201f2fSdrahn     /* Index into reloc_request[], sorted on increasing "value", secondary
151d2201f2fSdrahn        by increasing index for strict sorting order.  */
152d2201f2fSdrahn     size_t *bpo_reloc_indexes;
153d2201f2fSdrahn 
154d2201f2fSdrahn     /* An array of all relocations, with the "value" member filled in by
155d2201f2fSdrahn        the relaxation function.  */
156d2201f2fSdrahn     struct bpo_reloc_request *reloc_request;
157d2201f2fSdrahn   };
158d2201f2fSdrahn 
159d2201f2fSdrahn static bfd_boolean mmix_elf_link_output_symbol_hook
160*cf2f2c56Smiod   PARAMS ((struct bfd_link_info *, const char *, Elf_Internal_Sym *,
161*cf2f2c56Smiod 	   asection *, struct elf_link_hash_entry *));
162d2201f2fSdrahn 
163d2201f2fSdrahn static bfd_reloc_status_type mmix_elf_reloc
164d2201f2fSdrahn   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
165d2201f2fSdrahn 
166d2201f2fSdrahn static reloc_howto_type *bfd_elf64_bfd_reloc_type_lookup
167d2201f2fSdrahn   PARAMS ((bfd *, bfd_reloc_code_real_type));
168d2201f2fSdrahn 
169d2201f2fSdrahn static void mmix_info_to_howto_rela
170d2201f2fSdrahn   PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
171d2201f2fSdrahn 
172d2201f2fSdrahn static int mmix_elf_sort_relocs PARAMS ((const PTR, const PTR));
173d2201f2fSdrahn 
174d2201f2fSdrahn static bfd_boolean mmix_elf_new_section_hook
175d2201f2fSdrahn   PARAMS ((bfd *, asection *));
176d2201f2fSdrahn 
177d2201f2fSdrahn static bfd_boolean mmix_elf_check_relocs
178d2201f2fSdrahn   PARAMS ((bfd *, struct bfd_link_info *, asection *,
179d2201f2fSdrahn 	   const Elf_Internal_Rela *));
180d2201f2fSdrahn 
181d2201f2fSdrahn static bfd_boolean mmix_elf_check_common_relocs
182d2201f2fSdrahn   PARAMS ((bfd *, struct bfd_link_info *, asection *,
183d2201f2fSdrahn 	   const Elf_Internal_Rela *));
184d2201f2fSdrahn 
185d2201f2fSdrahn static bfd_boolean mmix_elf_relocate_section
186d2201f2fSdrahn   PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
187d2201f2fSdrahn 	   Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
188d2201f2fSdrahn 
189d2201f2fSdrahn static asection * mmix_elf_gc_mark_hook
190d2201f2fSdrahn   PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *,
191d2201f2fSdrahn 	   struct elf_link_hash_entry *, Elf_Internal_Sym *));
192d2201f2fSdrahn 
193d2201f2fSdrahn static bfd_boolean mmix_elf_gc_sweep_hook
194d2201f2fSdrahn   PARAMS ((bfd *, struct bfd_link_info *, asection *,
195d2201f2fSdrahn 	   const Elf_Internal_Rela *));
196d2201f2fSdrahn 
197d2201f2fSdrahn static bfd_reloc_status_type mmix_final_link_relocate
198d2201f2fSdrahn   PARAMS ((reloc_howto_type *, asection *, bfd_byte *,
199d2201f2fSdrahn 	   bfd_vma, bfd_signed_vma, bfd_vma, const char *, asection *));
200d2201f2fSdrahn 
201d2201f2fSdrahn static bfd_reloc_status_type mmix_elf_perform_relocation
202d2201f2fSdrahn   PARAMS ((asection *, reloc_howto_type *, PTR, bfd_vma, bfd_vma));
203d2201f2fSdrahn 
204d2201f2fSdrahn static bfd_boolean mmix_elf_section_from_bfd_section
205d2201f2fSdrahn   PARAMS ((bfd *, asection *, int *));
206d2201f2fSdrahn 
207d2201f2fSdrahn static bfd_boolean mmix_elf_add_symbol_hook
208*cf2f2c56Smiod   PARAMS ((bfd *, struct bfd_link_info *, Elf_Internal_Sym *,
209d2201f2fSdrahn 	   const char **, flagword *, asection **, bfd_vma *));
210d2201f2fSdrahn 
211d2201f2fSdrahn static bfd_boolean mmix_elf_is_local_label_name
212d2201f2fSdrahn   PARAMS ((bfd *, const char *));
213d2201f2fSdrahn 
214d2201f2fSdrahn static int bpo_reloc_request_sort_fn PARAMS ((const PTR, const PTR));
215d2201f2fSdrahn 
216d2201f2fSdrahn static bfd_boolean mmix_elf_relax_section
217d2201f2fSdrahn   PARAMS ((bfd *abfd, asection *sec, struct bfd_link_info *link_info,
218d2201f2fSdrahn 	   bfd_boolean *again));
219d2201f2fSdrahn 
220d2201f2fSdrahn extern bfd_boolean mmix_elf_final_link PARAMS ((bfd *, struct bfd_link_info *));
221d2201f2fSdrahn 
222d2201f2fSdrahn extern void mmix_elf_symbol_processing PARAMS ((bfd *, asymbol *));
223d2201f2fSdrahn 
224d2201f2fSdrahn /* Only intended to be called from a debugger.  */
225d2201f2fSdrahn extern void mmix_dump_bpo_gregs
226d2201f2fSdrahn   PARAMS ((struct bfd_link_info *, bfd_error_handler_type));
227d2201f2fSdrahn 
228*cf2f2c56Smiod static void
229*cf2f2c56Smiod mmix_set_relaxable_size
230*cf2f2c56Smiod   PARAMS ((bfd *, asection *, void *));
231*cf2f2c56Smiod 
232*cf2f2c56Smiod static bfd_boolean
233*cf2f2c56Smiod mmix_elf_get_section_contents
234*cf2f2c56Smiod   PARAMS ((bfd *, sec_ptr, void *, file_ptr, bfd_size_type));
235*cf2f2c56Smiod 
236*cf2f2c56Smiod 
237d2201f2fSdrahn /* Watch out: this currently needs to have elements with the same index as
238d2201f2fSdrahn    their R_MMIX_ number.  */
239d2201f2fSdrahn static reloc_howto_type elf_mmix_howto_table[] =
240d2201f2fSdrahn  {
241d2201f2fSdrahn   /* This reloc does nothing.  */
242d2201f2fSdrahn   HOWTO (R_MMIX_NONE,		/* type */
243d2201f2fSdrahn 	 0,			/* rightshift */
244d2201f2fSdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
245d2201f2fSdrahn 	 32,			/* bitsize */
246d2201f2fSdrahn 	 FALSE,			/* pc_relative */
247d2201f2fSdrahn 	 0,			/* bitpos */
248d2201f2fSdrahn 	 complain_overflow_bitfield, /* complain_on_overflow */
249d2201f2fSdrahn 	 bfd_elf_generic_reloc,	/* special_function */
250d2201f2fSdrahn 	 "R_MMIX_NONE",		/* name */
251d2201f2fSdrahn 	 FALSE,			/* partial_inplace */
252d2201f2fSdrahn 	 0,			/* src_mask */
253d2201f2fSdrahn 	 0,			/* dst_mask */
254d2201f2fSdrahn 	 FALSE),		/* pcrel_offset */
255d2201f2fSdrahn 
256d2201f2fSdrahn   /* An 8 bit absolute relocation.  */
257d2201f2fSdrahn   HOWTO (R_MMIX_8,		/* type */
258d2201f2fSdrahn 	 0,			/* rightshift */
259d2201f2fSdrahn 	 0,			/* size (0 = byte, 1 = short, 2 = long) */
260d2201f2fSdrahn 	 8,			/* bitsize */
261d2201f2fSdrahn 	 FALSE,			/* pc_relative */
262d2201f2fSdrahn 	 0,			/* bitpos */
263d2201f2fSdrahn 	 complain_overflow_bitfield, /* complain_on_overflow */
264d2201f2fSdrahn 	 bfd_elf_generic_reloc,	/* special_function */
265d2201f2fSdrahn 	 "R_MMIX_8",		/* name */
266d2201f2fSdrahn 	 FALSE,			/* partial_inplace */
267d2201f2fSdrahn 	 0,			/* src_mask */
268d2201f2fSdrahn 	 0xff,			/* dst_mask */
269d2201f2fSdrahn 	 FALSE),		/* pcrel_offset */
270d2201f2fSdrahn 
271d2201f2fSdrahn   /* An 16 bit absolute relocation.  */
272d2201f2fSdrahn   HOWTO (R_MMIX_16,		/* type */
273d2201f2fSdrahn 	 0,			/* rightshift */
274d2201f2fSdrahn 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
275d2201f2fSdrahn 	 16,			/* bitsize */
276d2201f2fSdrahn 	 FALSE,			/* pc_relative */
277d2201f2fSdrahn 	 0,			/* bitpos */
278d2201f2fSdrahn 	 complain_overflow_bitfield, /* complain_on_overflow */
279d2201f2fSdrahn 	 bfd_elf_generic_reloc,	/* special_function */
280d2201f2fSdrahn 	 "R_MMIX_16",		/* name */
281d2201f2fSdrahn 	 FALSE,			/* partial_inplace */
282d2201f2fSdrahn 	 0,			/* src_mask */
283d2201f2fSdrahn 	 0xffff,		/* dst_mask */
284d2201f2fSdrahn 	 FALSE),		/* pcrel_offset */
285d2201f2fSdrahn 
286d2201f2fSdrahn   /* An 24 bit absolute relocation.  */
287d2201f2fSdrahn   HOWTO (R_MMIX_24,		/* type */
288d2201f2fSdrahn 	 0,			/* rightshift */
289d2201f2fSdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
290d2201f2fSdrahn 	 24,			/* bitsize */
291d2201f2fSdrahn 	 FALSE,			/* pc_relative */
292d2201f2fSdrahn 	 0,			/* bitpos */
293d2201f2fSdrahn 	 complain_overflow_bitfield, /* complain_on_overflow */
294d2201f2fSdrahn 	 bfd_elf_generic_reloc,	/* special_function */
295d2201f2fSdrahn 	 "R_MMIX_24",		/* name */
296d2201f2fSdrahn 	 FALSE,			/* partial_inplace */
297d2201f2fSdrahn 	 ~0xffffff,		/* src_mask */
298d2201f2fSdrahn 	 0xffffff,		/* dst_mask */
299d2201f2fSdrahn 	 FALSE),		/* pcrel_offset */
300d2201f2fSdrahn 
301d2201f2fSdrahn   /* A 32 bit absolute relocation.  */
302d2201f2fSdrahn   HOWTO (R_MMIX_32,		/* type */
303d2201f2fSdrahn 	 0,			/* rightshift */
304d2201f2fSdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
305d2201f2fSdrahn 	 32,			/* bitsize */
306d2201f2fSdrahn 	 FALSE,			/* pc_relative */
307d2201f2fSdrahn 	 0,			/* bitpos */
308d2201f2fSdrahn 	 complain_overflow_bitfield, /* complain_on_overflow */
309d2201f2fSdrahn 	 bfd_elf_generic_reloc,	/* special_function */
310d2201f2fSdrahn 	 "R_MMIX_32",		/* name */
311d2201f2fSdrahn 	 FALSE,			/* partial_inplace */
312d2201f2fSdrahn 	 0,			/* src_mask */
313d2201f2fSdrahn 	 0xffffffff,		/* dst_mask */
314d2201f2fSdrahn 	 FALSE),		/* pcrel_offset */
315d2201f2fSdrahn 
316d2201f2fSdrahn   /* 64 bit relocation.  */
317d2201f2fSdrahn   HOWTO (R_MMIX_64,		/* type */
318d2201f2fSdrahn 	 0,			/* rightshift */
319d2201f2fSdrahn 	 4,			/* size (0 = byte, 1 = short, 2 = long) */
320d2201f2fSdrahn 	 64,			/* bitsize */
321d2201f2fSdrahn 	 FALSE,			/* pc_relative */
322d2201f2fSdrahn 	 0,			/* bitpos */
323d2201f2fSdrahn 	 complain_overflow_bitfield, /* complain_on_overflow */
324d2201f2fSdrahn 	 bfd_elf_generic_reloc,	/* special_function */
325d2201f2fSdrahn 	 "R_MMIX_64",		/* name */
326d2201f2fSdrahn 	 FALSE,			/* partial_inplace */
327d2201f2fSdrahn 	 0,			/* src_mask */
328d2201f2fSdrahn 	 MINUS_ONE,		/* dst_mask */
329d2201f2fSdrahn 	 FALSE),		/* pcrel_offset */
330d2201f2fSdrahn 
331d2201f2fSdrahn   /* An 8 bit PC-relative relocation.  */
332d2201f2fSdrahn   HOWTO (R_MMIX_PC_8,		/* type */
333d2201f2fSdrahn 	 0,			/* rightshift */
334d2201f2fSdrahn 	 0,			/* size (0 = byte, 1 = short, 2 = long) */
335d2201f2fSdrahn 	 8,			/* bitsize */
336d2201f2fSdrahn 	 TRUE,			/* pc_relative */
337d2201f2fSdrahn 	 0,			/* bitpos */
338d2201f2fSdrahn 	 complain_overflow_bitfield, /* complain_on_overflow */
339d2201f2fSdrahn 	 bfd_elf_generic_reloc,	/* special_function */
340d2201f2fSdrahn 	 "R_MMIX_PC_8",		/* name */
341d2201f2fSdrahn 	 FALSE,			/* partial_inplace */
342d2201f2fSdrahn 	 0,			/* src_mask */
343d2201f2fSdrahn 	 0xff,			/* dst_mask */
344d2201f2fSdrahn 	 TRUE),			/* pcrel_offset */
345d2201f2fSdrahn 
346d2201f2fSdrahn   /* An 16 bit PC-relative relocation.  */
347d2201f2fSdrahn   HOWTO (R_MMIX_PC_16,		/* type */
348d2201f2fSdrahn 	 0,			/* rightshift */
349d2201f2fSdrahn 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
350d2201f2fSdrahn 	 16,			/* bitsize */
351d2201f2fSdrahn 	 TRUE,			/* pc_relative */
352d2201f2fSdrahn 	 0,			/* bitpos */
353d2201f2fSdrahn 	 complain_overflow_bitfield, /* complain_on_overflow */
354d2201f2fSdrahn 	 bfd_elf_generic_reloc,	/* special_function */
355d2201f2fSdrahn 	 "R_MMIX_PC_16",	/* name */
356d2201f2fSdrahn 	 FALSE,			/* partial_inplace */
357d2201f2fSdrahn 	 0,			/* src_mask */
358d2201f2fSdrahn 	 0xffff,		/* dst_mask */
359d2201f2fSdrahn 	 TRUE),			/* pcrel_offset */
360d2201f2fSdrahn 
361d2201f2fSdrahn   /* An 24 bit PC-relative relocation.  */
362d2201f2fSdrahn   HOWTO (R_MMIX_PC_24,		/* type */
363d2201f2fSdrahn 	 0,			/* rightshift */
364d2201f2fSdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
365d2201f2fSdrahn 	 24,			/* bitsize */
366d2201f2fSdrahn 	 TRUE,			/* pc_relative */
367d2201f2fSdrahn 	 0,			/* bitpos */
368d2201f2fSdrahn 	 complain_overflow_bitfield, /* complain_on_overflow */
369d2201f2fSdrahn 	 bfd_elf_generic_reloc,	/* special_function */
370d2201f2fSdrahn 	 "R_MMIX_PC_24",	/* name */
371d2201f2fSdrahn 	 FALSE,			/* partial_inplace */
372d2201f2fSdrahn 	 ~0xffffff,		/* src_mask */
373d2201f2fSdrahn 	 0xffffff,		/* dst_mask */
374d2201f2fSdrahn 	 TRUE),			/* pcrel_offset */
375d2201f2fSdrahn 
376d2201f2fSdrahn   /* A 32 bit absolute PC-relative relocation.  */
377d2201f2fSdrahn   HOWTO (R_MMIX_PC_32,		/* type */
378d2201f2fSdrahn 	 0,			/* rightshift */
379d2201f2fSdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
380d2201f2fSdrahn 	 32,			/* bitsize */
381d2201f2fSdrahn 	 TRUE,			/* pc_relative */
382d2201f2fSdrahn 	 0,			/* bitpos */
383d2201f2fSdrahn 	 complain_overflow_bitfield, /* complain_on_overflow */
384d2201f2fSdrahn 	 bfd_elf_generic_reloc,	/* special_function */
385d2201f2fSdrahn 	 "R_MMIX_PC_32",	/* name */
386d2201f2fSdrahn 	 FALSE,			/* partial_inplace */
387d2201f2fSdrahn 	 0,			/* src_mask */
388d2201f2fSdrahn 	 0xffffffff,		/* dst_mask */
389d2201f2fSdrahn 	 TRUE),			/* pcrel_offset */
390d2201f2fSdrahn 
391d2201f2fSdrahn   /* 64 bit PC-relative relocation.  */
392d2201f2fSdrahn   HOWTO (R_MMIX_PC_64,		/* type */
393d2201f2fSdrahn 	 0,			/* rightshift */
394d2201f2fSdrahn 	 4,			/* size (0 = byte, 1 = short, 2 = long) */
395d2201f2fSdrahn 	 64,			/* bitsize */
396d2201f2fSdrahn 	 TRUE,			/* pc_relative */
397d2201f2fSdrahn 	 0,			/* bitpos */
398d2201f2fSdrahn 	 complain_overflow_bitfield, /* complain_on_overflow */
399d2201f2fSdrahn 	 bfd_elf_generic_reloc,	/* special_function */
400d2201f2fSdrahn 	 "R_MMIX_PC_64",	/* name */
401d2201f2fSdrahn 	 FALSE,			/* partial_inplace */
402d2201f2fSdrahn 	 0,			/* src_mask */
403d2201f2fSdrahn 	 MINUS_ONE,		/* dst_mask */
404d2201f2fSdrahn 	 TRUE),			/* pcrel_offset */
405d2201f2fSdrahn 
406d2201f2fSdrahn   /* GNU extension to record C++ vtable hierarchy.  */
407d2201f2fSdrahn   HOWTO (R_MMIX_GNU_VTINHERIT, /* type */
408d2201f2fSdrahn 	 0,			/* rightshift */
409d2201f2fSdrahn 	 0,			/* size (0 = byte, 1 = short, 2 = long) */
410d2201f2fSdrahn 	 0,			/* bitsize */
411d2201f2fSdrahn 	 FALSE,			/* pc_relative */
412d2201f2fSdrahn 	 0,			/* bitpos */
413d2201f2fSdrahn 	 complain_overflow_dont, /* complain_on_overflow */
414d2201f2fSdrahn 	 NULL,			/* special_function */
415d2201f2fSdrahn 	 "R_MMIX_GNU_VTINHERIT", /* name */
416d2201f2fSdrahn 	 FALSE,			/* partial_inplace */
417d2201f2fSdrahn 	 0,			/* src_mask */
418d2201f2fSdrahn 	 0,			/* dst_mask */
419d2201f2fSdrahn 	 TRUE),			/* pcrel_offset */
420d2201f2fSdrahn 
421d2201f2fSdrahn   /* GNU extension to record C++ vtable member usage.  */
422d2201f2fSdrahn   HOWTO (R_MMIX_GNU_VTENTRY,	/* type */
423d2201f2fSdrahn 	 0,			/* rightshift */
424d2201f2fSdrahn 	 0,			/* size (0 = byte, 1 = short, 2 = long) */
425d2201f2fSdrahn 	 0,			/* bitsize */
426d2201f2fSdrahn 	 FALSE,			/* pc_relative */
427d2201f2fSdrahn 	 0,			/* bitpos */
428d2201f2fSdrahn 	 complain_overflow_dont, /* complain_on_overflow */
429d2201f2fSdrahn 	 _bfd_elf_rel_vtable_reloc_fn,	/* special_function */
430d2201f2fSdrahn 	 "R_MMIX_GNU_VTENTRY", /* name */
431d2201f2fSdrahn 	 FALSE,			/* partial_inplace */
432d2201f2fSdrahn 	 0,			/* src_mask */
433d2201f2fSdrahn 	 0,			/* dst_mask */
434d2201f2fSdrahn 	 FALSE),		/* pcrel_offset */
435d2201f2fSdrahn 
436d2201f2fSdrahn   /* The GETA relocation is supposed to get any address that could
437d2201f2fSdrahn      possibly be reached by the GETA instruction.  It can silently expand
438d2201f2fSdrahn      to get a 64-bit operand, but will complain if any of the two least
439d2201f2fSdrahn      significant bits are set.  The howto members reflect a simple GETA.  */
440d2201f2fSdrahn   HOWTO (R_MMIX_GETA,		/* type */
441d2201f2fSdrahn 	 2,			/* rightshift */
442d2201f2fSdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
443d2201f2fSdrahn 	 19,			/* bitsize */
444d2201f2fSdrahn 	 TRUE,			/* pc_relative */
445d2201f2fSdrahn 	 0,			/* bitpos */
446d2201f2fSdrahn 	 complain_overflow_signed, /* complain_on_overflow */
447d2201f2fSdrahn 	 mmix_elf_reloc,	/* special_function */
448d2201f2fSdrahn 	 "R_MMIX_GETA",		/* name */
449d2201f2fSdrahn 	 FALSE,			/* partial_inplace */
450d2201f2fSdrahn 	 ~0x0100ffff,		/* src_mask */
451d2201f2fSdrahn 	 0x0100ffff,		/* dst_mask */
452d2201f2fSdrahn 	 TRUE),			/* pcrel_offset */
453d2201f2fSdrahn 
454d2201f2fSdrahn   HOWTO (R_MMIX_GETA_1,		/* type */
455d2201f2fSdrahn 	 2,			/* rightshift */
456d2201f2fSdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
457d2201f2fSdrahn 	 19,			/* bitsize */
458d2201f2fSdrahn 	 TRUE,			/* pc_relative */
459d2201f2fSdrahn 	 0,			/* bitpos */
460d2201f2fSdrahn 	 complain_overflow_signed, /* complain_on_overflow */
461d2201f2fSdrahn 	 mmix_elf_reloc,	/* special_function */
462d2201f2fSdrahn 	 "R_MMIX_GETA_1",		/* name */
463d2201f2fSdrahn 	 FALSE,			/* partial_inplace */
464d2201f2fSdrahn 	 ~0x0100ffff,		/* src_mask */
465d2201f2fSdrahn 	 0x0100ffff,		/* dst_mask */
466d2201f2fSdrahn 	 TRUE),			/* pcrel_offset */
467d2201f2fSdrahn 
468d2201f2fSdrahn   HOWTO (R_MMIX_GETA_2,		/* type */
469d2201f2fSdrahn 	 2,			/* rightshift */
470d2201f2fSdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
471d2201f2fSdrahn 	 19,			/* bitsize */
472d2201f2fSdrahn 	 TRUE,			/* pc_relative */
473d2201f2fSdrahn 	 0,			/* bitpos */
474d2201f2fSdrahn 	 complain_overflow_signed, /* complain_on_overflow */
475d2201f2fSdrahn 	 mmix_elf_reloc,	/* special_function */
476d2201f2fSdrahn 	 "R_MMIX_GETA_2",		/* name */
477d2201f2fSdrahn 	 FALSE,			/* partial_inplace */
478d2201f2fSdrahn 	 ~0x0100ffff,		/* src_mask */
479d2201f2fSdrahn 	 0x0100ffff,		/* dst_mask */
480d2201f2fSdrahn 	 TRUE),			/* pcrel_offset */
481d2201f2fSdrahn 
482d2201f2fSdrahn   HOWTO (R_MMIX_GETA_3,		/* type */
483d2201f2fSdrahn 	 2,			/* rightshift */
484d2201f2fSdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
485d2201f2fSdrahn 	 19,			/* bitsize */
486d2201f2fSdrahn 	 TRUE,			/* pc_relative */
487d2201f2fSdrahn 	 0,			/* bitpos */
488d2201f2fSdrahn 	 complain_overflow_signed, /* complain_on_overflow */
489d2201f2fSdrahn 	 mmix_elf_reloc,	/* special_function */
490d2201f2fSdrahn 	 "R_MMIX_GETA_3",		/* name */
491d2201f2fSdrahn 	 FALSE,			/* partial_inplace */
492d2201f2fSdrahn 	 ~0x0100ffff,		/* src_mask */
493d2201f2fSdrahn 	 0x0100ffff,		/* dst_mask */
494d2201f2fSdrahn 	 TRUE),			/* pcrel_offset */
495d2201f2fSdrahn 
496d2201f2fSdrahn   /* The conditional branches are supposed to reach any (code) address.
497d2201f2fSdrahn      It can silently expand to a 64-bit operand, but will emit an error if
498d2201f2fSdrahn      any of the two least significant bits are set.  The howto members
499d2201f2fSdrahn      reflect a simple branch.  */
500d2201f2fSdrahn   HOWTO (R_MMIX_CBRANCH,	/* type */
501d2201f2fSdrahn 	 2,			/* rightshift */
502d2201f2fSdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
503d2201f2fSdrahn 	 19,			/* bitsize */
504d2201f2fSdrahn 	 TRUE,			/* pc_relative */
505d2201f2fSdrahn 	 0,			/* bitpos */
506d2201f2fSdrahn 	 complain_overflow_signed, /* complain_on_overflow */
507d2201f2fSdrahn 	 mmix_elf_reloc,	/* special_function */
508d2201f2fSdrahn 	 "R_MMIX_CBRANCH",	/* name */
509d2201f2fSdrahn 	 FALSE,			/* partial_inplace */
510d2201f2fSdrahn 	 ~0x0100ffff,		/* src_mask */
511d2201f2fSdrahn 	 0x0100ffff,		/* dst_mask */
512d2201f2fSdrahn 	 TRUE),		       	/* pcrel_offset */
513d2201f2fSdrahn 
514d2201f2fSdrahn   HOWTO (R_MMIX_CBRANCH_J,	/* type */
515d2201f2fSdrahn 	 2,			/* rightshift */
516d2201f2fSdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
517d2201f2fSdrahn 	 19,			/* bitsize */
518d2201f2fSdrahn 	 TRUE,			/* pc_relative */
519d2201f2fSdrahn 	 0,			/* bitpos */
520d2201f2fSdrahn 	 complain_overflow_signed, /* complain_on_overflow */
521d2201f2fSdrahn 	 mmix_elf_reloc,	/* special_function */
522d2201f2fSdrahn 	 "R_MMIX_CBRANCH_J",	/* name */
523d2201f2fSdrahn 	 FALSE,			/* partial_inplace */
524d2201f2fSdrahn 	 ~0x0100ffff,		/* src_mask */
525d2201f2fSdrahn 	 0x0100ffff,		/* dst_mask */
526d2201f2fSdrahn 	 TRUE),			/* pcrel_offset */
527d2201f2fSdrahn 
528d2201f2fSdrahn   HOWTO (R_MMIX_CBRANCH_1,	/* type */
529d2201f2fSdrahn 	 2,			/* rightshift */
530d2201f2fSdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
531d2201f2fSdrahn 	 19,			/* bitsize */
532d2201f2fSdrahn 	 TRUE,			/* pc_relative */
533d2201f2fSdrahn 	 0,			/* bitpos */
534d2201f2fSdrahn 	 complain_overflow_signed, /* complain_on_overflow */
535d2201f2fSdrahn 	 mmix_elf_reloc,	/* special_function */
536d2201f2fSdrahn 	 "R_MMIX_CBRANCH_1",	/* name */
537d2201f2fSdrahn 	 FALSE,			/* partial_inplace */
538d2201f2fSdrahn 	 ~0x0100ffff,		/* src_mask */
539d2201f2fSdrahn 	 0x0100ffff,		/* dst_mask */
540d2201f2fSdrahn 	 TRUE),			/* pcrel_offset */
541d2201f2fSdrahn 
542d2201f2fSdrahn   HOWTO (R_MMIX_CBRANCH_2,	/* type */
543d2201f2fSdrahn 	 2,			/* rightshift */
544d2201f2fSdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
545d2201f2fSdrahn 	 19,			/* bitsize */
546d2201f2fSdrahn 	 TRUE,			/* pc_relative */
547d2201f2fSdrahn 	 0,			/* bitpos */
548d2201f2fSdrahn 	 complain_overflow_signed, /* complain_on_overflow */
549d2201f2fSdrahn 	 mmix_elf_reloc,	/* special_function */
550d2201f2fSdrahn 	 "R_MMIX_CBRANCH_2",	/* name */
551d2201f2fSdrahn 	 FALSE,			/* partial_inplace */
552d2201f2fSdrahn 	 ~0x0100ffff,		/* src_mask */
553d2201f2fSdrahn 	 0x0100ffff,		/* dst_mask */
554d2201f2fSdrahn 	 TRUE),			/* pcrel_offset */
555d2201f2fSdrahn 
556d2201f2fSdrahn   HOWTO (R_MMIX_CBRANCH_3,	/* type */
557d2201f2fSdrahn 	 2,			/* rightshift */
558d2201f2fSdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
559d2201f2fSdrahn 	 19,			/* bitsize */
560d2201f2fSdrahn 	 TRUE,			/* pc_relative */
561d2201f2fSdrahn 	 0,			/* bitpos */
562d2201f2fSdrahn 	 complain_overflow_signed, /* complain_on_overflow */
563d2201f2fSdrahn 	 mmix_elf_reloc,	/* special_function */
564d2201f2fSdrahn 	 "R_MMIX_CBRANCH_3",	/* name */
565d2201f2fSdrahn 	 FALSE,			/* partial_inplace */
566d2201f2fSdrahn 	 ~0x0100ffff,		/* src_mask */
567d2201f2fSdrahn 	 0x0100ffff,		/* dst_mask */
568d2201f2fSdrahn 	 TRUE),			/* pcrel_offset */
569d2201f2fSdrahn 
570d2201f2fSdrahn   /* The PUSHJ instruction can reach any (code) address, as long as it's
571d2201f2fSdrahn      the beginning of a function (no usable restriction).  It can silently
572d2201f2fSdrahn      expand to a 64-bit operand, but will emit an error if any of the two
573*cf2f2c56Smiod      least significant bits are set.  It can also expand into a call to a
574*cf2f2c56Smiod      stub; see R_MMIX_PUSHJ_STUBBABLE.  The howto members reflect a simple
575d2201f2fSdrahn      PUSHJ.  */
576d2201f2fSdrahn   HOWTO (R_MMIX_PUSHJ,		/* type */
577d2201f2fSdrahn 	 2,			/* rightshift */
578d2201f2fSdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
579d2201f2fSdrahn 	 19,			/* bitsize */
580d2201f2fSdrahn 	 TRUE,			/* pc_relative */
581d2201f2fSdrahn 	 0,			/* bitpos */
582d2201f2fSdrahn 	 complain_overflow_signed, /* complain_on_overflow */
583d2201f2fSdrahn 	 mmix_elf_reloc,	/* special_function */
584d2201f2fSdrahn 	 "R_MMIX_PUSHJ",	/* name */
585d2201f2fSdrahn 	 FALSE,			/* partial_inplace */
586d2201f2fSdrahn 	 ~0x0100ffff,		/* src_mask */
587d2201f2fSdrahn 	 0x0100ffff,		/* dst_mask */
588d2201f2fSdrahn 	 TRUE),			/* pcrel_offset */
589d2201f2fSdrahn 
590d2201f2fSdrahn   HOWTO (R_MMIX_PUSHJ_1,	/* type */
591d2201f2fSdrahn 	 2,			/* rightshift */
592d2201f2fSdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
593d2201f2fSdrahn 	 19,			/* bitsize */
594d2201f2fSdrahn 	 TRUE,			/* pc_relative */
595d2201f2fSdrahn 	 0,			/* bitpos */
596d2201f2fSdrahn 	 complain_overflow_signed, /* complain_on_overflow */
597d2201f2fSdrahn 	 mmix_elf_reloc,	/* special_function */
598d2201f2fSdrahn 	 "R_MMIX_PUSHJ_1",	/* name */
599d2201f2fSdrahn 	 FALSE,			/* partial_inplace */
600d2201f2fSdrahn 	 ~0x0100ffff,		/* src_mask */
601d2201f2fSdrahn 	 0x0100ffff,		/* dst_mask */
602d2201f2fSdrahn 	 TRUE),			/* pcrel_offset */
603d2201f2fSdrahn 
604d2201f2fSdrahn   HOWTO (R_MMIX_PUSHJ_2,	/* type */
605d2201f2fSdrahn 	 2,			/* rightshift */
606d2201f2fSdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
607d2201f2fSdrahn 	 19,			/* bitsize */
608d2201f2fSdrahn 	 TRUE,			/* pc_relative */
609d2201f2fSdrahn 	 0,			/* bitpos */
610d2201f2fSdrahn 	 complain_overflow_signed, /* complain_on_overflow */
611d2201f2fSdrahn 	 mmix_elf_reloc,	/* special_function */
612d2201f2fSdrahn 	 "R_MMIX_PUSHJ_2",	/* name */
613d2201f2fSdrahn 	 FALSE,			/* partial_inplace */
614d2201f2fSdrahn 	 ~0x0100ffff,		/* src_mask */
615d2201f2fSdrahn 	 0x0100ffff,		/* dst_mask */
616d2201f2fSdrahn 	 TRUE),			/* pcrel_offset */
617d2201f2fSdrahn 
618d2201f2fSdrahn   HOWTO (R_MMIX_PUSHJ_3,	/* type */
619d2201f2fSdrahn 	 2,			/* rightshift */
620d2201f2fSdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
621d2201f2fSdrahn 	 19,			/* bitsize */
622d2201f2fSdrahn 	 TRUE,			/* pc_relative */
623d2201f2fSdrahn 	 0,			/* bitpos */
624d2201f2fSdrahn 	 complain_overflow_signed, /* complain_on_overflow */
625d2201f2fSdrahn 	 mmix_elf_reloc,	/* special_function */
626d2201f2fSdrahn 	 "R_MMIX_PUSHJ_3",	/* name */
627d2201f2fSdrahn 	 FALSE,			/* partial_inplace */
628d2201f2fSdrahn 	 ~0x0100ffff,		/* src_mask */
629d2201f2fSdrahn 	 0x0100ffff,		/* dst_mask */
630d2201f2fSdrahn 	 TRUE),			/* pcrel_offset */
631d2201f2fSdrahn 
632d2201f2fSdrahn   /* A JMP is supposed to reach any (code) address.  By itself, it can
633d2201f2fSdrahn      reach +-64M; the expansion can reach all 64 bits.  Note that the 64M
634d2201f2fSdrahn      limit is soon reached if you link the program in wildly different
635d2201f2fSdrahn      memory segments.  The howto members reflect a trivial JMP.  */
636d2201f2fSdrahn   HOWTO (R_MMIX_JMP,		/* type */
637d2201f2fSdrahn 	 2,			/* rightshift */
638d2201f2fSdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
639d2201f2fSdrahn 	 27,			/* bitsize */
640d2201f2fSdrahn 	 TRUE,			/* pc_relative */
641d2201f2fSdrahn 	 0,			/* bitpos */
642d2201f2fSdrahn 	 complain_overflow_signed, /* complain_on_overflow */
643d2201f2fSdrahn 	 mmix_elf_reloc,	/* special_function */
644d2201f2fSdrahn 	 "R_MMIX_JMP",		/* name */
645d2201f2fSdrahn 	 FALSE,			/* partial_inplace */
646d2201f2fSdrahn 	 ~0x1ffffff,		/* src_mask */
647d2201f2fSdrahn 	 0x1ffffff,		/* dst_mask */
648d2201f2fSdrahn 	 TRUE),			/* pcrel_offset */
649d2201f2fSdrahn 
650d2201f2fSdrahn   HOWTO (R_MMIX_JMP_1,		/* type */
651d2201f2fSdrahn 	 2,			/* rightshift */
652d2201f2fSdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
653d2201f2fSdrahn 	 27,			/* bitsize */
654d2201f2fSdrahn 	 TRUE,			/* pc_relative */
655d2201f2fSdrahn 	 0,			/* bitpos */
656d2201f2fSdrahn 	 complain_overflow_signed, /* complain_on_overflow */
657d2201f2fSdrahn 	 mmix_elf_reloc,	/* special_function */
658d2201f2fSdrahn 	 "R_MMIX_JMP_1",	/* name */
659d2201f2fSdrahn 	 FALSE,			/* partial_inplace */
660d2201f2fSdrahn 	 ~0x1ffffff,		/* src_mask */
661d2201f2fSdrahn 	 0x1ffffff,		/* dst_mask */
662d2201f2fSdrahn 	 TRUE),			/* pcrel_offset */
663d2201f2fSdrahn 
664d2201f2fSdrahn   HOWTO (R_MMIX_JMP_2,		/* type */
665d2201f2fSdrahn 	 2,			/* rightshift */
666d2201f2fSdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
667d2201f2fSdrahn 	 27,			/* bitsize */
668d2201f2fSdrahn 	 TRUE,			/* pc_relative */
669d2201f2fSdrahn 	 0,			/* bitpos */
670d2201f2fSdrahn 	 complain_overflow_signed, /* complain_on_overflow */
671d2201f2fSdrahn 	 mmix_elf_reloc,	/* special_function */
672d2201f2fSdrahn 	 "R_MMIX_JMP_2",	/* name */
673d2201f2fSdrahn 	 FALSE,			/* partial_inplace */
674d2201f2fSdrahn 	 ~0x1ffffff,		/* src_mask */
675d2201f2fSdrahn 	 0x1ffffff,		/* dst_mask */
676d2201f2fSdrahn 	 TRUE),			/* pcrel_offset */
677d2201f2fSdrahn 
678d2201f2fSdrahn   HOWTO (R_MMIX_JMP_3,		/* type */
679d2201f2fSdrahn 	 2,			/* rightshift */
680d2201f2fSdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
681d2201f2fSdrahn 	 27,			/* bitsize */
682d2201f2fSdrahn 	 TRUE,			/* pc_relative */
683d2201f2fSdrahn 	 0,			/* bitpos */
684d2201f2fSdrahn 	 complain_overflow_signed, /* complain_on_overflow */
685d2201f2fSdrahn 	 mmix_elf_reloc,	/* special_function */
686d2201f2fSdrahn 	 "R_MMIX_JMP_3",	/* name */
687d2201f2fSdrahn 	 FALSE,			/* partial_inplace */
688d2201f2fSdrahn 	 ~0x1ffffff,		/* src_mask */
689d2201f2fSdrahn 	 0x1ffffff,		/* dst_mask */
690d2201f2fSdrahn 	 TRUE),			/* pcrel_offset */
691d2201f2fSdrahn 
692d2201f2fSdrahn   /* When we don't emit link-time-relaxable code from the assembler, or
693d2201f2fSdrahn      when relaxation has done all it can do, these relocs are used.  For
694d2201f2fSdrahn      GETA/PUSHJ/branches.  */
695d2201f2fSdrahn   HOWTO (R_MMIX_ADDR19,		/* type */
696d2201f2fSdrahn 	 2,			/* rightshift */
697d2201f2fSdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
698d2201f2fSdrahn 	 19,			/* bitsize */
699d2201f2fSdrahn 	 TRUE,			/* pc_relative */
700d2201f2fSdrahn 	 0,			/* bitpos */
701d2201f2fSdrahn 	 complain_overflow_signed, /* complain_on_overflow */
702d2201f2fSdrahn 	 mmix_elf_reloc,	/* special_function */
703d2201f2fSdrahn 	 "R_MMIX_ADDR19",	/* name */
704d2201f2fSdrahn 	 FALSE,			/* partial_inplace */
705d2201f2fSdrahn 	 ~0x0100ffff,		/* src_mask */
706d2201f2fSdrahn 	 0x0100ffff,		/* dst_mask */
707d2201f2fSdrahn 	 TRUE),			/* pcrel_offset */
708d2201f2fSdrahn 
709d2201f2fSdrahn   /* For JMP.  */
710d2201f2fSdrahn   HOWTO (R_MMIX_ADDR27,		/* type */
711d2201f2fSdrahn 	 2,			/* rightshift */
712d2201f2fSdrahn 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
713d2201f2fSdrahn 	 27,			/* bitsize */
714d2201f2fSdrahn 	 TRUE,			/* pc_relative */
715d2201f2fSdrahn 	 0,			/* bitpos */
716d2201f2fSdrahn 	 complain_overflow_signed, /* complain_on_overflow */
717d2201f2fSdrahn 	 mmix_elf_reloc,	/* special_function */
718d2201f2fSdrahn 	 "R_MMIX_ADDR27",	/* name */
719d2201f2fSdrahn 	 FALSE,			/* partial_inplace */
720d2201f2fSdrahn 	 ~0x1ffffff,		/* src_mask */
721d2201f2fSdrahn 	 0x1ffffff,		/* dst_mask */
722d2201f2fSdrahn 	 TRUE),			/* pcrel_offset */
723d2201f2fSdrahn 
724d2201f2fSdrahn   /* A general register or the value 0..255.  If a value, then the
725d2201f2fSdrahn      instruction (offset -3) needs adjusting.  */
726d2201f2fSdrahn   HOWTO (R_MMIX_REG_OR_BYTE,	/* type */
727d2201f2fSdrahn 	 0,			/* rightshift */
728d2201f2fSdrahn 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
729d2201f2fSdrahn 	 8,			/* bitsize */
730d2201f2fSdrahn 	 FALSE,			/* pc_relative */
731d2201f2fSdrahn 	 0,			/* bitpos */
732d2201f2fSdrahn 	 complain_overflow_bitfield, /* complain_on_overflow */
733d2201f2fSdrahn 	 mmix_elf_reloc,	/* special_function */
734d2201f2fSdrahn 	 "R_MMIX_REG_OR_BYTE",	/* name */
735d2201f2fSdrahn 	 FALSE,			/* partial_inplace */
736d2201f2fSdrahn 	 0,			/* src_mask */
737d2201f2fSdrahn 	 0xff,			/* dst_mask */
738d2201f2fSdrahn 	 FALSE),		/* pcrel_offset */
739d2201f2fSdrahn 
740d2201f2fSdrahn   /* A general register.  */
741d2201f2fSdrahn   HOWTO (R_MMIX_REG,		/* type */
742d2201f2fSdrahn 	 0,			/* rightshift */
743d2201f2fSdrahn 	 1,			/* size (0 = byte, 1 = short, 2 = long) */
744d2201f2fSdrahn 	 8,			/* bitsize */
745d2201f2fSdrahn 	 FALSE,			/* pc_relative */
746d2201f2fSdrahn 	 0,			/* bitpos */
747d2201f2fSdrahn 	 complain_overflow_bitfield, /* complain_on_overflow */
748d2201f2fSdrahn 	 mmix_elf_reloc,	/* special_function */
749d2201f2fSdrahn 	 "R_MMIX_REG",		/* name */
750d2201f2fSdrahn 	 FALSE,			/* partial_inplace */
751d2201f2fSdrahn 	 0,			/* src_mask */
752d2201f2fSdrahn 	 0xff,			/* dst_mask */
753d2201f2fSdrahn 	 FALSE),		/* pcrel_offset */
754d2201f2fSdrahn 
755d2201f2fSdrahn   /* A register plus an index, corresponding to the relocation expression.
756d2201f2fSdrahn      The sizes must correspond to the valid range of the expression, while
757d2201f2fSdrahn      the bitmasks correspond to what we store in the image.  */
758d2201f2fSdrahn   HOWTO (R_MMIX_BASE_PLUS_OFFSET,	/* type */
759d2201f2fSdrahn 	 0,			/* rightshift */
760d2201f2fSdrahn 	 4,			/* size (0 = byte, 1 = short, 2 = long) */
761d2201f2fSdrahn 	 64,			/* bitsize */
762d2201f2fSdrahn 	 FALSE,			/* pc_relative */
763d2201f2fSdrahn 	 0,			/* bitpos */
764d2201f2fSdrahn 	 complain_overflow_bitfield, /* complain_on_overflow */
765d2201f2fSdrahn 	 mmix_elf_reloc,	/* special_function */
766d2201f2fSdrahn 	 "R_MMIX_BASE_PLUS_OFFSET", /* name */
767d2201f2fSdrahn 	 FALSE,			/* partial_inplace */
768d2201f2fSdrahn 	 0,			/* src_mask */
769d2201f2fSdrahn 	 0xffff,		/* dst_mask */
770d2201f2fSdrahn 	 FALSE),		/* pcrel_offset */
771d2201f2fSdrahn 
772d2201f2fSdrahn   /* A "magic" relocation for a LOCAL expression, asserting that the
773d2201f2fSdrahn      expression is less than the number of global registers.  No actual
774d2201f2fSdrahn      modification of the contents is done.  Implementing this as a
775d2201f2fSdrahn      relocation was less intrusive than e.g. putting such expressions in a
776d2201f2fSdrahn      section to discard *after* relocation.  */
777d2201f2fSdrahn   HOWTO (R_MMIX_LOCAL,		/* type */
778d2201f2fSdrahn 	 0,			/* rightshift */
779d2201f2fSdrahn 	 0,			/* size (0 = byte, 1 = short, 2 = long) */
780d2201f2fSdrahn 	 0,			/* bitsize */
781d2201f2fSdrahn 	 FALSE,			/* pc_relative */
782d2201f2fSdrahn 	 0,			/* bitpos */
783d2201f2fSdrahn 	 complain_overflow_dont, /* complain_on_overflow */
784d2201f2fSdrahn 	 mmix_elf_reloc,	/* special_function */
785d2201f2fSdrahn 	 "R_MMIX_LOCAL",	/* name */
786d2201f2fSdrahn 	 FALSE,			/* partial_inplace */
787d2201f2fSdrahn 	 0,			/* src_mask */
788d2201f2fSdrahn 	 0,			/* dst_mask */
789d2201f2fSdrahn 	 FALSE),		/* pcrel_offset */
790*cf2f2c56Smiod 
791*cf2f2c56Smiod   HOWTO (R_MMIX_PUSHJ_STUBBABLE, /* type */
792*cf2f2c56Smiod 	 2,			/* rightshift */
793*cf2f2c56Smiod 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
794*cf2f2c56Smiod 	 19,			/* bitsize */
795*cf2f2c56Smiod 	 TRUE,			/* pc_relative */
796*cf2f2c56Smiod 	 0,			/* bitpos */
797*cf2f2c56Smiod 	 complain_overflow_signed, /* complain_on_overflow */
798*cf2f2c56Smiod 	 mmix_elf_reloc,	/* special_function */
799*cf2f2c56Smiod 	 "R_MMIX_PUSHJ_STUBBABLE", /* name */
800*cf2f2c56Smiod 	 FALSE,			/* partial_inplace */
801*cf2f2c56Smiod 	 ~0x0100ffff,		/* src_mask */
802*cf2f2c56Smiod 	 0x0100ffff,		/* dst_mask */
803*cf2f2c56Smiod 	 TRUE)			/* pcrel_offset */
804d2201f2fSdrahn  };
805d2201f2fSdrahn 
806d2201f2fSdrahn 
807d2201f2fSdrahn /* Map BFD reloc types to MMIX ELF reloc types.  */
808d2201f2fSdrahn 
809d2201f2fSdrahn struct mmix_reloc_map
810d2201f2fSdrahn   {
811d2201f2fSdrahn     bfd_reloc_code_real_type bfd_reloc_val;
812d2201f2fSdrahn     enum elf_mmix_reloc_type elf_reloc_val;
813d2201f2fSdrahn   };
814d2201f2fSdrahn 
815d2201f2fSdrahn 
816d2201f2fSdrahn static const struct mmix_reloc_map mmix_reloc_map[] =
817d2201f2fSdrahn   {
818d2201f2fSdrahn     {BFD_RELOC_NONE, R_MMIX_NONE},
819d2201f2fSdrahn     {BFD_RELOC_8, R_MMIX_8},
820d2201f2fSdrahn     {BFD_RELOC_16, R_MMIX_16},
821d2201f2fSdrahn     {BFD_RELOC_24, R_MMIX_24},
822d2201f2fSdrahn     {BFD_RELOC_32, R_MMIX_32},
823d2201f2fSdrahn     {BFD_RELOC_64, R_MMIX_64},
824d2201f2fSdrahn     {BFD_RELOC_8_PCREL, R_MMIX_PC_8},
825d2201f2fSdrahn     {BFD_RELOC_16_PCREL, R_MMIX_PC_16},
826d2201f2fSdrahn     {BFD_RELOC_24_PCREL, R_MMIX_PC_24},
827d2201f2fSdrahn     {BFD_RELOC_32_PCREL, R_MMIX_PC_32},
828d2201f2fSdrahn     {BFD_RELOC_64_PCREL, R_MMIX_PC_64},
829d2201f2fSdrahn     {BFD_RELOC_VTABLE_INHERIT, R_MMIX_GNU_VTINHERIT},
830d2201f2fSdrahn     {BFD_RELOC_VTABLE_ENTRY, R_MMIX_GNU_VTENTRY},
831d2201f2fSdrahn     {BFD_RELOC_MMIX_GETA, R_MMIX_GETA},
832d2201f2fSdrahn     {BFD_RELOC_MMIX_CBRANCH, R_MMIX_CBRANCH},
833d2201f2fSdrahn     {BFD_RELOC_MMIX_PUSHJ, R_MMIX_PUSHJ},
834d2201f2fSdrahn     {BFD_RELOC_MMIX_JMP, R_MMIX_JMP},
835d2201f2fSdrahn     {BFD_RELOC_MMIX_ADDR19, R_MMIX_ADDR19},
836d2201f2fSdrahn     {BFD_RELOC_MMIX_ADDR27, R_MMIX_ADDR27},
837d2201f2fSdrahn     {BFD_RELOC_MMIX_REG_OR_BYTE, R_MMIX_REG_OR_BYTE},
838d2201f2fSdrahn     {BFD_RELOC_MMIX_REG, R_MMIX_REG},
839d2201f2fSdrahn     {BFD_RELOC_MMIX_BASE_PLUS_OFFSET, R_MMIX_BASE_PLUS_OFFSET},
840*cf2f2c56Smiod     {BFD_RELOC_MMIX_LOCAL, R_MMIX_LOCAL},
841*cf2f2c56Smiod     {BFD_RELOC_MMIX_PUSHJ_STUBBABLE, R_MMIX_PUSHJ_STUBBABLE}
842d2201f2fSdrahn   };
843d2201f2fSdrahn 
844d2201f2fSdrahn static reloc_howto_type *
bfd_elf64_bfd_reloc_type_lookup(abfd,code)845d2201f2fSdrahn bfd_elf64_bfd_reloc_type_lookup (abfd, code)
846d2201f2fSdrahn      bfd *abfd ATTRIBUTE_UNUSED;
847d2201f2fSdrahn      bfd_reloc_code_real_type code;
848d2201f2fSdrahn {
849d2201f2fSdrahn   unsigned int i;
850d2201f2fSdrahn 
851d2201f2fSdrahn   for (i = 0;
852d2201f2fSdrahn        i < sizeof (mmix_reloc_map) / sizeof (mmix_reloc_map[0]);
853d2201f2fSdrahn        i++)
854d2201f2fSdrahn     {
855d2201f2fSdrahn       if (mmix_reloc_map[i].bfd_reloc_val == code)
856d2201f2fSdrahn 	return &elf_mmix_howto_table[mmix_reloc_map[i].elf_reloc_val];
857d2201f2fSdrahn     }
858d2201f2fSdrahn 
859d2201f2fSdrahn   return NULL;
860d2201f2fSdrahn }
861d2201f2fSdrahn 
862d2201f2fSdrahn static bfd_boolean
mmix_elf_new_section_hook(abfd,sec)863d2201f2fSdrahn mmix_elf_new_section_hook (abfd, sec)
864d2201f2fSdrahn      bfd *abfd;
865d2201f2fSdrahn      asection *sec;
866d2201f2fSdrahn {
867d2201f2fSdrahn   struct _mmix_elf_section_data *sdata;
868d2201f2fSdrahn   bfd_size_type amt = sizeof (*sdata);
869d2201f2fSdrahn 
870d2201f2fSdrahn   sdata = (struct _mmix_elf_section_data *) bfd_zalloc (abfd, amt);
871d2201f2fSdrahn   if (sdata == NULL)
872d2201f2fSdrahn     return FALSE;
873d2201f2fSdrahn   sec->used_by_bfd = (PTR) sdata;
874d2201f2fSdrahn 
875d2201f2fSdrahn   return _bfd_elf_new_section_hook (abfd, sec);
876d2201f2fSdrahn }
877d2201f2fSdrahn 
878d2201f2fSdrahn 
879d2201f2fSdrahn /* This function performs the actual bitfiddling and sanity check for a
880d2201f2fSdrahn    final relocation.  Each relocation gets its *worst*-case expansion
881d2201f2fSdrahn    in size when it arrives here; any reduction in size should have been
882d2201f2fSdrahn    caught in linker relaxation earlier.  When we get here, the relocation
883d2201f2fSdrahn    looks like the smallest instruction with SWYM:s (nop:s) appended to the
884d2201f2fSdrahn    max size.  We fill in those nop:s.
885d2201f2fSdrahn 
886d2201f2fSdrahn    R_MMIX_GETA: (FIXME: Relaxation should break this up in 1, 2, 3 tetra)
887d2201f2fSdrahn     GETA $N,foo
888d2201f2fSdrahn    ->
889d2201f2fSdrahn     SETL $N,foo & 0xffff
890d2201f2fSdrahn     INCML $N,(foo >> 16) & 0xffff
891d2201f2fSdrahn     INCMH $N,(foo >> 32) & 0xffff
892d2201f2fSdrahn     INCH $N,(foo >> 48) & 0xffff
893d2201f2fSdrahn 
894d2201f2fSdrahn    R_MMIX_CBRANCH: (FIXME: Relaxation should break this up, but
895d2201f2fSdrahn    condbranches needing relaxation might be rare enough to not be
896d2201f2fSdrahn    worthwhile.)
897d2201f2fSdrahn     [P]Bcc $N,foo
898d2201f2fSdrahn    ->
899d2201f2fSdrahn     [~P]B~cc $N,.+20
900d2201f2fSdrahn     SETL $255,foo & ...
901d2201f2fSdrahn     INCML ...
902d2201f2fSdrahn     INCMH ...
903d2201f2fSdrahn     INCH ...
904d2201f2fSdrahn     GO $255,$255,0
905d2201f2fSdrahn 
906d2201f2fSdrahn    R_MMIX_PUSHJ: (FIXME: Relaxation...)
907d2201f2fSdrahn     PUSHJ $N,foo
908d2201f2fSdrahn    ->
909d2201f2fSdrahn     SETL $255,foo & ...
910d2201f2fSdrahn     INCML ...
911d2201f2fSdrahn     INCMH ...
912d2201f2fSdrahn     INCH ...
913d2201f2fSdrahn     PUSHGO $N,$255,0
914d2201f2fSdrahn 
915d2201f2fSdrahn    R_MMIX_JMP: (FIXME: Relaxation...)
916d2201f2fSdrahn     JMP foo
917d2201f2fSdrahn    ->
918d2201f2fSdrahn     SETL $255,foo & ...
919d2201f2fSdrahn     INCML ...
920d2201f2fSdrahn     INCMH ...
921d2201f2fSdrahn     INCH ...
922d2201f2fSdrahn     GO $255,$255,0
923d2201f2fSdrahn 
924d2201f2fSdrahn    R_MMIX_ADDR19 and R_MMIX_ADDR27 are just filled in.  */
925d2201f2fSdrahn 
926d2201f2fSdrahn static bfd_reloc_status_type
mmix_elf_perform_relocation(isec,howto,datap,addr,value)927d2201f2fSdrahn mmix_elf_perform_relocation (isec, howto, datap, addr, value)
928d2201f2fSdrahn      asection *isec;
929d2201f2fSdrahn      reloc_howto_type *howto;
930d2201f2fSdrahn      PTR datap;
931*cf2f2c56Smiod      bfd_vma addr;
932d2201f2fSdrahn      bfd_vma value;
933d2201f2fSdrahn {
934d2201f2fSdrahn   bfd *abfd = isec->owner;
935d2201f2fSdrahn   bfd_reloc_status_type flag = bfd_reloc_ok;
936d2201f2fSdrahn   bfd_reloc_status_type r;
937d2201f2fSdrahn   int offs = 0;
938d2201f2fSdrahn   int reg = 255;
939d2201f2fSdrahn 
940d2201f2fSdrahn   /* The worst case bits are all similar SETL/INCML/INCMH/INCH sequences.
941d2201f2fSdrahn      We handle the differences here and the common sequence later.  */
942d2201f2fSdrahn   switch (howto->type)
943d2201f2fSdrahn     {
944d2201f2fSdrahn     case R_MMIX_GETA:
945d2201f2fSdrahn       offs = 0;
946d2201f2fSdrahn       reg = bfd_get_8 (abfd, (bfd_byte *) datap + 1);
947d2201f2fSdrahn 
948d2201f2fSdrahn       /* We change to an absolute value.  */
949d2201f2fSdrahn       value += addr;
950d2201f2fSdrahn       break;
951d2201f2fSdrahn 
952d2201f2fSdrahn     case R_MMIX_CBRANCH:
953d2201f2fSdrahn       {
954d2201f2fSdrahn 	int in1 = bfd_get_16 (abfd, (bfd_byte *) datap) << 16;
955d2201f2fSdrahn 
956d2201f2fSdrahn 	/* Invert the condition and prediction bit, and set the offset
957d2201f2fSdrahn 	   to five instructions ahead.
958d2201f2fSdrahn 
959d2201f2fSdrahn 	   We *can* do better if we want to.  If the branch is found to be
960d2201f2fSdrahn 	   within limits, we could leave the branch as is; there'll just
961d2201f2fSdrahn 	   be a bunch of NOP:s after it.  But we shouldn't see this
962d2201f2fSdrahn 	   sequence often enough that it's worth doing it.  */
963d2201f2fSdrahn 
964d2201f2fSdrahn 	bfd_put_32 (abfd,
965d2201f2fSdrahn 		    (((in1 ^ ((PRED_INV_BIT | COND_INV_BIT) << 24)) & ~0xffff)
966d2201f2fSdrahn 		     | (24/4)),
967d2201f2fSdrahn 		    (bfd_byte *) datap);
968d2201f2fSdrahn 
969d2201f2fSdrahn 	/* Put a "GO $255,$255,0" after the common sequence.  */
970d2201f2fSdrahn 	bfd_put_32 (abfd,
971d2201f2fSdrahn 		    ((GO_INSN_BYTE | IMM_OFFSET_BIT) << 24) | 0xffff00,
972d2201f2fSdrahn 		    (bfd_byte *) datap + 20);
973d2201f2fSdrahn 
974d2201f2fSdrahn 	/* Common sequence starts at offset 4.  */
975d2201f2fSdrahn 	offs = 4;
976d2201f2fSdrahn 
977d2201f2fSdrahn 	/* We change to an absolute value.  */
978d2201f2fSdrahn 	value += addr;
979d2201f2fSdrahn       }
980d2201f2fSdrahn       break;
981d2201f2fSdrahn 
982*cf2f2c56Smiod     case R_MMIX_PUSHJ_STUBBABLE:
983*cf2f2c56Smiod       /* If the address fits, we're fine.  */
984*cf2f2c56Smiod       if ((value & 3) == 0
985*cf2f2c56Smiod 	  /* Note rightshift 0; see R_MMIX_JMP case below.  */
986*cf2f2c56Smiod 	  && (r = bfd_check_overflow (complain_overflow_signed,
987*cf2f2c56Smiod 				      howto->bitsize,
988*cf2f2c56Smiod 				      0,
989*cf2f2c56Smiod 				      bfd_arch_bits_per_address (abfd),
990*cf2f2c56Smiod 				      value)) == bfd_reloc_ok)
991*cf2f2c56Smiod 	goto pcrel_mmix_reloc_fits;
992*cf2f2c56Smiod       else
993*cf2f2c56Smiod 	{
994*cf2f2c56Smiod 	  bfd_size_type raw_size
995*cf2f2c56Smiod 	    = (isec->_raw_size
996*cf2f2c56Smiod 	       - mmix_elf_section_data (isec)->pjs.n_pushj_relocs
997*cf2f2c56Smiod 	       * MAX_PUSHJ_STUB_SIZE);
998*cf2f2c56Smiod 
999*cf2f2c56Smiod 	  /* We have the bytes at the PUSHJ insn and need to get the
1000*cf2f2c56Smiod 	     position for the stub.  There's supposed to be room allocated
1001*cf2f2c56Smiod 	     for the stub.  */
1002*cf2f2c56Smiod 	  bfd_byte *stubcontents
1003*cf2f2c56Smiod 	    = ((char *) datap
1004*cf2f2c56Smiod 	       - (addr - (isec->output_section->vma + isec->output_offset))
1005*cf2f2c56Smiod 	       + raw_size
1006*cf2f2c56Smiod 	       + mmix_elf_section_data (isec)->pjs.stub_offset);
1007*cf2f2c56Smiod 	  bfd_vma stubaddr;
1008*cf2f2c56Smiod 
1009*cf2f2c56Smiod 	  /* The address doesn't fit, so redirect the PUSHJ to the
1010*cf2f2c56Smiod 	     location of the stub.  */
1011*cf2f2c56Smiod 	  r = mmix_elf_perform_relocation (isec,
1012*cf2f2c56Smiod 					   &elf_mmix_howto_table
1013*cf2f2c56Smiod 					   [R_MMIX_ADDR19],
1014*cf2f2c56Smiod 					   datap,
1015*cf2f2c56Smiod 					   addr,
1016*cf2f2c56Smiod 					   isec->output_section->vma
1017*cf2f2c56Smiod 					   + isec->output_offset
1018*cf2f2c56Smiod 					   + raw_size
1019*cf2f2c56Smiod 					   + (mmix_elf_section_data (isec)
1020*cf2f2c56Smiod 					      ->pjs.stub_offset)
1021*cf2f2c56Smiod 					   - addr);
1022*cf2f2c56Smiod 	  if (r != bfd_reloc_ok)
1023*cf2f2c56Smiod 	    return r;
1024*cf2f2c56Smiod 
1025*cf2f2c56Smiod 	  stubaddr
1026*cf2f2c56Smiod 	    = (isec->output_section->vma
1027*cf2f2c56Smiod 	       + isec->output_offset
1028*cf2f2c56Smiod 	       + raw_size
1029*cf2f2c56Smiod 	       + mmix_elf_section_data (isec)->pjs.stub_offset);
1030*cf2f2c56Smiod 
1031*cf2f2c56Smiod 	  /* We generate a simple JMP if that suffices, else the whole 5
1032*cf2f2c56Smiod 	     insn stub.  */
1033*cf2f2c56Smiod 	  if (bfd_check_overflow (complain_overflow_signed,
1034*cf2f2c56Smiod 				  elf_mmix_howto_table[R_MMIX_ADDR27].bitsize,
1035*cf2f2c56Smiod 				  0,
1036*cf2f2c56Smiod 				  bfd_arch_bits_per_address (abfd),
1037*cf2f2c56Smiod 				  addr + value - stubaddr) == bfd_reloc_ok)
1038*cf2f2c56Smiod 	    {
1039*cf2f2c56Smiod 	      bfd_put_32 (abfd, JMP_INSN_BYTE << 24, stubcontents);
1040*cf2f2c56Smiod 	      r = mmix_elf_perform_relocation (isec,
1041*cf2f2c56Smiod 					       &elf_mmix_howto_table
1042*cf2f2c56Smiod 					       [R_MMIX_ADDR27],
1043*cf2f2c56Smiod 					       stubcontents,
1044*cf2f2c56Smiod 					       stubaddr,
1045*cf2f2c56Smiod 					       value + addr - stubaddr);
1046*cf2f2c56Smiod 	      mmix_elf_section_data (isec)->pjs.stub_offset += 4;
1047*cf2f2c56Smiod 
1048*cf2f2c56Smiod 	      if (raw_size
1049*cf2f2c56Smiod 		  + mmix_elf_section_data (isec)->pjs.stub_offset
1050*cf2f2c56Smiod 		  > isec->_cooked_size)
1051*cf2f2c56Smiod 		abort ();
1052*cf2f2c56Smiod 
1053*cf2f2c56Smiod 	      return r;
1054*cf2f2c56Smiod 	    }
1055*cf2f2c56Smiod 	  else
1056*cf2f2c56Smiod 	    {
1057*cf2f2c56Smiod 	      /* Put a "GO $255,0" after the common sequence.  */
1058*cf2f2c56Smiod 	      bfd_put_32 (abfd,
1059*cf2f2c56Smiod 			  ((GO_INSN_BYTE | IMM_OFFSET_BIT) << 24)
1060*cf2f2c56Smiod 			  | 0xff00, (bfd_byte *) stubcontents + 16);
1061*cf2f2c56Smiod 
1062*cf2f2c56Smiod 	      /* Prepare for the general code to set the first part of the
1063*cf2f2c56Smiod 		 linker stub, and */
1064*cf2f2c56Smiod 	      value += addr;
1065*cf2f2c56Smiod 	      datap = stubcontents;
1066*cf2f2c56Smiod 	      mmix_elf_section_data (isec)->pjs.stub_offset
1067*cf2f2c56Smiod 		+= MAX_PUSHJ_STUB_SIZE;
1068*cf2f2c56Smiod 	    }
1069*cf2f2c56Smiod 	}
1070*cf2f2c56Smiod       break;
1071*cf2f2c56Smiod 
1072d2201f2fSdrahn     case R_MMIX_PUSHJ:
1073d2201f2fSdrahn       {
1074d2201f2fSdrahn 	int inreg = bfd_get_8 (abfd, (bfd_byte *) datap + 1);
1075d2201f2fSdrahn 
1076d2201f2fSdrahn 	/* Put a "PUSHGO $N,$255,0" after the common sequence.  */
1077d2201f2fSdrahn 	bfd_put_32 (abfd,
1078d2201f2fSdrahn 		    ((PUSHGO_INSN_BYTE | IMM_OFFSET_BIT) << 24)
1079d2201f2fSdrahn 		    | (inreg << 16)
1080d2201f2fSdrahn 		    | 0xff00,
1081d2201f2fSdrahn 		    (bfd_byte *) datap + 16);
1082d2201f2fSdrahn 
1083d2201f2fSdrahn 	/* We change to an absolute value.  */
1084d2201f2fSdrahn 	value += addr;
1085d2201f2fSdrahn       }
1086d2201f2fSdrahn       break;
1087d2201f2fSdrahn 
1088d2201f2fSdrahn     case R_MMIX_JMP:
1089d2201f2fSdrahn       /* This one is a little special.  If we get here on a non-relaxing
1090d2201f2fSdrahn 	 link, and the destination is actually in range, we don't need to
1091d2201f2fSdrahn 	 execute the nops.
1092d2201f2fSdrahn 	 If so, we fall through to the bit-fiddling relocs.
1093d2201f2fSdrahn 
1094d2201f2fSdrahn 	 FIXME: bfd_check_overflow seems broken; the relocation is
1095d2201f2fSdrahn 	 rightshifted before testing, so supply a zero rightshift.  */
1096d2201f2fSdrahn 
1097d2201f2fSdrahn       if (! ((value & 3) == 0
1098d2201f2fSdrahn 	     && (r = bfd_check_overflow (complain_overflow_signed,
1099d2201f2fSdrahn 					 howto->bitsize,
1100d2201f2fSdrahn 					 0,
1101d2201f2fSdrahn 					 bfd_arch_bits_per_address (abfd),
1102d2201f2fSdrahn 					 value)) == bfd_reloc_ok))
1103d2201f2fSdrahn 	{
1104d2201f2fSdrahn 	  /* If the relocation doesn't fit in a JMP, we let the NOP:s be
1105d2201f2fSdrahn 	     modified below, and put a "GO $255,$255,0" after the
1106d2201f2fSdrahn 	     address-loading sequence.  */
1107d2201f2fSdrahn 	  bfd_put_32 (abfd,
1108d2201f2fSdrahn 		      ((GO_INSN_BYTE | IMM_OFFSET_BIT) << 24)
1109d2201f2fSdrahn 		      | 0xffff00,
1110d2201f2fSdrahn 		      (bfd_byte *) datap + 16);
1111d2201f2fSdrahn 
1112d2201f2fSdrahn 	  /* We change to an absolute value.  */
1113d2201f2fSdrahn 	  value += addr;
1114d2201f2fSdrahn 	  break;
1115d2201f2fSdrahn 	}
1116d2201f2fSdrahn       /* FALLTHROUGH.  */
1117d2201f2fSdrahn     case R_MMIX_ADDR19:
1118d2201f2fSdrahn     case R_MMIX_ADDR27:
1119*cf2f2c56Smiod     pcrel_mmix_reloc_fits:
1120d2201f2fSdrahn       /* These must be in range, or else we emit an error.  */
1121d2201f2fSdrahn       if ((value & 3) == 0
1122d2201f2fSdrahn 	  /* Note rightshift 0; see above.  */
1123d2201f2fSdrahn 	  && (r = bfd_check_overflow (complain_overflow_signed,
1124d2201f2fSdrahn 				      howto->bitsize,
1125d2201f2fSdrahn 				      0,
1126d2201f2fSdrahn 				      bfd_arch_bits_per_address (abfd),
1127d2201f2fSdrahn 				      value)) == bfd_reloc_ok)
1128d2201f2fSdrahn 	{
1129d2201f2fSdrahn 	  bfd_vma in1
1130d2201f2fSdrahn 	    = bfd_get_32 (abfd, (bfd_byte *) datap);
1131d2201f2fSdrahn 	  bfd_vma highbit;
1132d2201f2fSdrahn 
1133d2201f2fSdrahn 	  if ((bfd_signed_vma) value < 0)
1134d2201f2fSdrahn 	    {
1135*cf2f2c56Smiod 	      highbit = 1 << 24;
1136d2201f2fSdrahn 	      value += (1 << (howto->bitsize - 1));
1137d2201f2fSdrahn 	    }
1138d2201f2fSdrahn 	  else
1139d2201f2fSdrahn 	    highbit = 0;
1140d2201f2fSdrahn 
1141d2201f2fSdrahn 	  value >>= 2;
1142d2201f2fSdrahn 
1143d2201f2fSdrahn 	  bfd_put_32 (abfd,
1144d2201f2fSdrahn 		      (in1 & howto->src_mask)
1145d2201f2fSdrahn 		      | highbit
1146d2201f2fSdrahn 		      | (value & howto->dst_mask),
1147d2201f2fSdrahn 		      (bfd_byte *) datap);
1148d2201f2fSdrahn 
1149d2201f2fSdrahn 	  return bfd_reloc_ok;
1150d2201f2fSdrahn 	}
1151d2201f2fSdrahn       else
1152d2201f2fSdrahn 	return bfd_reloc_overflow;
1153d2201f2fSdrahn 
1154d2201f2fSdrahn     case R_MMIX_BASE_PLUS_OFFSET:
1155d2201f2fSdrahn       {
1156d2201f2fSdrahn 	struct bpo_reloc_section_info *bpodata
1157d2201f2fSdrahn 	  = mmix_elf_section_data (isec)->bpo.reloc;
1158d2201f2fSdrahn 	asection *bpo_greg_section
1159d2201f2fSdrahn 	  = bpodata->bpo_greg_section;
1160d2201f2fSdrahn 	struct bpo_greg_section_info *gregdata
1161d2201f2fSdrahn 	  = mmix_elf_section_data (bpo_greg_section)->bpo.greg;
1162d2201f2fSdrahn 	size_t bpo_index
1163d2201f2fSdrahn 	  = gregdata->bpo_reloc_indexes[bpodata->bpo_index++];
1164d2201f2fSdrahn 
1165d2201f2fSdrahn 	/* A consistency check: The value we now have in "relocation" must
1166d2201f2fSdrahn 	   be the same as the value we stored for that relocation.  It
1167d2201f2fSdrahn 	   doesn't cost much, so can be left in at all times.  */
1168d2201f2fSdrahn 	if (value != gregdata->reloc_request[bpo_index].value)
1169d2201f2fSdrahn 	  {
1170d2201f2fSdrahn 	    (*_bfd_error_handler)
1171d2201f2fSdrahn 	      (_("%s: Internal inconsistency error for value for\n\
1172d2201f2fSdrahn  linker-allocated global register: linked: 0x%lx%08lx != relaxed: 0x%lx%08lx\n"),
1173d2201f2fSdrahn 	       bfd_get_filename (isec->owner),
1174d2201f2fSdrahn 	       (unsigned long) (value >> 32), (unsigned long) value,
1175d2201f2fSdrahn 	       (unsigned long) (gregdata->reloc_request[bpo_index].value
1176d2201f2fSdrahn 				>> 32),
1177d2201f2fSdrahn 	       (unsigned long) gregdata->reloc_request[bpo_index].value);
1178d2201f2fSdrahn 	    bfd_set_error (bfd_error_bad_value);
1179d2201f2fSdrahn 	    return bfd_reloc_overflow;
1180d2201f2fSdrahn 	  }
1181d2201f2fSdrahn 
1182d2201f2fSdrahn 	/* Then store the register number and offset for that register
1183d2201f2fSdrahn 	   into datap and datap + 1 respectively.  */
1184d2201f2fSdrahn 	bfd_put_8 (abfd,
1185d2201f2fSdrahn 		   gregdata->reloc_request[bpo_index].regindex
1186d2201f2fSdrahn 		   + bpo_greg_section->output_section->vma / 8,
1187d2201f2fSdrahn 		   datap);
1188d2201f2fSdrahn 	bfd_put_8 (abfd,
1189d2201f2fSdrahn 		   gregdata->reloc_request[bpo_index].offset,
1190d2201f2fSdrahn 		   ((unsigned char *) datap) + 1);
1191d2201f2fSdrahn 	return bfd_reloc_ok;
1192d2201f2fSdrahn       }
1193d2201f2fSdrahn 
1194d2201f2fSdrahn     case R_MMIX_REG_OR_BYTE:
1195d2201f2fSdrahn     case R_MMIX_REG:
1196d2201f2fSdrahn       if (value > 255)
1197d2201f2fSdrahn 	return bfd_reloc_overflow;
1198d2201f2fSdrahn       bfd_put_8 (abfd, value, datap);
1199d2201f2fSdrahn       return bfd_reloc_ok;
1200d2201f2fSdrahn 
1201d2201f2fSdrahn     default:
1202d2201f2fSdrahn       BAD_CASE (howto->type);
1203d2201f2fSdrahn     }
1204d2201f2fSdrahn 
1205d2201f2fSdrahn   /* This code adds the common SETL/INCML/INCMH/INCH worst-case
1206d2201f2fSdrahn      sequence.  */
1207d2201f2fSdrahn 
1208d2201f2fSdrahn   /* Lowest two bits must be 0.  We return bfd_reloc_overflow for
1209d2201f2fSdrahn      everything that looks strange.  */
1210d2201f2fSdrahn   if (value & 3)
1211d2201f2fSdrahn     flag = bfd_reloc_overflow;
1212d2201f2fSdrahn 
1213d2201f2fSdrahn   bfd_put_32 (abfd,
1214d2201f2fSdrahn 	      (SETL_INSN_BYTE << 24) | (value & 0xffff) | (reg << 16),
1215d2201f2fSdrahn 	      (bfd_byte *) datap + offs);
1216d2201f2fSdrahn   bfd_put_32 (abfd,
1217d2201f2fSdrahn 	      (INCML_INSN_BYTE << 24) | ((value >> 16) & 0xffff) | (reg << 16),
1218d2201f2fSdrahn 	      (bfd_byte *) datap + offs + 4);
1219d2201f2fSdrahn   bfd_put_32 (abfd,
1220d2201f2fSdrahn 	      (INCMH_INSN_BYTE << 24) | ((value >> 32) & 0xffff) | (reg << 16),
1221d2201f2fSdrahn 	      (bfd_byte *) datap + offs + 8);
1222d2201f2fSdrahn   bfd_put_32 (abfd,
1223d2201f2fSdrahn 	      (INCH_INSN_BYTE << 24) | ((value >> 48) & 0xffff) | (reg << 16),
1224d2201f2fSdrahn 	      (bfd_byte *) datap + offs + 12);
1225d2201f2fSdrahn 
1226d2201f2fSdrahn   return flag;
1227d2201f2fSdrahn }
1228d2201f2fSdrahn 
1229d2201f2fSdrahn /* Set the howto pointer for an MMIX ELF reloc (type RELA).  */
1230d2201f2fSdrahn 
1231d2201f2fSdrahn static void
mmix_info_to_howto_rela(abfd,cache_ptr,dst)1232d2201f2fSdrahn mmix_info_to_howto_rela (abfd, cache_ptr, dst)
1233d2201f2fSdrahn      bfd *abfd ATTRIBUTE_UNUSED;
1234d2201f2fSdrahn      arelent *cache_ptr;
1235d2201f2fSdrahn      Elf_Internal_Rela *dst;
1236d2201f2fSdrahn {
1237d2201f2fSdrahn   unsigned int r_type;
1238d2201f2fSdrahn 
1239d2201f2fSdrahn   r_type = ELF64_R_TYPE (dst->r_info);
1240d2201f2fSdrahn   BFD_ASSERT (r_type < (unsigned int) R_MMIX_max);
1241d2201f2fSdrahn   cache_ptr->howto = &elf_mmix_howto_table[r_type];
1242d2201f2fSdrahn }
1243d2201f2fSdrahn 
1244d2201f2fSdrahn /* Any MMIX-specific relocation gets here at assembly time or when linking
1245d2201f2fSdrahn    to other formats (such as mmo); this is the relocation function from
1246d2201f2fSdrahn    the reloc_table.  We don't get here for final pure ELF linking.  */
1247d2201f2fSdrahn 
1248d2201f2fSdrahn static bfd_reloc_status_type
mmix_elf_reloc(abfd,reloc_entry,symbol,data,input_section,output_bfd,error_message)1249d2201f2fSdrahn mmix_elf_reloc (abfd, reloc_entry, symbol, data, input_section,
1250d2201f2fSdrahn 		output_bfd, error_message)
1251d2201f2fSdrahn      bfd *abfd;
1252d2201f2fSdrahn      arelent *reloc_entry;
1253d2201f2fSdrahn      asymbol *symbol;
1254d2201f2fSdrahn      PTR data;
1255d2201f2fSdrahn      asection *input_section;
1256d2201f2fSdrahn      bfd *output_bfd;
1257d2201f2fSdrahn      char **error_message ATTRIBUTE_UNUSED;
1258d2201f2fSdrahn {
1259d2201f2fSdrahn   bfd_vma relocation;
1260d2201f2fSdrahn   bfd_reloc_status_type r;
1261d2201f2fSdrahn   asection *reloc_target_output_section;
1262d2201f2fSdrahn   bfd_reloc_status_type flag = bfd_reloc_ok;
1263d2201f2fSdrahn   bfd_vma output_base = 0;
1264d2201f2fSdrahn   bfd_vma addr;
1265d2201f2fSdrahn 
1266d2201f2fSdrahn   r = bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
1267d2201f2fSdrahn 			     input_section, output_bfd, error_message);
1268d2201f2fSdrahn 
1269d2201f2fSdrahn   /* If that was all that was needed (i.e. this isn't a final link, only
1270d2201f2fSdrahn      some segment adjustments), we're done.  */
1271d2201f2fSdrahn   if (r != bfd_reloc_continue)
1272d2201f2fSdrahn     return r;
1273d2201f2fSdrahn 
1274d2201f2fSdrahn   if (bfd_is_und_section (symbol->section)
1275d2201f2fSdrahn       && (symbol->flags & BSF_WEAK) == 0
1276d2201f2fSdrahn       && output_bfd == (bfd *) NULL)
1277d2201f2fSdrahn     return bfd_reloc_undefined;
1278d2201f2fSdrahn 
1279d2201f2fSdrahn   /* Is the address of the relocation really within the section?  */
1280d2201f2fSdrahn   if (reloc_entry->address > input_section->_cooked_size)
1281d2201f2fSdrahn     return bfd_reloc_outofrange;
1282d2201f2fSdrahn 
1283*cf2f2c56Smiod   /* Work out which section the relocation is targeted at and the
1284d2201f2fSdrahn      initial relocation command value.  */
1285d2201f2fSdrahn 
1286d2201f2fSdrahn   /* Get symbol value.  (Common symbols are special.)  */
1287d2201f2fSdrahn   if (bfd_is_com_section (symbol->section))
1288d2201f2fSdrahn     relocation = 0;
1289d2201f2fSdrahn   else
1290d2201f2fSdrahn     relocation = symbol->value;
1291d2201f2fSdrahn 
1292d2201f2fSdrahn   reloc_target_output_section = bfd_get_output_section (symbol);
1293d2201f2fSdrahn 
1294d2201f2fSdrahn   /* Here the variable relocation holds the final address of the symbol we
1295d2201f2fSdrahn      are relocating against, plus any addend.  */
1296d2201f2fSdrahn   if (output_bfd)
1297d2201f2fSdrahn     output_base = 0;
1298d2201f2fSdrahn   else
1299d2201f2fSdrahn     output_base = reloc_target_output_section->vma;
1300d2201f2fSdrahn 
1301d2201f2fSdrahn   relocation += output_base + symbol->section->output_offset;
1302d2201f2fSdrahn 
1303d2201f2fSdrahn   /* Get position of relocation.  */
1304d2201f2fSdrahn   addr = (reloc_entry->address + input_section->output_section->vma
1305d2201f2fSdrahn 	  + input_section->output_offset);
1306d2201f2fSdrahn   if (output_bfd != (bfd *) NULL)
1307d2201f2fSdrahn     {
1308d2201f2fSdrahn       /* Add in supplied addend.  */
1309d2201f2fSdrahn       relocation += reloc_entry->addend;
1310d2201f2fSdrahn 
1311d2201f2fSdrahn       /* This is a partial relocation, and we want to apply the
1312d2201f2fSdrahn 	 relocation to the reloc entry rather than the raw data.
1313d2201f2fSdrahn 	 Modify the reloc inplace to reflect what we now know.  */
1314d2201f2fSdrahn       reloc_entry->addend = relocation;
1315d2201f2fSdrahn       reloc_entry->address += input_section->output_offset;
1316d2201f2fSdrahn       return flag;
1317d2201f2fSdrahn     }
1318d2201f2fSdrahn 
1319d2201f2fSdrahn   return mmix_final_link_relocate (reloc_entry->howto, input_section,
1320d2201f2fSdrahn 				   data, reloc_entry->address,
1321d2201f2fSdrahn 				   reloc_entry->addend, relocation,
1322d2201f2fSdrahn 				   bfd_asymbol_name (symbol),
1323d2201f2fSdrahn 				   reloc_target_output_section);
1324d2201f2fSdrahn }
1325d2201f2fSdrahn 
1326d2201f2fSdrahn /* Relocate an MMIX ELF section.  Modified from elf32-fr30.c; look to it
1327d2201f2fSdrahn    for guidance if you're thinking of copying this.  */
1328d2201f2fSdrahn 
1329d2201f2fSdrahn static bfd_boolean
mmix_elf_relocate_section(output_bfd,info,input_bfd,input_section,contents,relocs,local_syms,local_sections)1330d2201f2fSdrahn mmix_elf_relocate_section (output_bfd, info, input_bfd, input_section,
1331d2201f2fSdrahn 			   contents, relocs, local_syms, local_sections)
1332d2201f2fSdrahn      bfd *output_bfd ATTRIBUTE_UNUSED;
1333d2201f2fSdrahn      struct bfd_link_info *info;
1334d2201f2fSdrahn      bfd *input_bfd;
1335d2201f2fSdrahn      asection *input_section;
1336d2201f2fSdrahn      bfd_byte *contents;
1337d2201f2fSdrahn      Elf_Internal_Rela *relocs;
1338d2201f2fSdrahn      Elf_Internal_Sym *local_syms;
1339d2201f2fSdrahn      asection **local_sections;
1340d2201f2fSdrahn {
1341d2201f2fSdrahn   Elf_Internal_Shdr *symtab_hdr;
1342d2201f2fSdrahn   struct elf_link_hash_entry **sym_hashes;
1343d2201f2fSdrahn   Elf_Internal_Rela *rel;
1344d2201f2fSdrahn   Elf_Internal_Rela *relend;
1345*cf2f2c56Smiod   bfd_size_type raw_size
1346*cf2f2c56Smiod     = (input_section->_raw_size
1347*cf2f2c56Smiod        - mmix_elf_section_data (input_section)->pjs.n_pushj_relocs
1348*cf2f2c56Smiod        * MAX_PUSHJ_STUB_SIZE);
1349*cf2f2c56Smiod   size_t pjsno = 0;
1350d2201f2fSdrahn 
1351d2201f2fSdrahn   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
1352d2201f2fSdrahn   sym_hashes = elf_sym_hashes (input_bfd);
1353d2201f2fSdrahn   relend = relocs + input_section->reloc_count;
1354d2201f2fSdrahn 
1355d2201f2fSdrahn   for (rel = relocs; rel < relend; rel ++)
1356d2201f2fSdrahn     {
1357d2201f2fSdrahn       reloc_howto_type *howto;
1358d2201f2fSdrahn       unsigned long r_symndx;
1359d2201f2fSdrahn       Elf_Internal_Sym *sym;
1360d2201f2fSdrahn       asection *sec;
1361d2201f2fSdrahn       struct elf_link_hash_entry *h;
1362d2201f2fSdrahn       bfd_vma relocation;
1363d2201f2fSdrahn       bfd_reloc_status_type r;
1364d2201f2fSdrahn       const char *name = NULL;
1365d2201f2fSdrahn       int r_type;
1366d2201f2fSdrahn       bfd_boolean undefined_signalled = FALSE;
1367d2201f2fSdrahn 
1368d2201f2fSdrahn       r_type = ELF64_R_TYPE (rel->r_info);
1369d2201f2fSdrahn 
1370d2201f2fSdrahn       if (r_type == R_MMIX_GNU_VTINHERIT
1371d2201f2fSdrahn 	  || r_type == R_MMIX_GNU_VTENTRY)
1372d2201f2fSdrahn 	continue;
1373d2201f2fSdrahn 
1374d2201f2fSdrahn       r_symndx = ELF64_R_SYM (rel->r_info);
1375d2201f2fSdrahn 
1376*cf2f2c56Smiod       if (info->relocatable)
1377d2201f2fSdrahn 	{
1378*cf2f2c56Smiod 	  /* This is a relocatable link.  For most relocs we don't have to
1379*cf2f2c56Smiod 	     change anything, unless the reloc is against a section
1380*cf2f2c56Smiod 	     symbol, in which case we have to adjust according to where
1381*cf2f2c56Smiod 	     the section symbol winds up in the output section.  */
1382d2201f2fSdrahn 	  if (r_symndx < symtab_hdr->sh_info)
1383d2201f2fSdrahn 	    {
1384d2201f2fSdrahn 	      sym = local_syms + r_symndx;
1385d2201f2fSdrahn 
1386d2201f2fSdrahn 	      if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
1387d2201f2fSdrahn 		{
1388d2201f2fSdrahn 		  sec = local_sections [r_symndx];
1389d2201f2fSdrahn 		  rel->r_addend += sec->output_offset + sym->st_value;
1390d2201f2fSdrahn 		}
1391d2201f2fSdrahn 	    }
1392d2201f2fSdrahn 
1393*cf2f2c56Smiod 	  /* For PUSHJ stub relocs however, we may need to change the
1394*cf2f2c56Smiod 	     reloc and the section contents, if the reloc doesn't reach
1395*cf2f2c56Smiod 	     beyond the end of the output section and previous stubs.
1396*cf2f2c56Smiod 	     Then we change the section contents to be a PUSHJ to the end
1397*cf2f2c56Smiod 	     of the input section plus stubs (we can do that without using
1398*cf2f2c56Smiod 	     a reloc), and then we change the reloc to be a R_MMIX_PUSHJ
1399*cf2f2c56Smiod 	     at the stub location.  */
1400*cf2f2c56Smiod 	  if (r_type == R_MMIX_PUSHJ_STUBBABLE)
1401*cf2f2c56Smiod 	    {
1402*cf2f2c56Smiod 	      /* We've already checked whether we need a stub; use that
1403*cf2f2c56Smiod 		 knowledge.  */
1404*cf2f2c56Smiod 	      if (mmix_elf_section_data (input_section)->pjs.stub_size[pjsno]
1405*cf2f2c56Smiod 		  != 0)
1406*cf2f2c56Smiod 		{
1407*cf2f2c56Smiod 		  Elf_Internal_Rela relcpy;
1408*cf2f2c56Smiod 
1409*cf2f2c56Smiod 		  if (mmix_elf_section_data (input_section)
1410*cf2f2c56Smiod 		      ->pjs.stub_size[pjsno] != MAX_PUSHJ_STUB_SIZE)
1411*cf2f2c56Smiod 		    abort ();
1412*cf2f2c56Smiod 
1413*cf2f2c56Smiod 		  /* There's already a PUSHJ insn there, so just fill in
1414*cf2f2c56Smiod 		     the offset bits to the stub.  */
1415*cf2f2c56Smiod 		  if (mmix_final_link_relocate (elf_mmix_howto_table
1416*cf2f2c56Smiod 						+ R_MMIX_ADDR19,
1417*cf2f2c56Smiod 						input_section,
1418*cf2f2c56Smiod 						contents,
1419*cf2f2c56Smiod 						rel->r_offset,
1420*cf2f2c56Smiod 						0,
1421*cf2f2c56Smiod 						input_section
1422*cf2f2c56Smiod 						->output_section->vma
1423*cf2f2c56Smiod 						+ input_section->output_offset
1424*cf2f2c56Smiod 						+ raw_size
1425*cf2f2c56Smiod 						+ mmix_elf_section_data (input_section)
1426*cf2f2c56Smiod 						->pjs.stub_offset,
1427*cf2f2c56Smiod 						NULL, NULL) != bfd_reloc_ok)
1428*cf2f2c56Smiod 		    return FALSE;
1429*cf2f2c56Smiod 
1430*cf2f2c56Smiod 		  /* Put a JMP insn at the stub; it goes with the
1431*cf2f2c56Smiod 		     R_MMIX_JMP reloc.  */
1432*cf2f2c56Smiod 		  bfd_put_32 (output_bfd, JMP_INSN_BYTE << 24,
1433*cf2f2c56Smiod 			      contents
1434*cf2f2c56Smiod 			      + raw_size
1435*cf2f2c56Smiod 			      + mmix_elf_section_data (input_section)
1436*cf2f2c56Smiod 			      ->pjs.stub_offset);
1437*cf2f2c56Smiod 
1438*cf2f2c56Smiod 		  /* Change the reloc to be at the stub, and to a full
1439*cf2f2c56Smiod 		     R_MMIX_JMP reloc.  */
1440*cf2f2c56Smiod 		  rel->r_info = ELF64_R_INFO (r_symndx, R_MMIX_JMP);
1441*cf2f2c56Smiod 		  rel->r_offset
1442*cf2f2c56Smiod 		    = (raw_size
1443*cf2f2c56Smiod 		       + mmix_elf_section_data (input_section)
1444*cf2f2c56Smiod 		       ->pjs.stub_offset);
1445*cf2f2c56Smiod 
1446*cf2f2c56Smiod 		  mmix_elf_section_data (input_section)->pjs.stub_offset
1447*cf2f2c56Smiod 		    += MAX_PUSHJ_STUB_SIZE;
1448*cf2f2c56Smiod 
1449*cf2f2c56Smiod 		  /* Shift this reloc to the end of the relocs to maintain
1450*cf2f2c56Smiod 		     the r_offset sorted reloc order.  */
1451*cf2f2c56Smiod 		  relcpy = *rel;
1452*cf2f2c56Smiod 		  memmove (rel, rel + 1, (char *) relend - (char *) rel);
1453*cf2f2c56Smiod 		  relend[-1] = relcpy;
1454*cf2f2c56Smiod 
1455*cf2f2c56Smiod 		  /* Back up one reloc, or else we'd skip the next reloc
1456*cf2f2c56Smiod 		   in turn.  */
1457*cf2f2c56Smiod 		  rel--;
1458*cf2f2c56Smiod 		}
1459*cf2f2c56Smiod 
1460*cf2f2c56Smiod 	      pjsno++;
1461*cf2f2c56Smiod 	    }
1462d2201f2fSdrahn 	  continue;
1463d2201f2fSdrahn 	}
1464d2201f2fSdrahn 
1465d2201f2fSdrahn       /* This is a final link.  */
1466d2201f2fSdrahn       howto = elf_mmix_howto_table + ELF64_R_TYPE (rel->r_info);
1467d2201f2fSdrahn       h = NULL;
1468d2201f2fSdrahn       sym = NULL;
1469d2201f2fSdrahn       sec = NULL;
1470d2201f2fSdrahn 
1471d2201f2fSdrahn       if (r_symndx < symtab_hdr->sh_info)
1472d2201f2fSdrahn 	{
1473d2201f2fSdrahn 	  sym = local_syms + r_symndx;
1474d2201f2fSdrahn 	  sec = local_sections [r_symndx];
1475*cf2f2c56Smiod 	  relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
1476d2201f2fSdrahn 
1477*cf2f2c56Smiod 	  name = bfd_elf_string_from_elf_section (input_bfd,
1478*cf2f2c56Smiod 						  symtab_hdr->sh_link,
1479*cf2f2c56Smiod 						  sym->st_name);
1480*cf2f2c56Smiod 	  if (name == NULL)
1481*cf2f2c56Smiod 	    name = bfd_section_name (input_bfd, sec);
1482d2201f2fSdrahn 	}
1483d2201f2fSdrahn       else
1484d2201f2fSdrahn 	{
1485*cf2f2c56Smiod 	  bfd_boolean unresolved_reloc;
1486d2201f2fSdrahn 
1487*cf2f2c56Smiod 	  RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
1488*cf2f2c56Smiod 				   r_symndx, symtab_hdr, sym_hashes,
1489*cf2f2c56Smiod 				   h, sec, relocation,
1490*cf2f2c56Smiod 				   unresolved_reloc, undefined_signalled);
1491d2201f2fSdrahn 	  name = h->root.root.string;
1492d2201f2fSdrahn 	}
1493d2201f2fSdrahn 
1494d2201f2fSdrahn       r = mmix_final_link_relocate (howto, input_section,
1495d2201f2fSdrahn 				    contents, rel->r_offset,
1496d2201f2fSdrahn 				    rel->r_addend, relocation, name, sec);
1497d2201f2fSdrahn 
1498d2201f2fSdrahn       if (r != bfd_reloc_ok)
1499d2201f2fSdrahn 	{
1500d2201f2fSdrahn 	  bfd_boolean check_ok = TRUE;
1501d2201f2fSdrahn 	  const char * msg = (const char *) NULL;
1502d2201f2fSdrahn 
1503d2201f2fSdrahn 	  switch (r)
1504d2201f2fSdrahn 	    {
1505d2201f2fSdrahn 	    case bfd_reloc_overflow:
1506d2201f2fSdrahn 	      check_ok = info->callbacks->reloc_overflow
1507d2201f2fSdrahn 		(info, name, howto->name, (bfd_vma) 0,
1508d2201f2fSdrahn 		 input_bfd, input_section, rel->r_offset);
1509d2201f2fSdrahn 	      break;
1510d2201f2fSdrahn 
1511d2201f2fSdrahn 	    case bfd_reloc_undefined:
1512d2201f2fSdrahn 	      /* We may have sent this message above.  */
1513d2201f2fSdrahn 	      if (! undefined_signalled)
1514d2201f2fSdrahn 		check_ok = info->callbacks->undefined_symbol
1515d2201f2fSdrahn 		  (info, name, input_bfd, input_section, rel->r_offset,
1516d2201f2fSdrahn 		   TRUE);
1517d2201f2fSdrahn 	      undefined_signalled = TRUE;
1518d2201f2fSdrahn 	      break;
1519d2201f2fSdrahn 
1520d2201f2fSdrahn 	    case bfd_reloc_outofrange:
1521d2201f2fSdrahn 	      msg = _("internal error: out of range error");
1522d2201f2fSdrahn 	      break;
1523d2201f2fSdrahn 
1524d2201f2fSdrahn 	    case bfd_reloc_notsupported:
1525d2201f2fSdrahn 	      msg = _("internal error: unsupported relocation error");
1526d2201f2fSdrahn 	      break;
1527d2201f2fSdrahn 
1528d2201f2fSdrahn 	    case bfd_reloc_dangerous:
1529d2201f2fSdrahn 	      msg = _("internal error: dangerous relocation");
1530d2201f2fSdrahn 	      break;
1531d2201f2fSdrahn 
1532d2201f2fSdrahn 	    default:
1533d2201f2fSdrahn 	      msg = _("internal error: unknown error");
1534d2201f2fSdrahn 	      break;
1535d2201f2fSdrahn 	    }
1536d2201f2fSdrahn 
1537d2201f2fSdrahn 	  if (msg)
1538d2201f2fSdrahn 	    check_ok = info->callbacks->warning
1539d2201f2fSdrahn 	      (info, msg, name, input_bfd, input_section, rel->r_offset);
1540d2201f2fSdrahn 
1541d2201f2fSdrahn 	  if (! check_ok)
1542d2201f2fSdrahn 	    return FALSE;
1543d2201f2fSdrahn 	}
1544d2201f2fSdrahn     }
1545d2201f2fSdrahn 
1546d2201f2fSdrahn   return TRUE;
1547d2201f2fSdrahn }
1548d2201f2fSdrahn 
1549d2201f2fSdrahn /* Perform a single relocation.  By default we use the standard BFD
1550d2201f2fSdrahn    routines.  A few relocs we have to do ourselves.  */
1551d2201f2fSdrahn 
1552d2201f2fSdrahn static bfd_reloc_status_type
mmix_final_link_relocate(howto,input_section,contents,r_offset,r_addend,relocation,symname,symsec)1553d2201f2fSdrahn mmix_final_link_relocate (howto, input_section, contents,
1554d2201f2fSdrahn 			  r_offset, r_addend, relocation, symname, symsec)
1555d2201f2fSdrahn      reloc_howto_type *howto;
1556d2201f2fSdrahn      asection *input_section;
1557d2201f2fSdrahn      bfd_byte *contents;
1558d2201f2fSdrahn      bfd_vma r_offset;
1559d2201f2fSdrahn      bfd_signed_vma r_addend;
1560d2201f2fSdrahn      bfd_vma relocation;
1561d2201f2fSdrahn      const char *symname;
1562d2201f2fSdrahn      asection *symsec;
1563d2201f2fSdrahn {
1564d2201f2fSdrahn   bfd_reloc_status_type r = bfd_reloc_ok;
1565d2201f2fSdrahn   bfd_vma addr
1566d2201f2fSdrahn     = (input_section->output_section->vma
1567d2201f2fSdrahn        + input_section->output_offset
1568d2201f2fSdrahn        + r_offset);
1569d2201f2fSdrahn   bfd_signed_vma srel
1570d2201f2fSdrahn     = (bfd_signed_vma) relocation + r_addend;
1571d2201f2fSdrahn 
1572d2201f2fSdrahn   switch (howto->type)
1573d2201f2fSdrahn     {
1574d2201f2fSdrahn       /* All these are PC-relative.  */
1575*cf2f2c56Smiod     case R_MMIX_PUSHJ_STUBBABLE:
1576d2201f2fSdrahn     case R_MMIX_PUSHJ:
1577d2201f2fSdrahn     case R_MMIX_CBRANCH:
1578d2201f2fSdrahn     case R_MMIX_ADDR19:
1579d2201f2fSdrahn     case R_MMIX_GETA:
1580d2201f2fSdrahn     case R_MMIX_ADDR27:
1581d2201f2fSdrahn     case R_MMIX_JMP:
1582d2201f2fSdrahn       contents += r_offset;
1583d2201f2fSdrahn 
1584d2201f2fSdrahn       srel -= (input_section->output_section->vma
1585d2201f2fSdrahn 	       + input_section->output_offset
1586d2201f2fSdrahn 	       + r_offset);
1587d2201f2fSdrahn 
1588d2201f2fSdrahn       r = mmix_elf_perform_relocation (input_section, howto, contents,
1589d2201f2fSdrahn 				       addr, srel);
1590d2201f2fSdrahn       break;
1591d2201f2fSdrahn 
1592d2201f2fSdrahn     case R_MMIX_BASE_PLUS_OFFSET:
1593d2201f2fSdrahn       if (symsec == NULL)
1594d2201f2fSdrahn 	return bfd_reloc_undefined;
1595d2201f2fSdrahn 
1596d2201f2fSdrahn       /* Check that we're not relocating against a register symbol.  */
1597d2201f2fSdrahn       if (strcmp (bfd_get_section_name (symsec->owner, symsec),
1598d2201f2fSdrahn 		  MMIX_REG_CONTENTS_SECTION_NAME) == 0
1599d2201f2fSdrahn 	  || strcmp (bfd_get_section_name (symsec->owner, symsec),
1600d2201f2fSdrahn 		     MMIX_REG_SECTION_NAME) == 0)
1601d2201f2fSdrahn 	{
1602d2201f2fSdrahn 	  /* Note: This is separated out into two messages in order
1603d2201f2fSdrahn 	     to ease the translation into other languages.  */
1604d2201f2fSdrahn 	  if (symname == NULL || *symname == 0)
1605d2201f2fSdrahn 	    (*_bfd_error_handler)
1606d2201f2fSdrahn 	      (_("%s: base-plus-offset relocation against register symbol: (unknown) in %s"),
1607d2201f2fSdrahn 	       bfd_get_filename (input_section->owner),
1608d2201f2fSdrahn 	       bfd_get_section_name (symsec->owner, symsec));
1609d2201f2fSdrahn 	  else
1610d2201f2fSdrahn 	    (*_bfd_error_handler)
1611d2201f2fSdrahn 	      (_("%s: base-plus-offset relocation against register symbol: %s in %s"),
1612d2201f2fSdrahn 	       bfd_get_filename (input_section->owner), symname,
1613d2201f2fSdrahn 	       bfd_get_section_name (symsec->owner, symsec));
1614d2201f2fSdrahn 	  return bfd_reloc_overflow;
1615d2201f2fSdrahn 	}
1616d2201f2fSdrahn       goto do_mmix_reloc;
1617d2201f2fSdrahn 
1618d2201f2fSdrahn     case R_MMIX_REG_OR_BYTE:
1619d2201f2fSdrahn     case R_MMIX_REG:
1620d2201f2fSdrahn       /* For now, we handle these alike.  They must refer to an register
1621d2201f2fSdrahn 	 symbol, which is either relative to the register section and in
1622d2201f2fSdrahn 	 the range 0..255, or is in the register contents section with vma
1623d2201f2fSdrahn 	 regno * 8.  */
1624d2201f2fSdrahn 
1625d2201f2fSdrahn       /* FIXME: A better way to check for reg contents section?
1626d2201f2fSdrahn 	 FIXME: Postpone section->scaling to mmix_elf_perform_relocation? */
1627d2201f2fSdrahn       if (symsec == NULL)
1628d2201f2fSdrahn 	return bfd_reloc_undefined;
1629d2201f2fSdrahn 
1630d2201f2fSdrahn       if (strcmp (bfd_get_section_name (symsec->owner, symsec),
1631d2201f2fSdrahn 		  MMIX_REG_CONTENTS_SECTION_NAME) == 0)
1632d2201f2fSdrahn 	{
1633d2201f2fSdrahn 	  if ((srel & 7) != 0 || srel < 32*8 || srel > 255*8)
1634d2201f2fSdrahn 	    {
1635d2201f2fSdrahn 	      /* The bfd_reloc_outofrange return value, though intuitively
1636d2201f2fSdrahn 		 a better value, will not get us an error.  */
1637d2201f2fSdrahn 	      return bfd_reloc_overflow;
1638d2201f2fSdrahn 	    }
1639d2201f2fSdrahn 	  srel /= 8;
1640d2201f2fSdrahn 	}
1641d2201f2fSdrahn       else if (strcmp (bfd_get_section_name (symsec->owner, symsec),
1642d2201f2fSdrahn 		       MMIX_REG_SECTION_NAME) == 0)
1643d2201f2fSdrahn 	{
1644d2201f2fSdrahn 	  if (srel < 0 || srel > 255)
1645d2201f2fSdrahn 	    /* The bfd_reloc_outofrange return value, though intuitively a
1646d2201f2fSdrahn 	       better value, will not get us an error.  */
1647d2201f2fSdrahn 	    return bfd_reloc_overflow;
1648d2201f2fSdrahn 	}
1649d2201f2fSdrahn       else
1650d2201f2fSdrahn 	{
1651d2201f2fSdrahn 	  /* Note: This is separated out into two messages in order
1652d2201f2fSdrahn 	     to ease the translation into other languages.  */
1653d2201f2fSdrahn 	  if (symname == NULL || *symname == 0)
1654d2201f2fSdrahn 	    (*_bfd_error_handler)
1655d2201f2fSdrahn 	      (_("%s: register relocation against non-register symbol: (unknown) in %s"),
1656d2201f2fSdrahn 	       bfd_get_filename (input_section->owner),
1657d2201f2fSdrahn 	       bfd_get_section_name (symsec->owner, symsec));
1658d2201f2fSdrahn 	  else
1659d2201f2fSdrahn 	    (*_bfd_error_handler)
1660d2201f2fSdrahn 	      (_("%s: register relocation against non-register symbol: %s in %s"),
1661d2201f2fSdrahn 	       bfd_get_filename (input_section->owner), symname,
1662d2201f2fSdrahn 	       bfd_get_section_name (symsec->owner, symsec));
1663d2201f2fSdrahn 
1664d2201f2fSdrahn 	  /* The bfd_reloc_outofrange return value, though intuitively a
1665d2201f2fSdrahn 	     better value, will not get us an error.  */
1666d2201f2fSdrahn 	  return bfd_reloc_overflow;
1667d2201f2fSdrahn 	}
1668d2201f2fSdrahn     do_mmix_reloc:
1669d2201f2fSdrahn       contents += r_offset;
1670d2201f2fSdrahn       r = mmix_elf_perform_relocation (input_section, howto, contents,
1671d2201f2fSdrahn 				       addr, srel);
1672d2201f2fSdrahn       break;
1673d2201f2fSdrahn 
1674d2201f2fSdrahn     case R_MMIX_LOCAL:
1675d2201f2fSdrahn       /* This isn't a real relocation, it's just an assertion that the
1676d2201f2fSdrahn 	 final relocation value corresponds to a local register.  We
1677d2201f2fSdrahn 	 ignore the actual relocation; nothing is changed.  */
1678d2201f2fSdrahn       {
1679d2201f2fSdrahn 	asection *regsec
1680d2201f2fSdrahn 	  = bfd_get_section_by_name (input_section->output_section->owner,
1681d2201f2fSdrahn 				     MMIX_REG_CONTENTS_SECTION_NAME);
1682d2201f2fSdrahn 	bfd_vma first_global;
1683d2201f2fSdrahn 
1684d2201f2fSdrahn 	/* Check that this is an absolute value, or a reference to the
1685d2201f2fSdrahn 	   register contents section or the register (symbol) section.
1686d2201f2fSdrahn 	   Absolute numbers can get here as undefined section.  Undefined
1687d2201f2fSdrahn 	   symbols are signalled elsewhere, so there's no conflict in us
1688d2201f2fSdrahn 	   accidentally handling it.  */
1689d2201f2fSdrahn 	if (!bfd_is_abs_section (symsec)
1690d2201f2fSdrahn 	    && !bfd_is_und_section (symsec)
1691d2201f2fSdrahn 	    && strcmp (bfd_get_section_name (symsec->owner, symsec),
1692d2201f2fSdrahn 		       MMIX_REG_CONTENTS_SECTION_NAME) != 0
1693d2201f2fSdrahn 	    && strcmp (bfd_get_section_name (symsec->owner, symsec),
1694d2201f2fSdrahn 		       MMIX_REG_SECTION_NAME) != 0)
1695d2201f2fSdrahn 	{
1696d2201f2fSdrahn 	  (*_bfd_error_handler)
1697d2201f2fSdrahn 	    (_("%s: directive LOCAL valid only with a register or absolute value"),
1698d2201f2fSdrahn 	     bfd_get_filename (input_section->owner));
1699d2201f2fSdrahn 
1700d2201f2fSdrahn 	  return bfd_reloc_overflow;
1701d2201f2fSdrahn 	}
1702d2201f2fSdrahn 
1703d2201f2fSdrahn       /* If we don't have a register contents section, then $255 is the
1704d2201f2fSdrahn 	 first global register.  */
1705d2201f2fSdrahn       if (regsec == NULL)
1706d2201f2fSdrahn 	first_global = 255;
1707d2201f2fSdrahn       else
1708d2201f2fSdrahn 	{
1709d2201f2fSdrahn 	  first_global = bfd_get_section_vma (abfd, regsec) / 8;
1710d2201f2fSdrahn 	  if (strcmp (bfd_get_section_name (symsec->owner, symsec),
1711d2201f2fSdrahn 		      MMIX_REG_CONTENTS_SECTION_NAME) == 0)
1712d2201f2fSdrahn 	    {
1713d2201f2fSdrahn 	      if ((srel & 7) != 0 || srel < 32*8 || srel > 255*8)
1714d2201f2fSdrahn 		/* The bfd_reloc_outofrange return value, though
1715d2201f2fSdrahn 		   intuitively a better value, will not get us an error.  */
1716d2201f2fSdrahn 		return bfd_reloc_overflow;
1717d2201f2fSdrahn 	      srel /= 8;
1718d2201f2fSdrahn 	    }
1719d2201f2fSdrahn 	}
1720d2201f2fSdrahn 
1721d2201f2fSdrahn 	if ((bfd_vma) srel >= first_global)
1722d2201f2fSdrahn 	  {
1723d2201f2fSdrahn 	    /* FIXME: Better error message.  */
1724d2201f2fSdrahn 	    (*_bfd_error_handler)
1725d2201f2fSdrahn 	      (_("%s: LOCAL directive: Register $%ld is not a local register.  First global register is $%ld."),
1726d2201f2fSdrahn 	       bfd_get_filename (input_section->owner), (long) srel, (long) first_global);
1727d2201f2fSdrahn 
1728d2201f2fSdrahn 	    return bfd_reloc_overflow;
1729d2201f2fSdrahn 	  }
1730d2201f2fSdrahn       }
1731d2201f2fSdrahn       r = bfd_reloc_ok;
1732d2201f2fSdrahn       break;
1733d2201f2fSdrahn 
1734d2201f2fSdrahn     default:
1735d2201f2fSdrahn       r = _bfd_final_link_relocate (howto, input_section->owner, input_section,
1736d2201f2fSdrahn 				    contents, r_offset,
1737d2201f2fSdrahn 				    relocation, r_addend);
1738d2201f2fSdrahn     }
1739d2201f2fSdrahn 
1740d2201f2fSdrahn   return r;
1741d2201f2fSdrahn }
1742d2201f2fSdrahn 
1743d2201f2fSdrahn /* Return the section that should be marked against GC for a given
1744d2201f2fSdrahn    relocation.  */
1745d2201f2fSdrahn 
1746d2201f2fSdrahn static asection *
mmix_elf_gc_mark_hook(sec,info,rel,h,sym)1747d2201f2fSdrahn mmix_elf_gc_mark_hook (sec, info, rel, h, sym)
1748d2201f2fSdrahn      asection *sec;
1749d2201f2fSdrahn      struct bfd_link_info *info ATTRIBUTE_UNUSED;
1750d2201f2fSdrahn      Elf_Internal_Rela *rel;
1751d2201f2fSdrahn      struct elf_link_hash_entry *h;
1752d2201f2fSdrahn      Elf_Internal_Sym *sym;
1753d2201f2fSdrahn {
1754d2201f2fSdrahn   if (h != NULL)
1755d2201f2fSdrahn     {
1756d2201f2fSdrahn       switch (ELF64_R_TYPE (rel->r_info))
1757d2201f2fSdrahn 	{
1758d2201f2fSdrahn 	case R_MMIX_GNU_VTINHERIT:
1759d2201f2fSdrahn 	case R_MMIX_GNU_VTENTRY:
1760d2201f2fSdrahn 	  break;
1761d2201f2fSdrahn 
1762d2201f2fSdrahn 	default:
1763d2201f2fSdrahn 	  switch (h->root.type)
1764d2201f2fSdrahn 	    {
1765d2201f2fSdrahn 	    case bfd_link_hash_defined:
1766d2201f2fSdrahn 	    case bfd_link_hash_defweak:
1767d2201f2fSdrahn 	      return h->root.u.def.section;
1768d2201f2fSdrahn 
1769d2201f2fSdrahn 	    case bfd_link_hash_common:
1770d2201f2fSdrahn 	      return h->root.u.c.p->section;
1771d2201f2fSdrahn 
1772d2201f2fSdrahn 	    default:
1773d2201f2fSdrahn 	      break;
1774d2201f2fSdrahn 	    }
1775d2201f2fSdrahn 	}
1776d2201f2fSdrahn     }
1777d2201f2fSdrahn   else
1778d2201f2fSdrahn     return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
1779d2201f2fSdrahn 
1780d2201f2fSdrahn   return NULL;
1781d2201f2fSdrahn }
1782d2201f2fSdrahn 
1783d2201f2fSdrahn /* Update relocation info for a GC-excluded section.  We could supposedly
1784d2201f2fSdrahn    perform the allocation after GC, but there's no suitable hook between
1785d2201f2fSdrahn    GC (or section merge) and the point when all input sections must be
1786d2201f2fSdrahn    present.  Better to waste some memory and (perhaps) a little time.  */
1787d2201f2fSdrahn 
1788d2201f2fSdrahn static bfd_boolean
mmix_elf_gc_sweep_hook(abfd,info,sec,relocs)1789d2201f2fSdrahn mmix_elf_gc_sweep_hook (abfd, info, sec, relocs)
1790d2201f2fSdrahn      bfd *abfd ATTRIBUTE_UNUSED;
1791d2201f2fSdrahn      struct bfd_link_info *info ATTRIBUTE_UNUSED;
1792d2201f2fSdrahn      asection *sec ATTRIBUTE_UNUSED;
1793d2201f2fSdrahn      const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED;
1794d2201f2fSdrahn {
1795d2201f2fSdrahn   struct bpo_reloc_section_info *bpodata
1796d2201f2fSdrahn     = mmix_elf_section_data (sec)->bpo.reloc;
1797d2201f2fSdrahn   asection *allocated_gregs_section;
1798d2201f2fSdrahn 
1799d2201f2fSdrahn   /* If no bpodata here, we have nothing to do.  */
1800d2201f2fSdrahn   if (bpodata == NULL)
1801d2201f2fSdrahn     return TRUE;
1802d2201f2fSdrahn 
1803d2201f2fSdrahn   allocated_gregs_section = bpodata->bpo_greg_section;
1804d2201f2fSdrahn 
1805d2201f2fSdrahn   mmix_elf_section_data (allocated_gregs_section)->bpo.greg->n_bpo_relocs
1806d2201f2fSdrahn     -= bpodata->n_bpo_relocs_this_section;
1807d2201f2fSdrahn 
1808d2201f2fSdrahn   return TRUE;
1809d2201f2fSdrahn }
1810d2201f2fSdrahn 
1811d2201f2fSdrahn /* Sort register relocs to come before expanding relocs.  */
1812d2201f2fSdrahn 
1813d2201f2fSdrahn static int
mmix_elf_sort_relocs(p1,p2)1814d2201f2fSdrahn mmix_elf_sort_relocs (p1, p2)
1815d2201f2fSdrahn      const PTR p1;
1816d2201f2fSdrahn      const PTR p2;
1817d2201f2fSdrahn {
1818d2201f2fSdrahn   const Elf_Internal_Rela *r1 = (const Elf_Internal_Rela *) p1;
1819d2201f2fSdrahn   const Elf_Internal_Rela *r2 = (const Elf_Internal_Rela *) p2;
1820d2201f2fSdrahn   int r1_is_reg, r2_is_reg;
1821d2201f2fSdrahn 
1822d2201f2fSdrahn   /* Sort primarily on r_offset & ~3, so relocs are done to consecutive
1823d2201f2fSdrahn      insns.  */
1824d2201f2fSdrahn   if ((r1->r_offset & ~(bfd_vma) 3) > (r2->r_offset & ~(bfd_vma) 3))
1825d2201f2fSdrahn     return 1;
1826d2201f2fSdrahn   else if ((r1->r_offset & ~(bfd_vma) 3) < (r2->r_offset & ~(bfd_vma) 3))
1827d2201f2fSdrahn     return -1;
1828d2201f2fSdrahn 
1829d2201f2fSdrahn   r1_is_reg
1830d2201f2fSdrahn     = (ELF64_R_TYPE (r1->r_info) == R_MMIX_REG_OR_BYTE
1831d2201f2fSdrahn        || ELF64_R_TYPE (r1->r_info) == R_MMIX_REG);
1832d2201f2fSdrahn   r2_is_reg
1833d2201f2fSdrahn     = (ELF64_R_TYPE (r2->r_info) == R_MMIX_REG_OR_BYTE
1834d2201f2fSdrahn        || ELF64_R_TYPE (r2->r_info) == R_MMIX_REG);
1835d2201f2fSdrahn   if (r1_is_reg != r2_is_reg)
1836d2201f2fSdrahn     return r2_is_reg - r1_is_reg;
1837d2201f2fSdrahn 
1838d2201f2fSdrahn   /* Neither or both are register relocs.  Then sort on full offset.  */
1839d2201f2fSdrahn   if (r1->r_offset > r2->r_offset)
1840d2201f2fSdrahn     return 1;
1841d2201f2fSdrahn   else if (r1->r_offset < r2->r_offset)
1842d2201f2fSdrahn     return -1;
1843d2201f2fSdrahn   return 0;
1844d2201f2fSdrahn }
1845d2201f2fSdrahn 
1846d2201f2fSdrahn /* Subset of mmix_elf_check_relocs, common to ELF and mmo linking.  */
1847d2201f2fSdrahn 
1848d2201f2fSdrahn static bfd_boolean
mmix_elf_check_common_relocs(abfd,info,sec,relocs)1849d2201f2fSdrahn mmix_elf_check_common_relocs  (abfd, info, sec, relocs)
1850d2201f2fSdrahn      bfd *abfd;
1851d2201f2fSdrahn      struct bfd_link_info *info;
1852d2201f2fSdrahn      asection *sec;
1853d2201f2fSdrahn      const Elf_Internal_Rela *relocs;
1854d2201f2fSdrahn {
1855d2201f2fSdrahn   bfd *bpo_greg_owner = NULL;
1856d2201f2fSdrahn   asection *allocated_gregs_section = NULL;
1857d2201f2fSdrahn   struct bpo_greg_section_info *gregdata = NULL;
1858d2201f2fSdrahn   struct bpo_reloc_section_info *bpodata = NULL;
1859d2201f2fSdrahn   const Elf_Internal_Rela *rel;
1860d2201f2fSdrahn   const Elf_Internal_Rela *rel_end;
1861d2201f2fSdrahn 
1862d2201f2fSdrahn   /* We currently have to abuse this COFF-specific member, since there's
1863d2201f2fSdrahn      no target-machine-dedicated member.  There's no alternative outside
1864d2201f2fSdrahn      the bfd_link_info struct; we can't specialize a hash-table since
1865d2201f2fSdrahn      they're different between ELF and mmo.  */
1866d2201f2fSdrahn   bpo_greg_owner = (bfd *) info->base_file;
1867d2201f2fSdrahn 
1868d2201f2fSdrahn   rel_end = relocs + sec->reloc_count;
1869d2201f2fSdrahn   for (rel = relocs; rel < rel_end; rel++)
1870d2201f2fSdrahn     {
1871d2201f2fSdrahn       switch (ELF64_R_TYPE (rel->r_info))
1872d2201f2fSdrahn         {
1873d2201f2fSdrahn 	  /* This relocation causes a GREG allocation.  We need to count
1874d2201f2fSdrahn 	     them, and we need to create a section for them, so we need an
1875d2201f2fSdrahn 	     object to fake as the owner of that section.  We can't use
1876d2201f2fSdrahn 	     the ELF dynobj for this, since the ELF bits assume lots of
1877d2201f2fSdrahn 	     DSO-related stuff if that member is non-NULL.  */
1878d2201f2fSdrahn 	case R_MMIX_BASE_PLUS_OFFSET:
1879*cf2f2c56Smiod 	  /* We don't do anything with this reloc for a relocatable link.  */
1880*cf2f2c56Smiod 	  if (info->relocatable)
1881*cf2f2c56Smiod 	    break;
1882*cf2f2c56Smiod 
1883d2201f2fSdrahn 	  if (bpo_greg_owner == NULL)
1884d2201f2fSdrahn 	    {
1885d2201f2fSdrahn 	      bpo_greg_owner = abfd;
1886d2201f2fSdrahn 	      info->base_file = (PTR) bpo_greg_owner;
1887d2201f2fSdrahn 	    }
1888d2201f2fSdrahn 
1889d2201f2fSdrahn 	  if (allocated_gregs_section == NULL)
1890d2201f2fSdrahn 	    allocated_gregs_section
1891d2201f2fSdrahn 	      = bfd_get_section_by_name (bpo_greg_owner,
1892d2201f2fSdrahn 					 MMIX_LD_ALLOCATED_REG_CONTENTS_SECTION_NAME);
1893d2201f2fSdrahn 
1894d2201f2fSdrahn 	  if (allocated_gregs_section == NULL)
1895d2201f2fSdrahn 	    {
1896d2201f2fSdrahn 	      allocated_gregs_section
1897d2201f2fSdrahn 		= bfd_make_section (bpo_greg_owner,
1898d2201f2fSdrahn 				    MMIX_LD_ALLOCATED_REG_CONTENTS_SECTION_NAME);
1899d2201f2fSdrahn 	      /* Setting both SEC_ALLOC and SEC_LOAD means the section is
1900d2201f2fSdrahn 		 treated like any other section, and we'd get errors for
1901d2201f2fSdrahn 		 address overlap with the text section.  Let's set none of
1902d2201f2fSdrahn 		 those flags, as that is what currently happens for usual
1903d2201f2fSdrahn 		 GREG allocations, and that works.  */
1904d2201f2fSdrahn 	      if (allocated_gregs_section == NULL
1905d2201f2fSdrahn 		  || !bfd_set_section_flags (bpo_greg_owner,
1906d2201f2fSdrahn 					     allocated_gregs_section,
1907d2201f2fSdrahn 					     (SEC_HAS_CONTENTS
1908d2201f2fSdrahn 					      | SEC_IN_MEMORY
1909d2201f2fSdrahn 					      | SEC_LINKER_CREATED))
1910d2201f2fSdrahn 		  || !bfd_set_section_alignment (bpo_greg_owner,
1911d2201f2fSdrahn 						 allocated_gregs_section,
1912d2201f2fSdrahn 						 3))
1913d2201f2fSdrahn 		return FALSE;
1914d2201f2fSdrahn 
1915d2201f2fSdrahn 	      gregdata = (struct bpo_greg_section_info *)
1916d2201f2fSdrahn 		bfd_zalloc (bpo_greg_owner, sizeof (struct bpo_greg_section_info));
1917d2201f2fSdrahn 	      if (gregdata == NULL)
1918d2201f2fSdrahn 		return FALSE;
1919d2201f2fSdrahn 	      mmix_elf_section_data (allocated_gregs_section)->bpo.greg
1920d2201f2fSdrahn 		= gregdata;
1921d2201f2fSdrahn 	    }
1922d2201f2fSdrahn 	  else if (gregdata == NULL)
1923d2201f2fSdrahn 	    gregdata
1924d2201f2fSdrahn 	      = mmix_elf_section_data (allocated_gregs_section)->bpo.greg;
1925d2201f2fSdrahn 
1926d2201f2fSdrahn 	  /* Get ourselves some auxiliary info for the BPO-relocs.  */
1927d2201f2fSdrahn 	  if (bpodata == NULL)
1928d2201f2fSdrahn 	    {
1929d2201f2fSdrahn 	      /* No use doing a separate iteration pass to find the upper
1930d2201f2fSdrahn 		 limit - just use the number of relocs.  */
1931d2201f2fSdrahn 	      bpodata = (struct bpo_reloc_section_info *)
1932d2201f2fSdrahn 		bfd_alloc (bpo_greg_owner,
1933d2201f2fSdrahn 			   sizeof (struct bpo_reloc_section_info)
1934d2201f2fSdrahn 			   * (sec->reloc_count + 1));
1935d2201f2fSdrahn 	      if (bpodata == NULL)
1936d2201f2fSdrahn 		return FALSE;
1937d2201f2fSdrahn 	      mmix_elf_section_data (sec)->bpo.reloc = bpodata;
1938d2201f2fSdrahn 	      bpodata->first_base_plus_offset_reloc
1939d2201f2fSdrahn 		= bpodata->bpo_index
1940d2201f2fSdrahn 		= gregdata->n_max_bpo_relocs;
1941d2201f2fSdrahn 	      bpodata->bpo_greg_section
1942d2201f2fSdrahn 		= allocated_gregs_section;
1943d2201f2fSdrahn 	      bpodata->n_bpo_relocs_this_section = 0;
1944d2201f2fSdrahn 	    }
1945d2201f2fSdrahn 
1946d2201f2fSdrahn 	  bpodata->n_bpo_relocs_this_section++;
1947d2201f2fSdrahn 	  gregdata->n_max_bpo_relocs++;
1948d2201f2fSdrahn 
1949d2201f2fSdrahn 	  /* We don't get another chance to set this before GC; we've not
1950*cf2f2c56Smiod 	     set up any hook that runs before GC.  */
1951d2201f2fSdrahn 	  gregdata->n_bpo_relocs
1952d2201f2fSdrahn 	    = gregdata->n_max_bpo_relocs;
1953d2201f2fSdrahn 	  break;
1954*cf2f2c56Smiod 
1955*cf2f2c56Smiod 	case R_MMIX_PUSHJ_STUBBABLE:
1956*cf2f2c56Smiod 	  mmix_elf_section_data (sec)->pjs.n_pushj_relocs++;
1957*cf2f2c56Smiod 	  break;
1958d2201f2fSdrahn 	}
1959d2201f2fSdrahn     }
1960d2201f2fSdrahn 
1961*cf2f2c56Smiod   /* Allocate per-reloc stub storage and initialize it to the max stub
1962*cf2f2c56Smiod      size.  */
1963*cf2f2c56Smiod   if (mmix_elf_section_data (sec)->pjs.n_pushj_relocs != 0)
1964*cf2f2c56Smiod     {
1965*cf2f2c56Smiod       size_t i;
1966*cf2f2c56Smiod 
1967*cf2f2c56Smiod       mmix_elf_section_data (sec)->pjs.stub_size
1968*cf2f2c56Smiod 	= bfd_alloc (abfd, mmix_elf_section_data (sec)->pjs.n_pushj_relocs
1969*cf2f2c56Smiod 		     * sizeof (mmix_elf_section_data (sec)
1970*cf2f2c56Smiod 			       ->pjs.stub_size[0]));
1971*cf2f2c56Smiod       if (mmix_elf_section_data (sec)->pjs.stub_size == NULL)
1972*cf2f2c56Smiod 	return FALSE;
1973*cf2f2c56Smiod 
1974*cf2f2c56Smiod       for (i = 0; i < mmix_elf_section_data (sec)->pjs.n_pushj_relocs; i++)
1975*cf2f2c56Smiod 	mmix_elf_section_data (sec)->pjs.stub_size[i] = MAX_PUSHJ_STUB_SIZE;
1976*cf2f2c56Smiod     }
1977*cf2f2c56Smiod 
1978d2201f2fSdrahn   return TRUE;
1979d2201f2fSdrahn }
1980d2201f2fSdrahn 
1981d2201f2fSdrahn /* Look through the relocs for a section during the first phase.  */
1982d2201f2fSdrahn 
1983d2201f2fSdrahn static bfd_boolean
mmix_elf_check_relocs(abfd,info,sec,relocs)1984d2201f2fSdrahn mmix_elf_check_relocs (abfd, info, sec, relocs)
1985d2201f2fSdrahn      bfd *abfd;
1986d2201f2fSdrahn      struct bfd_link_info *info;
1987d2201f2fSdrahn      asection *sec;
1988d2201f2fSdrahn      const Elf_Internal_Rela *relocs;
1989d2201f2fSdrahn {
1990d2201f2fSdrahn   Elf_Internal_Shdr *symtab_hdr;
1991d2201f2fSdrahn   struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
1992d2201f2fSdrahn   const Elf_Internal_Rela *rel;
1993d2201f2fSdrahn   const Elf_Internal_Rela *rel_end;
1994d2201f2fSdrahn 
1995d2201f2fSdrahn   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
1996d2201f2fSdrahn   sym_hashes = elf_sym_hashes (abfd);
1997d2201f2fSdrahn   sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof(Elf64_External_Sym);
1998d2201f2fSdrahn   if (!elf_bad_symtab (abfd))
1999d2201f2fSdrahn     sym_hashes_end -= symtab_hdr->sh_info;
2000d2201f2fSdrahn 
2001d2201f2fSdrahn   /* First we sort the relocs so that any register relocs come before
2002d2201f2fSdrahn      expansion-relocs to the same insn.  FIXME: Not done for mmo.  */
2003d2201f2fSdrahn   qsort ((PTR) relocs, sec->reloc_count, sizeof (Elf_Internal_Rela),
2004d2201f2fSdrahn 	 mmix_elf_sort_relocs);
2005d2201f2fSdrahn 
2006d2201f2fSdrahn   /* Do the common part.  */
2007d2201f2fSdrahn   if (!mmix_elf_check_common_relocs (abfd, info, sec, relocs))
2008d2201f2fSdrahn     return FALSE;
2009d2201f2fSdrahn 
2010*cf2f2c56Smiod   if (info->relocatable)
2011*cf2f2c56Smiod     return TRUE;
2012*cf2f2c56Smiod 
2013d2201f2fSdrahn   rel_end = relocs + sec->reloc_count;
2014d2201f2fSdrahn   for (rel = relocs; rel < rel_end; rel++)
2015d2201f2fSdrahn     {
2016d2201f2fSdrahn       struct elf_link_hash_entry *h;
2017d2201f2fSdrahn       unsigned long r_symndx;
2018d2201f2fSdrahn 
2019d2201f2fSdrahn       r_symndx = ELF64_R_SYM (rel->r_info);
2020d2201f2fSdrahn       if (r_symndx < symtab_hdr->sh_info)
2021d2201f2fSdrahn         h = NULL;
2022d2201f2fSdrahn       else
2023d2201f2fSdrahn         h = sym_hashes[r_symndx - symtab_hdr->sh_info];
2024d2201f2fSdrahn 
2025d2201f2fSdrahn       switch (ELF64_R_TYPE (rel->r_info))
2026d2201f2fSdrahn 	{
2027d2201f2fSdrahn         /* This relocation describes the C++ object vtable hierarchy.
2028d2201f2fSdrahn            Reconstruct it for later use during GC.  */
2029d2201f2fSdrahn         case R_MMIX_GNU_VTINHERIT:
2030*cf2f2c56Smiod           if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
2031d2201f2fSdrahn             return FALSE;
2032d2201f2fSdrahn           break;
2033d2201f2fSdrahn 
2034d2201f2fSdrahn         /* This relocation describes which C++ vtable entries are actually
2035d2201f2fSdrahn            used.  Record for later use during GC.  */
2036d2201f2fSdrahn         case R_MMIX_GNU_VTENTRY:
2037*cf2f2c56Smiod           if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
2038d2201f2fSdrahn             return FALSE;
2039d2201f2fSdrahn           break;
2040d2201f2fSdrahn 	}
2041d2201f2fSdrahn     }
2042d2201f2fSdrahn 
2043d2201f2fSdrahn   return TRUE;
2044d2201f2fSdrahn }
2045d2201f2fSdrahn 
2046d2201f2fSdrahn /* Wrapper for mmix_elf_check_common_relocs, called when linking to mmo.
2047d2201f2fSdrahn    Copied from elf_link_add_object_symbols.  */
2048d2201f2fSdrahn 
2049d2201f2fSdrahn bfd_boolean
_bfd_mmix_check_all_relocs(abfd,info)2050d2201f2fSdrahn _bfd_mmix_check_all_relocs (abfd, info)
2051d2201f2fSdrahn      bfd *abfd;
2052d2201f2fSdrahn      struct bfd_link_info *info;
2053d2201f2fSdrahn {
2054d2201f2fSdrahn   asection *o;
2055d2201f2fSdrahn 
2056d2201f2fSdrahn   for (o = abfd->sections; o != NULL; o = o->next)
2057d2201f2fSdrahn     {
2058d2201f2fSdrahn       Elf_Internal_Rela *internal_relocs;
2059d2201f2fSdrahn       bfd_boolean ok;
2060d2201f2fSdrahn 
2061d2201f2fSdrahn       if ((o->flags & SEC_RELOC) == 0
2062d2201f2fSdrahn 	  || o->reloc_count == 0
2063d2201f2fSdrahn 	  || ((info->strip == strip_all || info->strip == strip_debugger)
2064d2201f2fSdrahn 	      && (o->flags & SEC_DEBUGGING) != 0)
2065d2201f2fSdrahn 	  || bfd_is_abs_section (o->output_section))
2066d2201f2fSdrahn 	continue;
2067d2201f2fSdrahn 
2068d2201f2fSdrahn       internal_relocs
2069*cf2f2c56Smiod 	= _bfd_elf_link_read_relocs (abfd, o, (PTR) NULL,
2070d2201f2fSdrahn 				     (Elf_Internal_Rela *) NULL,
2071d2201f2fSdrahn 				     info->keep_memory);
2072d2201f2fSdrahn       if (internal_relocs == NULL)
2073d2201f2fSdrahn 	return FALSE;
2074d2201f2fSdrahn 
2075d2201f2fSdrahn       ok = mmix_elf_check_common_relocs (abfd, info, o, internal_relocs);
2076d2201f2fSdrahn 
2077d2201f2fSdrahn       if (! info->keep_memory)
2078d2201f2fSdrahn 	free (internal_relocs);
2079d2201f2fSdrahn 
2080d2201f2fSdrahn       if (! ok)
2081d2201f2fSdrahn 	return FALSE;
2082d2201f2fSdrahn     }
2083d2201f2fSdrahn 
2084d2201f2fSdrahn   return TRUE;
2085d2201f2fSdrahn }
2086d2201f2fSdrahn 
2087d2201f2fSdrahn /* Change symbols relative to the reg contents section to instead be to
2088d2201f2fSdrahn    the register section, and scale them down to correspond to the register
2089d2201f2fSdrahn    number.  */
2090d2201f2fSdrahn 
2091d2201f2fSdrahn static bfd_boolean
mmix_elf_link_output_symbol_hook(info,name,sym,input_sec,h)2092*cf2f2c56Smiod mmix_elf_link_output_symbol_hook (info, name, sym, input_sec, h)
2093d2201f2fSdrahn      struct bfd_link_info *info ATTRIBUTE_UNUSED;
2094d2201f2fSdrahn      const char *name ATTRIBUTE_UNUSED;
2095d2201f2fSdrahn      Elf_Internal_Sym *sym;
2096d2201f2fSdrahn      asection *input_sec;
2097*cf2f2c56Smiod      struct elf_link_hash_entry *h ATTRIBUTE_UNUSED;
2098d2201f2fSdrahn {
2099d2201f2fSdrahn   if (input_sec != NULL
2100d2201f2fSdrahn       && input_sec->name != NULL
2101d2201f2fSdrahn       && ELF_ST_TYPE (sym->st_info) != STT_SECTION
2102d2201f2fSdrahn       && strcmp (input_sec->name, MMIX_REG_CONTENTS_SECTION_NAME) == 0)
2103d2201f2fSdrahn     {
2104d2201f2fSdrahn       sym->st_value /= 8;
2105d2201f2fSdrahn       sym->st_shndx = SHN_REGISTER;
2106d2201f2fSdrahn     }
2107d2201f2fSdrahn 
2108d2201f2fSdrahn   return TRUE;
2109d2201f2fSdrahn }
2110d2201f2fSdrahn 
2111d2201f2fSdrahn /* We fake a register section that holds values that are register numbers.
2112d2201f2fSdrahn    Having a SHN_REGISTER and register section translates better to other
2113d2201f2fSdrahn    formats (e.g. mmo) than for example a STT_REGISTER attribute.
2114d2201f2fSdrahn    This section faking is based on a construct in elf32-mips.c.  */
2115d2201f2fSdrahn static asection mmix_elf_reg_section;
2116d2201f2fSdrahn static asymbol mmix_elf_reg_section_symbol;
2117d2201f2fSdrahn static asymbol *mmix_elf_reg_section_symbol_ptr;
2118d2201f2fSdrahn 
2119*cf2f2c56Smiod /* Handle the special section numbers that a symbol may use.  */
2120d2201f2fSdrahn 
2121d2201f2fSdrahn void
mmix_elf_symbol_processing(abfd,asym)2122d2201f2fSdrahn mmix_elf_symbol_processing (abfd, asym)
2123d2201f2fSdrahn      bfd *abfd ATTRIBUTE_UNUSED;
2124d2201f2fSdrahn      asymbol *asym;
2125d2201f2fSdrahn {
2126d2201f2fSdrahn   elf_symbol_type *elfsym;
2127d2201f2fSdrahn 
2128d2201f2fSdrahn   elfsym = (elf_symbol_type *) asym;
2129d2201f2fSdrahn   switch (elfsym->internal_elf_sym.st_shndx)
2130d2201f2fSdrahn     {
2131d2201f2fSdrahn     case SHN_REGISTER:
2132d2201f2fSdrahn       if (mmix_elf_reg_section.name == NULL)
2133d2201f2fSdrahn 	{
2134d2201f2fSdrahn 	  /* Initialize the register section.  */
2135d2201f2fSdrahn 	  mmix_elf_reg_section.name = MMIX_REG_SECTION_NAME;
2136d2201f2fSdrahn 	  mmix_elf_reg_section.flags = SEC_NO_FLAGS;
2137d2201f2fSdrahn 	  mmix_elf_reg_section.output_section = &mmix_elf_reg_section;
2138d2201f2fSdrahn 	  mmix_elf_reg_section.symbol = &mmix_elf_reg_section_symbol;
2139d2201f2fSdrahn 	  mmix_elf_reg_section.symbol_ptr_ptr = &mmix_elf_reg_section_symbol_ptr;
2140d2201f2fSdrahn 	  mmix_elf_reg_section_symbol.name = MMIX_REG_SECTION_NAME;
2141d2201f2fSdrahn 	  mmix_elf_reg_section_symbol.flags = BSF_SECTION_SYM;
2142d2201f2fSdrahn 	  mmix_elf_reg_section_symbol.section = &mmix_elf_reg_section;
2143d2201f2fSdrahn 	  mmix_elf_reg_section_symbol_ptr = &mmix_elf_reg_section_symbol;
2144d2201f2fSdrahn 	}
2145d2201f2fSdrahn       asym->section = &mmix_elf_reg_section;
2146d2201f2fSdrahn       break;
2147d2201f2fSdrahn 
2148d2201f2fSdrahn     default:
2149d2201f2fSdrahn       break;
2150d2201f2fSdrahn     }
2151d2201f2fSdrahn }
2152d2201f2fSdrahn 
2153d2201f2fSdrahn /* Given a BFD section, try to locate the corresponding ELF section
2154d2201f2fSdrahn    index.  */
2155d2201f2fSdrahn 
2156d2201f2fSdrahn static bfd_boolean
mmix_elf_section_from_bfd_section(abfd,sec,retval)2157d2201f2fSdrahn mmix_elf_section_from_bfd_section (abfd, sec, retval)
2158d2201f2fSdrahn      bfd *                 abfd ATTRIBUTE_UNUSED;
2159d2201f2fSdrahn      asection *            sec;
2160d2201f2fSdrahn      int *                 retval;
2161d2201f2fSdrahn {
2162d2201f2fSdrahn   if (strcmp (bfd_get_section_name (abfd, sec), MMIX_REG_SECTION_NAME) == 0)
2163d2201f2fSdrahn     *retval = SHN_REGISTER;
2164d2201f2fSdrahn   else
2165d2201f2fSdrahn     return FALSE;
2166d2201f2fSdrahn 
2167d2201f2fSdrahn   return TRUE;
2168d2201f2fSdrahn }
2169d2201f2fSdrahn 
2170d2201f2fSdrahn /* Hook called by the linker routine which adds symbols from an object
2171d2201f2fSdrahn    file.  We must handle the special SHN_REGISTER section number here.
2172d2201f2fSdrahn 
2173d2201f2fSdrahn    We also check that we only have *one* each of the section-start
2174d2201f2fSdrahn    symbols, since otherwise having two with the same value would cause
2175d2201f2fSdrahn    them to be "merged", but with the contents serialized.  */
2176d2201f2fSdrahn 
2177d2201f2fSdrahn bfd_boolean
mmix_elf_add_symbol_hook(abfd,info,sym,namep,flagsp,secp,valp)2178d2201f2fSdrahn mmix_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp)
2179d2201f2fSdrahn      bfd *abfd;
2180d2201f2fSdrahn      struct bfd_link_info *info ATTRIBUTE_UNUSED;
2181*cf2f2c56Smiod      Elf_Internal_Sym *sym;
2182d2201f2fSdrahn      const char **namep ATTRIBUTE_UNUSED;
2183d2201f2fSdrahn      flagword *flagsp ATTRIBUTE_UNUSED;
2184d2201f2fSdrahn      asection **secp;
2185d2201f2fSdrahn      bfd_vma *valp ATTRIBUTE_UNUSED;
2186d2201f2fSdrahn {
2187d2201f2fSdrahn   if (sym->st_shndx == SHN_REGISTER)
2188d2201f2fSdrahn     *secp = bfd_make_section_old_way (abfd, MMIX_REG_SECTION_NAME);
2189d2201f2fSdrahn   else if ((*namep)[0] == '_' && (*namep)[1] == '_' && (*namep)[2] == '.'
2190d2201f2fSdrahn 	   && strncmp (*namep, MMIX_LOC_SECTION_START_SYMBOL_PREFIX,
2191d2201f2fSdrahn 		       strlen (MMIX_LOC_SECTION_START_SYMBOL_PREFIX)) == 0)
2192d2201f2fSdrahn     {
2193d2201f2fSdrahn       /* See if we have another one.  */
2194d2201f2fSdrahn       struct bfd_link_hash_entry *h = bfd_link_hash_lookup (info->hash,
2195d2201f2fSdrahn 							    *namep,
2196d2201f2fSdrahn 							    FALSE,
2197d2201f2fSdrahn 							    FALSE,
2198d2201f2fSdrahn 							    FALSE);
2199d2201f2fSdrahn 
2200d2201f2fSdrahn       if (h != NULL && h->type != bfd_link_hash_undefined)
2201d2201f2fSdrahn 	{
2202d2201f2fSdrahn 	  /* How do we get the asymbol (or really: the filename) from h?
2203d2201f2fSdrahn 	     h->u.def.section->owner is NULL.  */
2204d2201f2fSdrahn 	  ((*_bfd_error_handler)
2205d2201f2fSdrahn 	   (_("%s: Error: multiple definition of `%s'; start of %s is set in a earlier linked file\n"),
2206d2201f2fSdrahn 	    bfd_get_filename (abfd), *namep,
2207d2201f2fSdrahn 	    *namep + strlen (MMIX_LOC_SECTION_START_SYMBOL_PREFIX)));
2208d2201f2fSdrahn 	   bfd_set_error (bfd_error_bad_value);
2209d2201f2fSdrahn 	   return FALSE;
2210d2201f2fSdrahn 	}
2211d2201f2fSdrahn     }
2212d2201f2fSdrahn 
2213d2201f2fSdrahn   return TRUE;
2214d2201f2fSdrahn }
2215d2201f2fSdrahn 
2216d2201f2fSdrahn /* We consider symbols matching "L.*:[0-9]+" to be local symbols.  */
2217d2201f2fSdrahn 
2218d2201f2fSdrahn bfd_boolean
mmix_elf_is_local_label_name(abfd,name)2219d2201f2fSdrahn mmix_elf_is_local_label_name (abfd, name)
2220d2201f2fSdrahn      bfd *abfd;
2221d2201f2fSdrahn      const char *name;
2222d2201f2fSdrahn {
2223d2201f2fSdrahn   const char *colpos;
2224d2201f2fSdrahn   int digits;
2225d2201f2fSdrahn 
2226d2201f2fSdrahn   /* Also include the default local-label definition.  */
2227d2201f2fSdrahn   if (_bfd_elf_is_local_label_name (abfd, name))
2228d2201f2fSdrahn     return TRUE;
2229d2201f2fSdrahn 
2230d2201f2fSdrahn   if (*name != 'L')
2231d2201f2fSdrahn     return FALSE;
2232d2201f2fSdrahn 
2233d2201f2fSdrahn   /* If there's no ":", or more than one, it's not a local symbol.  */
2234d2201f2fSdrahn   colpos = strchr (name, ':');
2235d2201f2fSdrahn   if (colpos == NULL || strchr (colpos + 1, ':') != NULL)
2236d2201f2fSdrahn     return FALSE;
2237d2201f2fSdrahn 
2238d2201f2fSdrahn   /* Check that there are remaining characters and that they are digits.  */
2239d2201f2fSdrahn   if (colpos[1] == 0)
2240d2201f2fSdrahn     return FALSE;
2241d2201f2fSdrahn 
2242d2201f2fSdrahn   digits = strspn (colpos + 1, "0123456789");
2243d2201f2fSdrahn   return digits != 0 && colpos[1 + digits] == 0;
2244d2201f2fSdrahn }
2245d2201f2fSdrahn 
2246d2201f2fSdrahn /* We get rid of the register section here.  */
2247d2201f2fSdrahn 
2248d2201f2fSdrahn bfd_boolean
mmix_elf_final_link(abfd,info)2249d2201f2fSdrahn mmix_elf_final_link (abfd, info)
2250d2201f2fSdrahn      bfd *abfd;
2251d2201f2fSdrahn      struct bfd_link_info *info;
2252d2201f2fSdrahn {
2253d2201f2fSdrahn   /* We never output a register section, though we create one for
2254d2201f2fSdrahn      temporary measures.  Check that nobody entered contents into it.  */
2255d2201f2fSdrahn   asection *reg_section;
2256d2201f2fSdrahn   asection **secpp;
2257d2201f2fSdrahn 
2258d2201f2fSdrahn   reg_section = bfd_get_section_by_name (abfd, MMIX_REG_SECTION_NAME);
2259d2201f2fSdrahn 
2260d2201f2fSdrahn   if (reg_section != NULL)
2261d2201f2fSdrahn     {
2262d2201f2fSdrahn       /* FIXME: Pass error state gracefully.  */
2263d2201f2fSdrahn       if (bfd_get_section_flags (abfd, reg_section) & SEC_HAS_CONTENTS)
2264d2201f2fSdrahn 	_bfd_abort (__FILE__, __LINE__, _("Register section has contents\n"));
2265d2201f2fSdrahn 
2266d2201f2fSdrahn       /* Really remove the section.  */
2267d2201f2fSdrahn       for (secpp = &abfd->sections;
2268d2201f2fSdrahn 	   *secpp != reg_section;
2269d2201f2fSdrahn 	   secpp = &(*secpp)->next)
2270d2201f2fSdrahn 	;
2271d2201f2fSdrahn       bfd_section_list_remove (abfd, secpp);
2272d2201f2fSdrahn       --abfd->section_count;
2273d2201f2fSdrahn     }
2274d2201f2fSdrahn 
2275*cf2f2c56Smiod   if (! bfd_elf_final_link (abfd, info))
2276d2201f2fSdrahn     return FALSE;
2277d2201f2fSdrahn 
2278d2201f2fSdrahn   /* Since this section is marked SEC_LINKER_CREATED, it isn't output by
2279d2201f2fSdrahn      the regular linker machinery.  We do it here, like other targets with
2280d2201f2fSdrahn      special sections.  */
2281d2201f2fSdrahn   if (info->base_file != NULL)
2282d2201f2fSdrahn     {
2283d2201f2fSdrahn       asection *greg_section
2284d2201f2fSdrahn 	= bfd_get_section_by_name ((bfd *) info->base_file,
2285d2201f2fSdrahn 				   MMIX_LD_ALLOCATED_REG_CONTENTS_SECTION_NAME);
2286d2201f2fSdrahn       if (!bfd_set_section_contents (abfd,
2287d2201f2fSdrahn 				     greg_section->output_section,
2288d2201f2fSdrahn 				     greg_section->contents,
2289d2201f2fSdrahn 				     (file_ptr) greg_section->output_offset,
2290d2201f2fSdrahn 				     greg_section->_cooked_size))
2291d2201f2fSdrahn 	return FALSE;
2292d2201f2fSdrahn     }
2293d2201f2fSdrahn   return TRUE;
2294d2201f2fSdrahn }
2295d2201f2fSdrahn 
2296*cf2f2c56Smiod /* We need to include the maximum size of PUSHJ-stubs in the initial
2297*cf2f2c56Smiod    section size.  This is expected to shrink during linker relaxation.
2298*cf2f2c56Smiod 
2299*cf2f2c56Smiod    You might think that we should set *only* _cooked_size, but that won't
2300*cf2f2c56Smiod    work: section contents allocation will be using _raw_size in mixed
2301*cf2f2c56Smiod    format linking and not enough storage will be allocated.  FIXME: That's
2302*cf2f2c56Smiod    a major bug, including the name bfd_get_section_size_before_reloc; it
2303*cf2f2c56Smiod    should be bfd_get_section_size_before_relax.  The relaxation functions
2304*cf2f2c56Smiod    set _cooked size.  Relaxation happens before relocation.  All functions
2305*cf2f2c56Smiod    *after relaxation* should be using _cooked size.  */
2306*cf2f2c56Smiod 
2307*cf2f2c56Smiod static void
mmix_set_relaxable_size(abfd,sec,ptr)2308*cf2f2c56Smiod mmix_set_relaxable_size (abfd, sec, ptr)
2309*cf2f2c56Smiod      bfd *abfd ATTRIBUTE_UNUSED;
2310*cf2f2c56Smiod      asection *sec;
2311*cf2f2c56Smiod      void *ptr;
2312*cf2f2c56Smiod {
2313*cf2f2c56Smiod   struct bfd_link_info *info = ptr;
2314*cf2f2c56Smiod 
2315*cf2f2c56Smiod   /* Make sure we only do this for section where we know we want this,
2316*cf2f2c56Smiod      otherwise we might end up resetting the size of COMMONs.  */
2317*cf2f2c56Smiod   if (mmix_elf_section_data (sec)->pjs.n_pushj_relocs == 0)
2318*cf2f2c56Smiod     return;
2319*cf2f2c56Smiod 
2320*cf2f2c56Smiod   sec->_cooked_size
2321*cf2f2c56Smiod     = (sec->_raw_size
2322*cf2f2c56Smiod        + mmix_elf_section_data (sec)->pjs.n_pushj_relocs
2323*cf2f2c56Smiod        * MAX_PUSHJ_STUB_SIZE);
2324*cf2f2c56Smiod   sec->_raw_size = sec->_cooked_size;
2325*cf2f2c56Smiod 
2326*cf2f2c56Smiod   /* For use in relocatable link, we start with a max stubs size.  See
2327*cf2f2c56Smiod      mmix_elf_relax_section.  */
2328*cf2f2c56Smiod   if (info->relocatable && sec->output_section)
2329*cf2f2c56Smiod     mmix_elf_section_data (sec->output_section)->pjs.stubs_size_sum
2330*cf2f2c56Smiod       += (mmix_elf_section_data (sec)->pjs.n_pushj_relocs
2331*cf2f2c56Smiod 	  * MAX_PUSHJ_STUB_SIZE);
2332*cf2f2c56Smiod }
2333*cf2f2c56Smiod 
2334d2201f2fSdrahn /* Initialize stuff for the linker-generated GREGs to match
2335d2201f2fSdrahn    R_MMIX_BASE_PLUS_OFFSET relocs seen by the linker.  */
2336d2201f2fSdrahn 
2337d2201f2fSdrahn bfd_boolean
_bfd_mmix_before_linker_allocation(abfd,info)2338*cf2f2c56Smiod _bfd_mmix_before_linker_allocation (abfd, info)
2339d2201f2fSdrahn      bfd *abfd ATTRIBUTE_UNUSED;
2340d2201f2fSdrahn      struct bfd_link_info *info;
2341d2201f2fSdrahn {
2342d2201f2fSdrahn   asection *bpo_gregs_section;
2343d2201f2fSdrahn   bfd *bpo_greg_owner;
2344d2201f2fSdrahn   struct bpo_greg_section_info *gregdata;
2345d2201f2fSdrahn   size_t n_gregs;
2346d2201f2fSdrahn   bfd_vma gregs_size;
2347d2201f2fSdrahn   size_t i;
2348d2201f2fSdrahn   size_t *bpo_reloc_indexes;
2349*cf2f2c56Smiod   bfd *ibfd;
2350*cf2f2c56Smiod 
2351*cf2f2c56Smiod   /* Set the initial size of sections.  */
2352*cf2f2c56Smiod   for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
2353*cf2f2c56Smiod     bfd_map_over_sections (ibfd, mmix_set_relaxable_size, info);
2354d2201f2fSdrahn 
2355d2201f2fSdrahn   /* The bpo_greg_owner bfd is supposed to have been set by
2356d2201f2fSdrahn      mmix_elf_check_relocs when the first R_MMIX_BASE_PLUS_OFFSET is seen.
2357d2201f2fSdrahn      If there is no such object, there was no R_MMIX_BASE_PLUS_OFFSET.  */
2358d2201f2fSdrahn   bpo_greg_owner = (bfd *) info->base_file;
2359d2201f2fSdrahn   if (bpo_greg_owner == NULL)
2360d2201f2fSdrahn     return TRUE;
2361d2201f2fSdrahn 
2362d2201f2fSdrahn   bpo_gregs_section
2363d2201f2fSdrahn     = bfd_get_section_by_name (bpo_greg_owner,
2364d2201f2fSdrahn 			       MMIX_LD_ALLOCATED_REG_CONTENTS_SECTION_NAME);
2365d2201f2fSdrahn 
2366d2201f2fSdrahn   if (bpo_gregs_section == NULL)
2367d2201f2fSdrahn     return TRUE;
2368d2201f2fSdrahn 
2369d2201f2fSdrahn   /* We use the target-data handle in the ELF section data.  */
2370d2201f2fSdrahn   gregdata = mmix_elf_section_data (bpo_gregs_section)->bpo.greg;
2371d2201f2fSdrahn   if (gregdata == NULL)
2372d2201f2fSdrahn     return FALSE;
2373d2201f2fSdrahn 
2374d2201f2fSdrahn   n_gregs = gregdata->n_bpo_relocs;
2375d2201f2fSdrahn   gregdata->n_allocated_bpo_gregs = n_gregs;
2376d2201f2fSdrahn 
2377d2201f2fSdrahn   /* When this reaches zero during relaxation, all entries have been
2378d2201f2fSdrahn      filled in and the size of the linker gregs can be calculated.  */
2379d2201f2fSdrahn   gregdata->n_remaining_bpo_relocs_this_relaxation_round = n_gregs;
2380d2201f2fSdrahn 
2381d2201f2fSdrahn   /* Set the zeroth-order estimate for the GREGs size.  */
2382d2201f2fSdrahn   gregs_size = n_gregs * 8;
2383d2201f2fSdrahn 
2384d2201f2fSdrahn   if (!bfd_set_section_size (bpo_greg_owner, bpo_gregs_section, gregs_size))
2385d2201f2fSdrahn     return FALSE;
2386d2201f2fSdrahn 
2387d2201f2fSdrahn   /* Allocate and set up the GREG arrays.  They're filled in at relaxation
2388d2201f2fSdrahn      time.  Note that we must use the max number ever noted for the array,
2389d2201f2fSdrahn      since the index numbers were created before GC.  */
2390d2201f2fSdrahn   gregdata->reloc_request
2391d2201f2fSdrahn     = bfd_zalloc (bpo_greg_owner,
2392d2201f2fSdrahn 		  sizeof (struct bpo_reloc_request)
2393d2201f2fSdrahn 		  * gregdata->n_max_bpo_relocs);
2394d2201f2fSdrahn 
2395d2201f2fSdrahn   gregdata->bpo_reloc_indexes
2396d2201f2fSdrahn     = bpo_reloc_indexes
2397d2201f2fSdrahn     = bfd_alloc (bpo_greg_owner,
2398d2201f2fSdrahn 		 gregdata->n_max_bpo_relocs
2399d2201f2fSdrahn 		 * sizeof (size_t));
2400d2201f2fSdrahn   if (bpo_reloc_indexes == NULL)
2401d2201f2fSdrahn     return FALSE;
2402d2201f2fSdrahn 
2403d2201f2fSdrahn   /* The default order is an identity mapping.  */
2404d2201f2fSdrahn   for (i = 0; i < gregdata->n_max_bpo_relocs; i++)
2405d2201f2fSdrahn     {
2406d2201f2fSdrahn       bpo_reloc_indexes[i] = i;
2407d2201f2fSdrahn       gregdata->reloc_request[i].bpo_reloc_no = i;
2408d2201f2fSdrahn     }
2409d2201f2fSdrahn 
2410d2201f2fSdrahn   return TRUE;
2411d2201f2fSdrahn }
2412d2201f2fSdrahn 
2413d2201f2fSdrahn /* Fill in contents in the linker allocated gregs.  Everything is
2414d2201f2fSdrahn    calculated at this point; we just move the contents into place here.  */
2415d2201f2fSdrahn 
2416d2201f2fSdrahn bfd_boolean
_bfd_mmix_after_linker_allocation(abfd,link_info)2417*cf2f2c56Smiod _bfd_mmix_after_linker_allocation (abfd, link_info)
2418d2201f2fSdrahn      bfd *abfd ATTRIBUTE_UNUSED;
2419d2201f2fSdrahn      struct bfd_link_info *link_info;
2420d2201f2fSdrahn {
2421d2201f2fSdrahn   asection *bpo_gregs_section;
2422d2201f2fSdrahn   bfd *bpo_greg_owner;
2423d2201f2fSdrahn   struct bpo_greg_section_info *gregdata;
2424d2201f2fSdrahn   size_t n_gregs;
2425d2201f2fSdrahn   size_t i, j;
2426d2201f2fSdrahn   size_t lastreg;
2427d2201f2fSdrahn   bfd_byte *contents;
2428d2201f2fSdrahn 
2429d2201f2fSdrahn   /* The bpo_greg_owner bfd is supposed to have been set by mmix_elf_check_relocs
2430d2201f2fSdrahn      when the first R_MMIX_BASE_PLUS_OFFSET is seen.  If there is no such
2431d2201f2fSdrahn      object, there was no R_MMIX_BASE_PLUS_OFFSET.  */
2432d2201f2fSdrahn   bpo_greg_owner = (bfd *) link_info->base_file;
2433d2201f2fSdrahn   if (bpo_greg_owner == NULL)
2434d2201f2fSdrahn     return TRUE;
2435d2201f2fSdrahn 
2436d2201f2fSdrahn   bpo_gregs_section
2437d2201f2fSdrahn     = bfd_get_section_by_name (bpo_greg_owner,
2438d2201f2fSdrahn 			       MMIX_LD_ALLOCATED_REG_CONTENTS_SECTION_NAME);
2439d2201f2fSdrahn 
2440d2201f2fSdrahn   /* This can't happen without DSO handling.  When DSOs are handled
2441d2201f2fSdrahn      without any R_MMIX_BASE_PLUS_OFFSET seen, there will be no such
2442d2201f2fSdrahn      section.  */
2443d2201f2fSdrahn   if (bpo_gregs_section == NULL)
2444d2201f2fSdrahn     return TRUE;
2445d2201f2fSdrahn 
2446d2201f2fSdrahn   /* We use the target-data handle in the ELF section data.  */
2447d2201f2fSdrahn 
2448d2201f2fSdrahn   gregdata = mmix_elf_section_data (bpo_gregs_section)->bpo.greg;
2449d2201f2fSdrahn   if (gregdata == NULL)
2450d2201f2fSdrahn     return FALSE;
2451d2201f2fSdrahn 
2452d2201f2fSdrahn   n_gregs = gregdata->n_allocated_bpo_gregs;
2453d2201f2fSdrahn 
2454d2201f2fSdrahn   /* We need to have a _raw_size contents even though there's only
2455d2201f2fSdrahn      _cooked_size worth of data, since the generic relocation machinery
2456d2201f2fSdrahn      will allocate and copy that much temporarily.  */
2457d2201f2fSdrahn   bpo_gregs_section->contents
2458d2201f2fSdrahn     = contents = bfd_alloc (bpo_greg_owner, bpo_gregs_section->_raw_size);
2459d2201f2fSdrahn   if (contents == NULL)
2460d2201f2fSdrahn     return FALSE;
2461d2201f2fSdrahn 
2462d2201f2fSdrahn   /* Sanity check: If these numbers mismatch, some relocation has not been
2463d2201f2fSdrahn      accounted for and the rest of gregdata is probably inconsistent.
2464d2201f2fSdrahn      It's a bug, but it's more helpful to identify it than segfaulting
2465d2201f2fSdrahn      below.  */
2466d2201f2fSdrahn   if (gregdata->n_remaining_bpo_relocs_this_relaxation_round
2467d2201f2fSdrahn       != gregdata->n_bpo_relocs)
2468d2201f2fSdrahn     {
2469d2201f2fSdrahn       (*_bfd_error_handler)
2470d2201f2fSdrahn 	(_("Internal inconsistency: remaining %u != max %u.\n\
2471d2201f2fSdrahn   Please report this bug."),
2472d2201f2fSdrahn 	 gregdata->n_remaining_bpo_relocs_this_relaxation_round,
2473d2201f2fSdrahn 	 gregdata->n_bpo_relocs);
2474d2201f2fSdrahn       return FALSE;
2475d2201f2fSdrahn     }
2476d2201f2fSdrahn 
2477d2201f2fSdrahn   for (lastreg = 255, i = 0, j = 0; j < n_gregs; i++)
2478d2201f2fSdrahn     if (gregdata->reloc_request[i].regindex != lastreg)
2479d2201f2fSdrahn       {
2480d2201f2fSdrahn 	bfd_put_64 (bpo_greg_owner, gregdata->reloc_request[i].value,
2481d2201f2fSdrahn 		    contents + j * 8);
2482d2201f2fSdrahn 	lastreg = gregdata->reloc_request[i].regindex;
2483d2201f2fSdrahn 	j++;
2484d2201f2fSdrahn       }
2485d2201f2fSdrahn 
2486d2201f2fSdrahn   return TRUE;
2487d2201f2fSdrahn }
2488d2201f2fSdrahn 
2489d2201f2fSdrahn /* Sort valid relocs to come before non-valid relocs, then on increasing
2490d2201f2fSdrahn    value.  */
2491d2201f2fSdrahn 
2492d2201f2fSdrahn static int
bpo_reloc_request_sort_fn(p1,p2)2493d2201f2fSdrahn bpo_reloc_request_sort_fn (p1, p2)
2494d2201f2fSdrahn      const PTR p1;
2495d2201f2fSdrahn      const PTR p2;
2496d2201f2fSdrahn {
2497d2201f2fSdrahn   const struct bpo_reloc_request *r1 = (const struct bpo_reloc_request *) p1;
2498d2201f2fSdrahn   const struct bpo_reloc_request *r2 = (const struct bpo_reloc_request *) p2;
2499d2201f2fSdrahn 
2500d2201f2fSdrahn   /* Primary function is validity; non-valid relocs sorted after valid
2501d2201f2fSdrahn      ones.  */
2502d2201f2fSdrahn   if (r1->valid != r2->valid)
2503d2201f2fSdrahn     return r2->valid - r1->valid;
2504d2201f2fSdrahn 
2505d2201f2fSdrahn   /* Then sort on value.  Don't simplify and return just the difference of
2506d2201f2fSdrahn      the values: the upper bits of the 64-bit value would be truncated on
2507d2201f2fSdrahn      a host with 32-bit ints.  */
2508d2201f2fSdrahn   if (r1->value != r2->value)
2509d2201f2fSdrahn     return r1->value > r2->value ? 1 : -1;
2510d2201f2fSdrahn 
2511d2201f2fSdrahn   /* As a last re-sort, use the relocation number, so we get a stable
2512d2201f2fSdrahn      sort.  The *addresses* aren't stable since items are swapped during
2513d2201f2fSdrahn      sorting.  It depends on the qsort implementation if this actually
2514d2201f2fSdrahn      happens.  */
2515d2201f2fSdrahn   return r1->bpo_reloc_no > r2->bpo_reloc_no
2516d2201f2fSdrahn     ? 1 : (r1->bpo_reloc_no < r2->bpo_reloc_no ? -1 : 0);
2517d2201f2fSdrahn }
2518d2201f2fSdrahn 
2519d2201f2fSdrahn /* For debug use only.  Dumps the global register allocations resulting
2520d2201f2fSdrahn    from base-plus-offset relocs.  */
2521d2201f2fSdrahn 
2522d2201f2fSdrahn void
mmix_dump_bpo_gregs(link_info,pf)2523d2201f2fSdrahn mmix_dump_bpo_gregs (link_info, pf)
2524d2201f2fSdrahn      struct bfd_link_info *link_info;
2525d2201f2fSdrahn      bfd_error_handler_type pf;
2526d2201f2fSdrahn {
2527d2201f2fSdrahn   bfd *bpo_greg_owner;
2528d2201f2fSdrahn   asection *bpo_gregs_section;
2529d2201f2fSdrahn   struct bpo_greg_section_info *gregdata;
2530d2201f2fSdrahn   unsigned int i;
2531d2201f2fSdrahn 
2532d2201f2fSdrahn   if (link_info == NULL || link_info->base_file == NULL)
2533d2201f2fSdrahn     return;
2534d2201f2fSdrahn 
2535d2201f2fSdrahn   bpo_greg_owner = (bfd *) link_info->base_file;
2536d2201f2fSdrahn 
2537d2201f2fSdrahn   bpo_gregs_section
2538d2201f2fSdrahn     = bfd_get_section_by_name (bpo_greg_owner,
2539d2201f2fSdrahn 			       MMIX_LD_ALLOCATED_REG_CONTENTS_SECTION_NAME);
2540d2201f2fSdrahn 
2541d2201f2fSdrahn   if (bpo_gregs_section == NULL)
2542d2201f2fSdrahn     return;
2543d2201f2fSdrahn 
2544d2201f2fSdrahn   gregdata = mmix_elf_section_data (bpo_gregs_section)->bpo.greg;
2545d2201f2fSdrahn   if (gregdata == NULL)
2546d2201f2fSdrahn     return;
2547d2201f2fSdrahn 
2548d2201f2fSdrahn   if (pf == NULL)
2549d2201f2fSdrahn     pf = _bfd_error_handler;
2550d2201f2fSdrahn 
2551d2201f2fSdrahn   /* These format strings are not translated.  They are for debug purposes
2552d2201f2fSdrahn      only and never displayed to an end user.  Should they escape, we
2553d2201f2fSdrahn      surely want them in original.  */
2554d2201f2fSdrahn   (*pf) (" n_bpo_relocs: %u\n n_max_bpo_relocs: %u\n n_remain...round: %u\n\
2555d2201f2fSdrahn  n_allocated_bpo_gregs: %u\n", gregdata->n_bpo_relocs,
2556d2201f2fSdrahn      gregdata->n_max_bpo_relocs,
2557d2201f2fSdrahn      gregdata->n_remaining_bpo_relocs_this_relaxation_round,
2558d2201f2fSdrahn      gregdata->n_allocated_bpo_gregs);
2559d2201f2fSdrahn 
2560d2201f2fSdrahn   if (gregdata->reloc_request)
2561d2201f2fSdrahn     for (i = 0; i < gregdata->n_max_bpo_relocs; i++)
2562d2201f2fSdrahn       (*pf) ("%4u (%4u)/%4u#%u: 0x%08lx%08lx  r: %3u o: %3u\n",
2563d2201f2fSdrahn 	     i,
2564d2201f2fSdrahn 	     (gregdata->bpo_reloc_indexes != NULL
2565d2201f2fSdrahn 	      ? gregdata->bpo_reloc_indexes[i] : (size_t) -1),
2566d2201f2fSdrahn 	     gregdata->reloc_request[i].bpo_reloc_no,
2567d2201f2fSdrahn 	     gregdata->reloc_request[i].valid,
2568d2201f2fSdrahn 
2569d2201f2fSdrahn 	     (unsigned long) (gregdata->reloc_request[i].value >> 32),
2570d2201f2fSdrahn 	     (unsigned long) gregdata->reloc_request[i].value,
2571d2201f2fSdrahn 	     gregdata->reloc_request[i].regindex,
2572d2201f2fSdrahn 	     gregdata->reloc_request[i].offset);
2573d2201f2fSdrahn }
2574d2201f2fSdrahn 
2575d2201f2fSdrahn /* This links all R_MMIX_BASE_PLUS_OFFSET relocs into a special array, and
2576d2201f2fSdrahn    when the last such reloc is done, an index-array is sorted according to
2577d2201f2fSdrahn    the values and iterated over to produce register numbers (indexed by 0
2578d2201f2fSdrahn    from the first allocated register number) and offsets for use in real
2579d2201f2fSdrahn    relocation.
2580d2201f2fSdrahn 
2581*cf2f2c56Smiod    PUSHJ stub accounting is also done here.
2582*cf2f2c56Smiod 
2583d2201f2fSdrahn    Symbol- and reloc-reading infrastructure copied from elf-m10200.c.  */
2584d2201f2fSdrahn 
2585d2201f2fSdrahn static bfd_boolean
mmix_elf_relax_section(abfd,sec,link_info,again)2586d2201f2fSdrahn mmix_elf_relax_section (abfd, sec, link_info, again)
2587d2201f2fSdrahn      bfd *abfd;
2588d2201f2fSdrahn      asection *sec;
2589d2201f2fSdrahn      struct bfd_link_info *link_info;
2590d2201f2fSdrahn      bfd_boolean *again;
2591d2201f2fSdrahn {
2592d2201f2fSdrahn   Elf_Internal_Shdr *symtab_hdr;
2593d2201f2fSdrahn   Elf_Internal_Rela *internal_relocs;
2594d2201f2fSdrahn   Elf_Internal_Rela *irel, *irelend;
2595d2201f2fSdrahn   asection *bpo_gregs_section = NULL;
2596d2201f2fSdrahn   struct bpo_greg_section_info *gregdata;
2597d2201f2fSdrahn   struct bpo_reloc_section_info *bpodata
2598d2201f2fSdrahn     = mmix_elf_section_data (sec)->bpo.reloc;
2599*cf2f2c56Smiod   /* The initialization is to quiet compiler warnings.  The value is to
2600*cf2f2c56Smiod      spot a missing actual initialization.  */
2601*cf2f2c56Smiod   size_t bpono = (size_t) -1;
2602*cf2f2c56Smiod   size_t pjsno = 0;
2603d2201f2fSdrahn   bfd *bpo_greg_owner;
2604d2201f2fSdrahn   Elf_Internal_Sym *isymbuf = NULL;
2605*cf2f2c56Smiod   bfd_size_type raw_size
2606*cf2f2c56Smiod     = (sec->_raw_size
2607*cf2f2c56Smiod        - mmix_elf_section_data (sec)->pjs.n_pushj_relocs
2608*cf2f2c56Smiod        * MAX_PUSHJ_STUB_SIZE);
2609*cf2f2c56Smiod 
2610*cf2f2c56Smiod   mmix_elf_section_data (sec)->pjs.stubs_size_sum = 0;
2611d2201f2fSdrahn 
2612d2201f2fSdrahn   /* Assume nothing changes.  */
2613d2201f2fSdrahn   *again = FALSE;
2614d2201f2fSdrahn 
2615d2201f2fSdrahn   /* If this is the first time we have been called for this section,
2616d2201f2fSdrahn      initialize the cooked size.  */
2617*cf2f2c56Smiod   if (sec->_cooked_size == 0 && sec->_raw_size != 0)
2618*cf2f2c56Smiod     abort ();
2619d2201f2fSdrahn 
2620*cf2f2c56Smiod   /* We don't have to do anything if this section does not have relocs, or
2621*cf2f2c56Smiod      if this is not a code section.  */
2622*cf2f2c56Smiod   if ((sec->flags & SEC_RELOC) == 0
2623d2201f2fSdrahn       || sec->reloc_count == 0
2624d2201f2fSdrahn       || (sec->flags & SEC_CODE) == 0
2625d2201f2fSdrahn       || (sec->flags & SEC_LINKER_CREATED) != 0
2626*cf2f2c56Smiod       /* If no R_MMIX_BASE_PLUS_OFFSET relocs and no PUSHJ-stub relocs,
2627*cf2f2c56Smiod          then nothing to do.  */
2628*cf2f2c56Smiod       || (bpodata == NULL
2629*cf2f2c56Smiod 	  && mmix_elf_section_data (sec)->pjs.n_pushj_relocs == 0))
2630d2201f2fSdrahn     return TRUE;
2631d2201f2fSdrahn 
2632d2201f2fSdrahn   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
2633d2201f2fSdrahn 
2634d2201f2fSdrahn   bpo_greg_owner = (bfd *) link_info->base_file;
2635*cf2f2c56Smiod 
2636*cf2f2c56Smiod   if (bpodata != NULL)
2637*cf2f2c56Smiod     {
2638d2201f2fSdrahn       bpo_gregs_section = bpodata->bpo_greg_section;
2639d2201f2fSdrahn       gregdata = mmix_elf_section_data (bpo_gregs_section)->bpo.greg;
2640d2201f2fSdrahn       bpono = bpodata->first_base_plus_offset_reloc;
2641*cf2f2c56Smiod     }
2642*cf2f2c56Smiod   else
2643*cf2f2c56Smiod     gregdata = NULL;
2644d2201f2fSdrahn 
2645d2201f2fSdrahn   /* Get a copy of the native relocations.  */
2646d2201f2fSdrahn   internal_relocs
2647*cf2f2c56Smiod     = _bfd_elf_link_read_relocs (abfd, sec, (PTR) NULL,
2648d2201f2fSdrahn 				 (Elf_Internal_Rela *) NULL,
2649d2201f2fSdrahn 				 link_info->keep_memory);
2650d2201f2fSdrahn   if (internal_relocs == NULL)
2651d2201f2fSdrahn     goto error_return;
2652d2201f2fSdrahn 
2653d2201f2fSdrahn   /* Walk through them looking for relaxing opportunities.  */
2654d2201f2fSdrahn   irelend = internal_relocs + sec->reloc_count;
2655d2201f2fSdrahn   for (irel = internal_relocs; irel < irelend; irel++)
2656d2201f2fSdrahn     {
2657d2201f2fSdrahn       bfd_vma symval;
2658*cf2f2c56Smiod       struct elf_link_hash_entry *h = NULL;
2659d2201f2fSdrahn 
2660*cf2f2c56Smiod       /* We only process two relocs.  */
2661*cf2f2c56Smiod       if (ELF64_R_TYPE (irel->r_info) != (int) R_MMIX_BASE_PLUS_OFFSET
2662*cf2f2c56Smiod 	  && ELF64_R_TYPE (irel->r_info) != (int) R_MMIX_PUSHJ_STUBBABLE)
2663d2201f2fSdrahn 	continue;
2664d2201f2fSdrahn 
2665*cf2f2c56Smiod       /* We process relocs in a distinctly different way when this is a
2666*cf2f2c56Smiod 	 relocatable link (for one, we don't look at symbols), so we avoid
2667*cf2f2c56Smiod 	 mixing its code with that for the "normal" relaxation.  */
2668*cf2f2c56Smiod       if (link_info->relocatable)
2669*cf2f2c56Smiod 	{
2670*cf2f2c56Smiod 	  /* The only transformation in a relocatable link is to generate
2671*cf2f2c56Smiod 	     a full stub at the location of the stub calculated for the
2672*cf2f2c56Smiod 	     input section, if the relocated stub location, the end of the
2673*cf2f2c56Smiod 	     output section plus earlier stubs, cannot be reached.  Thus
2674*cf2f2c56Smiod 	     relocatable linking can only lead to worse code, but it still
2675*cf2f2c56Smiod 	     works.  */
2676*cf2f2c56Smiod 	  if (ELF64_R_TYPE (irel->r_info) == R_MMIX_PUSHJ_STUBBABLE)
2677*cf2f2c56Smiod 	    {
2678*cf2f2c56Smiod 	      /* If we can reach the end of the output-section and beyond
2679*cf2f2c56Smiod 		 any current stubs, then we don't need a stub for this
2680*cf2f2c56Smiod 		 reloc.  The relaxed order of output stub allocation may
2681*cf2f2c56Smiod 		 not exactly match the straightforward order, so we always
2682*cf2f2c56Smiod 		 assume presence of output stubs, which will allow
2683*cf2f2c56Smiod 		 relaxation only on relocations indifferent to the
2684*cf2f2c56Smiod 		 presence of output stub allocations for other relocations
2685*cf2f2c56Smiod 		 and thus the order of output stub allocation.  */
2686*cf2f2c56Smiod 	      if (bfd_check_overflow (complain_overflow_signed,
2687*cf2f2c56Smiod 				      19,
2688*cf2f2c56Smiod 				      0,
2689*cf2f2c56Smiod 				      bfd_arch_bits_per_address (abfd),
2690*cf2f2c56Smiod 				      /* Output-stub location.  */
2691*cf2f2c56Smiod 				      sec->output_section->_cooked_size
2692*cf2f2c56Smiod 				      + (mmix_elf_section_data (sec
2693*cf2f2c56Smiod 							       ->output_section)
2694*cf2f2c56Smiod 					 ->pjs.stubs_size_sum)
2695*cf2f2c56Smiod 				      /* Location of this PUSHJ reloc.  */
2696*cf2f2c56Smiod 				      - (sec->output_offset + irel->r_offset)
2697*cf2f2c56Smiod 				      /* Don't count *this* stub twice.  */
2698*cf2f2c56Smiod 				      - (mmix_elf_section_data (sec)
2699*cf2f2c56Smiod 					 ->pjs.stub_size[pjsno]
2700*cf2f2c56Smiod 					 + MAX_PUSHJ_STUB_SIZE))
2701*cf2f2c56Smiod 		  == bfd_reloc_ok)
2702*cf2f2c56Smiod 		mmix_elf_section_data (sec)->pjs.stub_size[pjsno] = 0;
2703*cf2f2c56Smiod 
2704*cf2f2c56Smiod 	      mmix_elf_section_data (sec)->pjs.stubs_size_sum
2705*cf2f2c56Smiod 		+= mmix_elf_section_data (sec)->pjs.stub_size[pjsno];
2706*cf2f2c56Smiod 
2707*cf2f2c56Smiod 	      pjsno++;
2708*cf2f2c56Smiod 	    }
2709*cf2f2c56Smiod 
2710*cf2f2c56Smiod 	  continue;
2711*cf2f2c56Smiod 	}
2712*cf2f2c56Smiod 
2713d2201f2fSdrahn       /* Get the value of the symbol referred to by the reloc.  */
2714d2201f2fSdrahn       if (ELF64_R_SYM (irel->r_info) < symtab_hdr->sh_info)
2715d2201f2fSdrahn 	{
2716d2201f2fSdrahn 	  /* A local symbol.  */
2717d2201f2fSdrahn 	  Elf_Internal_Sym *isym;
2718d2201f2fSdrahn 	  asection *sym_sec;
2719d2201f2fSdrahn 
2720d2201f2fSdrahn 	  /* Read this BFD's local symbols if we haven't already.  */
2721d2201f2fSdrahn 	  if (isymbuf == NULL)
2722d2201f2fSdrahn 	    {
2723d2201f2fSdrahn 	      isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
2724d2201f2fSdrahn 	      if (isymbuf == NULL)
2725d2201f2fSdrahn 		isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
2726d2201f2fSdrahn 						symtab_hdr->sh_info, 0,
2727d2201f2fSdrahn 						NULL, NULL, NULL);
2728d2201f2fSdrahn 	      if (isymbuf == 0)
2729d2201f2fSdrahn 		goto error_return;
2730d2201f2fSdrahn 	    }
2731d2201f2fSdrahn 
2732d2201f2fSdrahn 	  isym = isymbuf + ELF64_R_SYM (irel->r_info);
2733d2201f2fSdrahn 	  if (isym->st_shndx == SHN_UNDEF)
2734d2201f2fSdrahn 	    sym_sec = bfd_und_section_ptr;
2735d2201f2fSdrahn 	  else if (isym->st_shndx == SHN_ABS)
2736d2201f2fSdrahn 	    sym_sec = bfd_abs_section_ptr;
2737d2201f2fSdrahn 	  else if (isym->st_shndx == SHN_COMMON)
2738d2201f2fSdrahn 	    sym_sec = bfd_com_section_ptr;
2739d2201f2fSdrahn 	  else
2740d2201f2fSdrahn 	    sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
2741d2201f2fSdrahn 	  symval = (isym->st_value
2742d2201f2fSdrahn 		    + sym_sec->output_section->vma
2743d2201f2fSdrahn 		    + sym_sec->output_offset);
2744d2201f2fSdrahn 	}
2745d2201f2fSdrahn       else
2746d2201f2fSdrahn 	{
2747d2201f2fSdrahn 	  unsigned long indx;
2748d2201f2fSdrahn 
2749d2201f2fSdrahn 	  /* An external symbol.  */
2750d2201f2fSdrahn 	  indx = ELF64_R_SYM (irel->r_info) - symtab_hdr->sh_info;
2751d2201f2fSdrahn 	  h = elf_sym_hashes (abfd)[indx];
2752d2201f2fSdrahn 	  BFD_ASSERT (h != NULL);
2753d2201f2fSdrahn 	  if (h->root.type != bfd_link_hash_defined
2754d2201f2fSdrahn 	      && h->root.type != bfd_link_hash_defweak)
2755d2201f2fSdrahn 	    {
2756*cf2f2c56Smiod 	      /* This appears to be a reference to an undefined symbol.  Just
2757*cf2f2c56Smiod 		 ignore it--it will be caught by the regular reloc processing.
2758*cf2f2c56Smiod 		 We need to keep BPO reloc accounting consistent, though
2759*cf2f2c56Smiod 		 else we'll abort instead of emitting an error message.  */
2760*cf2f2c56Smiod 	      if (ELF64_R_TYPE (irel->r_info) == R_MMIX_BASE_PLUS_OFFSET
2761*cf2f2c56Smiod 		  && gregdata != NULL)
2762*cf2f2c56Smiod 		{
2763d2201f2fSdrahn 		  gregdata->n_remaining_bpo_relocs_this_relaxation_round--;
2764d2201f2fSdrahn 		  bpono++;
2765*cf2f2c56Smiod 		}
2766d2201f2fSdrahn 	      continue;
2767d2201f2fSdrahn 	    }
2768d2201f2fSdrahn 
2769d2201f2fSdrahn 	  symval = (h->root.u.def.value
2770d2201f2fSdrahn 		    + h->root.u.def.section->output_section->vma
2771d2201f2fSdrahn 		    + h->root.u.def.section->output_offset);
2772d2201f2fSdrahn 	}
2773d2201f2fSdrahn 
2774*cf2f2c56Smiod       if (ELF64_R_TYPE (irel->r_info) == (int) R_MMIX_PUSHJ_STUBBABLE)
2775*cf2f2c56Smiod 	{
2776*cf2f2c56Smiod 	  bfd_vma value = symval + irel->r_addend;
2777*cf2f2c56Smiod 	  bfd_vma dot
2778*cf2f2c56Smiod 	    = (sec->output_section->vma
2779*cf2f2c56Smiod 	       + sec->output_offset
2780*cf2f2c56Smiod 	       + irel->r_offset);
2781*cf2f2c56Smiod 	  bfd_vma stubaddr
2782*cf2f2c56Smiod 	    = (sec->output_section->vma
2783*cf2f2c56Smiod 	       + sec->output_offset
2784*cf2f2c56Smiod 	       + raw_size
2785*cf2f2c56Smiod 	       + mmix_elf_section_data (sec)->pjs.stubs_size_sum);
2786*cf2f2c56Smiod 
2787*cf2f2c56Smiod 	  if ((value & 3) == 0
2788*cf2f2c56Smiod 	      && bfd_check_overflow (complain_overflow_signed,
2789*cf2f2c56Smiod 				     19,
2790*cf2f2c56Smiod 				     0,
2791*cf2f2c56Smiod 				     bfd_arch_bits_per_address (abfd),
2792*cf2f2c56Smiod 				     value - dot
2793*cf2f2c56Smiod 				     - (value > dot
2794*cf2f2c56Smiod 					? mmix_elf_section_data (sec)
2795*cf2f2c56Smiod 					->pjs.stub_size[pjsno]
2796*cf2f2c56Smiod 					: 0))
2797*cf2f2c56Smiod 	      == bfd_reloc_ok)
2798*cf2f2c56Smiod 	    /* If the reloc fits, no stub is needed.  */
2799*cf2f2c56Smiod 	    mmix_elf_section_data (sec)->pjs.stub_size[pjsno] = 0;
2800*cf2f2c56Smiod 	  else
2801*cf2f2c56Smiod 	    /* Maybe we can get away with just a JMP insn?  */
2802*cf2f2c56Smiod 	    if ((value & 3) == 0
2803*cf2f2c56Smiod 		&& bfd_check_overflow (complain_overflow_signed,
2804*cf2f2c56Smiod 				       27,
2805*cf2f2c56Smiod 				       0,
2806*cf2f2c56Smiod 				       bfd_arch_bits_per_address (abfd),
2807*cf2f2c56Smiod 				       value - stubaddr
2808*cf2f2c56Smiod 				       - (value > dot
2809*cf2f2c56Smiod 					  ? mmix_elf_section_data (sec)
2810*cf2f2c56Smiod 					  ->pjs.stub_size[pjsno] - 4
2811*cf2f2c56Smiod 					  : 0))
2812*cf2f2c56Smiod 		== bfd_reloc_ok)
2813*cf2f2c56Smiod 	      /* Yep, account for a stub consisting of a single JMP insn.  */
2814*cf2f2c56Smiod 	      mmix_elf_section_data (sec)->pjs.stub_size[pjsno] = 4;
2815*cf2f2c56Smiod 	  else
2816*cf2f2c56Smiod 	    /* Nope, go for the full insn stub.  It doesn't seem useful to
2817*cf2f2c56Smiod 	       emit the intermediate sizes; those will only be useful for
2818*cf2f2c56Smiod 	       a >64M program assuming contiguous code.  */
2819*cf2f2c56Smiod 	    mmix_elf_section_data (sec)->pjs.stub_size[pjsno]
2820*cf2f2c56Smiod 	      = MAX_PUSHJ_STUB_SIZE;
2821*cf2f2c56Smiod 
2822*cf2f2c56Smiod 	  mmix_elf_section_data (sec)->pjs.stubs_size_sum
2823*cf2f2c56Smiod 	    += mmix_elf_section_data (sec)->pjs.stub_size[pjsno];
2824*cf2f2c56Smiod 	  pjsno++;
2825*cf2f2c56Smiod 	  continue;
2826*cf2f2c56Smiod 	}
2827*cf2f2c56Smiod 
2828*cf2f2c56Smiod       /* We're looking at a R_MMIX_BASE_PLUS_OFFSET reloc.  */
2829*cf2f2c56Smiod 
2830d2201f2fSdrahn       gregdata->reloc_request[gregdata->bpo_reloc_indexes[bpono]].value
2831d2201f2fSdrahn 	= symval + irel->r_addend;
2832d2201f2fSdrahn       gregdata->reloc_request[gregdata->bpo_reloc_indexes[bpono++]].valid = TRUE;
2833d2201f2fSdrahn       gregdata->n_remaining_bpo_relocs_this_relaxation_round--;
2834d2201f2fSdrahn     }
2835d2201f2fSdrahn 
2836d2201f2fSdrahn   /* Check if that was the last BPO-reloc.  If so, sort the values and
2837d2201f2fSdrahn      calculate how many registers we need to cover them.  Set the size of
2838d2201f2fSdrahn      the linker gregs, and if the number of registers changed, indicate
2839d2201f2fSdrahn      that we need to relax some more because we have more work to do.  */
2840*cf2f2c56Smiod   if (gregdata != NULL
2841*cf2f2c56Smiod       && gregdata->n_remaining_bpo_relocs_this_relaxation_round == 0)
2842d2201f2fSdrahn     {
2843d2201f2fSdrahn       size_t i;
2844d2201f2fSdrahn       bfd_vma prev_base;
2845d2201f2fSdrahn       size_t regindex;
2846d2201f2fSdrahn 
2847d2201f2fSdrahn       /* First, reset the remaining relocs for the next round.  */
2848d2201f2fSdrahn       gregdata->n_remaining_bpo_relocs_this_relaxation_round
2849d2201f2fSdrahn 	= gregdata->n_bpo_relocs;
2850d2201f2fSdrahn 
2851d2201f2fSdrahn       qsort ((PTR) gregdata->reloc_request,
2852d2201f2fSdrahn 	     gregdata->n_max_bpo_relocs,
2853d2201f2fSdrahn 	     sizeof (struct bpo_reloc_request),
2854d2201f2fSdrahn 	     bpo_reloc_request_sort_fn);
2855d2201f2fSdrahn 
2856d2201f2fSdrahn       /* Recalculate indexes.  When we find a change (however unlikely
2857d2201f2fSdrahn 	 after the initial iteration), we know we need to relax again,
2858d2201f2fSdrahn 	 since items in the GREG-array are sorted by increasing value and
2859d2201f2fSdrahn 	 stored in the relaxation phase.  */
2860d2201f2fSdrahn       for (i = 0; i < gregdata->n_max_bpo_relocs; i++)
2861d2201f2fSdrahn 	if (gregdata->bpo_reloc_indexes[gregdata->reloc_request[i].bpo_reloc_no]
2862d2201f2fSdrahn 	    != i)
2863d2201f2fSdrahn 	  {
2864d2201f2fSdrahn 	    gregdata->bpo_reloc_indexes[gregdata->reloc_request[i].bpo_reloc_no]
2865d2201f2fSdrahn 	      = i;
2866d2201f2fSdrahn 	    *again = TRUE;
2867d2201f2fSdrahn 	  }
2868d2201f2fSdrahn 
2869d2201f2fSdrahn       /* Allocate register numbers (indexing from 0).  Stop at the first
2870d2201f2fSdrahn 	 non-valid reloc.  */
2871d2201f2fSdrahn       for (i = 0, regindex = 0, prev_base = gregdata->reloc_request[0].value;
2872d2201f2fSdrahn 	   i < gregdata->n_bpo_relocs;
2873d2201f2fSdrahn 	   i++)
2874d2201f2fSdrahn 	{
2875d2201f2fSdrahn 	  if (gregdata->reloc_request[i].value > prev_base + 255)
2876d2201f2fSdrahn 	    {
2877d2201f2fSdrahn 	      regindex++;
2878d2201f2fSdrahn 	      prev_base = gregdata->reloc_request[i].value;
2879d2201f2fSdrahn 	    }
2880d2201f2fSdrahn 	  gregdata->reloc_request[i].regindex = regindex;
2881d2201f2fSdrahn 	  gregdata->reloc_request[i].offset
2882d2201f2fSdrahn 	    = gregdata->reloc_request[i].value - prev_base;
2883d2201f2fSdrahn 	}
2884d2201f2fSdrahn 
2885d2201f2fSdrahn       /* If it's not the same as the last time, we need to relax again,
2886d2201f2fSdrahn 	 because the size of the section has changed.  I'm not sure we
2887d2201f2fSdrahn 	 actually need to do any adjustments since the shrinking happens
2888d2201f2fSdrahn 	 at the start of this section, but better safe than sorry.  */
2889d2201f2fSdrahn       if (gregdata->n_allocated_bpo_gregs != regindex + 1)
2890d2201f2fSdrahn 	{
2891d2201f2fSdrahn 	  gregdata->n_allocated_bpo_gregs = regindex + 1;
2892d2201f2fSdrahn 	  *again = TRUE;
2893d2201f2fSdrahn 	}
2894d2201f2fSdrahn 
2895d2201f2fSdrahn       bpo_gregs_section->_cooked_size = (regindex + 1) * 8;
2896d2201f2fSdrahn     }
2897d2201f2fSdrahn 
2898d2201f2fSdrahn   if (isymbuf != NULL && (unsigned char *) isymbuf != symtab_hdr->contents)
2899d2201f2fSdrahn     {
2900d2201f2fSdrahn       if (! link_info->keep_memory)
2901d2201f2fSdrahn 	free (isymbuf);
2902d2201f2fSdrahn       else
2903d2201f2fSdrahn 	{
2904d2201f2fSdrahn 	  /* Cache the symbols for elf_link_input_bfd.  */
2905d2201f2fSdrahn 	  symtab_hdr->contents = (unsigned char *) isymbuf;
2906d2201f2fSdrahn 	}
2907d2201f2fSdrahn     }
2908d2201f2fSdrahn 
2909d2201f2fSdrahn   if (internal_relocs != NULL
2910d2201f2fSdrahn       && elf_section_data (sec)->relocs != internal_relocs)
2911d2201f2fSdrahn     free (internal_relocs);
2912d2201f2fSdrahn 
2913*cf2f2c56Smiod   if (sec->_cooked_size
2914*cf2f2c56Smiod       < raw_size + mmix_elf_section_data (sec)->pjs.stubs_size_sum)
2915*cf2f2c56Smiod     abort ();
2916*cf2f2c56Smiod 
2917*cf2f2c56Smiod   if (sec->_cooked_size
2918*cf2f2c56Smiod       > raw_size + mmix_elf_section_data (sec)->pjs.stubs_size_sum)
2919*cf2f2c56Smiod     {
2920*cf2f2c56Smiod       sec->_cooked_size
2921*cf2f2c56Smiod 	= raw_size + mmix_elf_section_data (sec)->pjs.stubs_size_sum;
2922*cf2f2c56Smiod       *again = TRUE;
2923*cf2f2c56Smiod     }
2924*cf2f2c56Smiod 
2925d2201f2fSdrahn   return TRUE;
2926d2201f2fSdrahn 
2927d2201f2fSdrahn  error_return:
2928d2201f2fSdrahn   if (isymbuf != NULL && (unsigned char *) isymbuf != symtab_hdr->contents)
2929d2201f2fSdrahn     free (isymbuf);
2930d2201f2fSdrahn   if (internal_relocs != NULL
2931d2201f2fSdrahn       && elf_section_data (sec)->relocs != internal_relocs)
2932d2201f2fSdrahn     free (internal_relocs);
2933d2201f2fSdrahn   return FALSE;
2934d2201f2fSdrahn }
2935*cf2f2c56Smiod 
2936*cf2f2c56Smiod /* Because we set _raw_size to include the max size of pushj stubs,
2937*cf2f2c56Smiod    i.e. larger than the actual section input size (see
2938*cf2f2c56Smiod    mmix_set_relaxable_raw_size), we have to take care of that when reading
2939*cf2f2c56Smiod    the section.  */
2940*cf2f2c56Smiod 
2941*cf2f2c56Smiod static bfd_boolean
mmix_elf_get_section_contents(abfd,section,location,offset,count)2942*cf2f2c56Smiod mmix_elf_get_section_contents (abfd, section, location, offset, count)
2943*cf2f2c56Smiod      bfd *abfd;
2944*cf2f2c56Smiod      sec_ptr section;
2945*cf2f2c56Smiod      void *location;
2946*cf2f2c56Smiod      file_ptr offset;
2947*cf2f2c56Smiod      bfd_size_type count;
2948*cf2f2c56Smiod {
2949*cf2f2c56Smiod   bfd_size_type raw_size
2950*cf2f2c56Smiod     = (section->_raw_size
2951*cf2f2c56Smiod        - mmix_elf_section_data (section)->pjs.n_pushj_relocs
2952*cf2f2c56Smiod        * MAX_PUSHJ_STUB_SIZE);
2953*cf2f2c56Smiod 
2954*cf2f2c56Smiod   if (offset + count > section->_raw_size)
2955*cf2f2c56Smiod     {
2956*cf2f2c56Smiod       abort();
2957*cf2f2c56Smiod       bfd_set_error (bfd_error_invalid_operation);
2958*cf2f2c56Smiod       return FALSE;
2959*cf2f2c56Smiod     }
2960*cf2f2c56Smiod 
2961*cf2f2c56Smiod   /* Check bounds against the faked raw_size.  */
2962*cf2f2c56Smiod   if (offset + count > raw_size)
2963*cf2f2c56Smiod     {
2964*cf2f2c56Smiod       /* Clear the part in the faked area.  */
2965*cf2f2c56Smiod       memset (location + raw_size - offset, 0, count - (raw_size - offset));
2966*cf2f2c56Smiod 
2967*cf2f2c56Smiod       /* If there's no initial part within the "real" contents, we're
2968*cf2f2c56Smiod          done.  */
2969*cf2f2c56Smiod       if ((bfd_size_type) offset >= raw_size)
2970*cf2f2c56Smiod 	return TRUE;
2971*cf2f2c56Smiod 
2972*cf2f2c56Smiod       /* Else adjust the count and fall through to call the generic
2973*cf2f2c56Smiod          function.  */
2974*cf2f2c56Smiod       count = raw_size - offset;
2975*cf2f2c56Smiod     }
2976*cf2f2c56Smiod 
2977*cf2f2c56Smiod   return
2978*cf2f2c56Smiod     _bfd_generic_get_section_contents (abfd, section, location, offset,
2979*cf2f2c56Smiod 				       count);
2980*cf2f2c56Smiod }
2981*cf2f2c56Smiod 
2982d2201f2fSdrahn 
2983d2201f2fSdrahn #define ELF_ARCH		bfd_arch_mmix
2984d2201f2fSdrahn #define ELF_MACHINE_CODE 	EM_MMIX
2985d2201f2fSdrahn 
2986d2201f2fSdrahn /* According to mmix-doc page 36 (paragraph 45), this should be (1LL << 48LL).
2987d2201f2fSdrahn    However, that's too much for something somewhere in the linker part of
2988d2201f2fSdrahn    BFD; perhaps the start-address has to be a non-zero multiple of this
2989d2201f2fSdrahn    number, or larger than this number.  The symptom is that the linker
2990d2201f2fSdrahn    complains: "warning: allocated section `.text' not in segment".  We
2991d2201f2fSdrahn    settle for 64k; the page-size used in examples is 8k.
2992d2201f2fSdrahn    #define ELF_MAXPAGESIZE 0x10000
2993d2201f2fSdrahn 
2994d2201f2fSdrahn    Unfortunately, this causes excessive padding in the supposedly small
2995d2201f2fSdrahn    for-education programs that are the expected usage (where people would
2996d2201f2fSdrahn    inspect output).  We stick to 256 bytes just to have *some* default
2997d2201f2fSdrahn    alignment.  */
2998d2201f2fSdrahn #define ELF_MAXPAGESIZE 0x100
2999d2201f2fSdrahn 
3000d2201f2fSdrahn #define TARGET_BIG_SYM		bfd_elf64_mmix_vec
3001d2201f2fSdrahn #define TARGET_BIG_NAME		"elf64-mmix"
3002d2201f2fSdrahn 
3003d2201f2fSdrahn #define elf_info_to_howto_rel		NULL
3004d2201f2fSdrahn #define elf_info_to_howto		mmix_info_to_howto_rela
3005d2201f2fSdrahn #define elf_backend_relocate_section	mmix_elf_relocate_section
3006d2201f2fSdrahn #define elf_backend_gc_mark_hook	mmix_elf_gc_mark_hook
3007d2201f2fSdrahn #define elf_backend_gc_sweep_hook	mmix_elf_gc_sweep_hook
3008d2201f2fSdrahn 
3009d2201f2fSdrahn #define elf_backend_link_output_symbol_hook \
3010d2201f2fSdrahn 	mmix_elf_link_output_symbol_hook
3011d2201f2fSdrahn #define elf_backend_add_symbol_hook	mmix_elf_add_symbol_hook
3012d2201f2fSdrahn 
3013d2201f2fSdrahn #define elf_backend_check_relocs	mmix_elf_check_relocs
3014d2201f2fSdrahn #define elf_backend_symbol_processing	mmix_elf_symbol_processing
3015d2201f2fSdrahn 
3016d2201f2fSdrahn #define bfd_elf64_bfd_is_local_label_name \
3017d2201f2fSdrahn 	mmix_elf_is_local_label_name
3018d2201f2fSdrahn 
3019d2201f2fSdrahn #define elf_backend_may_use_rel_p	0
3020d2201f2fSdrahn #define elf_backend_may_use_rela_p	1
3021d2201f2fSdrahn #define elf_backend_default_use_rela_p	1
3022d2201f2fSdrahn 
3023d2201f2fSdrahn #define elf_backend_can_gc_sections	1
3024d2201f2fSdrahn #define elf_backend_section_from_bfd_section \
3025d2201f2fSdrahn 	mmix_elf_section_from_bfd_section
3026d2201f2fSdrahn 
3027d2201f2fSdrahn #define bfd_elf64_new_section_hook	mmix_elf_new_section_hook
3028d2201f2fSdrahn #define bfd_elf64_bfd_final_link	mmix_elf_final_link
3029d2201f2fSdrahn #define bfd_elf64_bfd_relax_section	mmix_elf_relax_section
3030*cf2f2c56Smiod #define bfd_elf64_get_section_contents	mmix_elf_get_section_contents
3031d2201f2fSdrahn 
3032d2201f2fSdrahn #include "elf64-target.h"
3033