1250199Sgrehan/* Motorola 68HC11-specific support for 32-bit ELF
2324461Ssephe   Copyright (C) 1999-2022 Free Software Foundation, Inc.
3250199Sgrehan   Contributed by Stephane Carrez (stcarrez@nerim.fr)
4250199Sgrehan   (Heavily copied from the D10V port by Martin Hunt (hunt@cygnus.com))
5250199Sgrehan
6250199Sgrehan   This file is part of BFD, the Binary File Descriptor library.
7250199Sgrehan
8250199Sgrehan   This program is free software; you can redistribute it and/or modify
9250199Sgrehan   it under the terms of the GNU General Public License as published by
10250199Sgrehan   the Free Software Foundation; either version 3 of the License, or
11250199Sgrehan   (at your option) any later version.
12250199Sgrehan
13250199Sgrehan   This program is distributed in the hope that it will be useful,
14250199Sgrehan   but WITHOUT ANY WARRANTY; without even the implied warranty of
15250199Sgrehan   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16250199Sgrehan   GNU General Public License for more details.
17250199Sgrehan
18250199Sgrehan   You should have received a copy of the GNU General Public License
19250199Sgrehan   along with this program; if not, write to the Free Software
20250199Sgrehan   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21250199Sgrehan   MA 02110-1301, USA.  */
22250199Sgrehan
23250199Sgrehan#include "sysdep.h"
24250199Sgrehan#include "bfd.h"
25250199Sgrehan#include "bfdlink.h"
26250199Sgrehan#include "libbfd.h"
27250199Sgrehan#include "elf-bfd.h"
28250199Sgrehan#include "elf32-m68hc1x.h"
29308504Ssephe#include "elf/m68hc11.h"
30308504Ssephe#include "opcode/m68hc11.h"
31250199Sgrehan
32250199Sgrehan/* Relocation functions.  */
33308504Ssephestatic reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup
34308504Ssephe  (bfd *, bfd_reloc_code_real_type);
35250199Sgrehanstatic bool m68hc11_info_to_howto_rel
36308504Ssephe  (bfd *, arelent *, Elf_Internal_Rela *);
37308504Ssephe
38308504Ssephe/* Trampoline generation.  */
39250199Sgrehanstatic bool m68hc11_elf_size_one_stub
40250199Sgrehan  (struct bfd_hash_entry *gen_entry, void *in_arg);
41308504Ssephestatic bool m68hc11_elf_build_one_stub
42250199Sgrehan  (struct bfd_hash_entry *gen_entry, void *in_arg);
43308504Ssephestatic struct bfd_link_hash_table* m68hc11_elf_bfd_link_hash_table_create
44308504Ssephe  (bfd* abfd);
45308504Ssephe
46324466Ssephe/* Linker relaxation.  */
47250199Sgrehanstatic bool m68hc11_elf_relax_section
48250199Sgrehan  (bfd *, asection *, struct bfd_link_info *, bool *);
49308504Ssephestatic void m68hc11_elf_relax_delete_bytes
50250199Sgrehan  (bfd *, asection *, bfd_vma, int);
51308504Ssephestatic void m68hc11_relax_group
52308504Ssephe  (bfd *, asection *, bfd_byte *, unsigned, unsigned long, unsigned long);
53308504Ssephestatic int compare_reloc (const void *, const void *);
54250199Sgrehan
55308504Ssephe/* Use REL instead of RELA to save space */
56308504Ssephe#define USE_REL	1
57307164Ssephe
58308504Ssephe/* The Motorola 68HC11 microcontroller only addresses 64Kb but we also
59308504Ssephe   support a memory bank switching mechanism similar to 68HC12.
60307164Ssephe   We must handle 8 and 16-bit relocations.  The 32-bit relocation
61307199Ssephe   are used for debugging sections (DWARF2) to represent a virtual
62308505Ssephe   address.
63250199Sgrehan   The 3-bit and 16-bit PC rel relocation is only used by 68HC12.  */
64308504Ssephestatic reloc_howto_type elf_m68hc11_howto_table[] = {
65308504Ssephe  /* This reloc does nothing.  */
66310757Ssephe  HOWTO (R_M68HC11_NONE,	/* type */
67310757Ssephe	 0,			/* rightshift */
68308504Ssephe	 0,			/* size */
69308504Ssephe	 0,			/* bitsize */
70308504Ssephe	 false,			/* pc_relative */
71308504Ssephe	 0,			/* bitpos */
72308504Ssephe	 complain_overflow_dont,/* complain_on_overflow */
73308504Ssephe	 bfd_elf_generic_reloc,	/* special_function */
74308504Ssephe	 "R_M68HC11_NONE",	/* name */
75308504Ssephe	 false,			/* partial_inplace */
76308504Ssephe	 0,			/* src_mask */
77308504Ssephe	 0,			/* dst_mask */
78250199Sgrehan	 false),		/* pcrel_offset */
79308504Ssephe
80308504Ssephe  /* A 8 bit absolute relocation */
81307161Ssephe  HOWTO (R_M68HC11_8,		/* type */
82307200Ssephe	 0,			/* rightshift */
83307200Ssephe	 1,			/* size */
84307200Ssephe	 8,			/* bitsize */
85307200Ssephe	 false,			/* pc_relative */
86307200Ssephe	 0,			/* bitpos */
87307200Ssephe	 complain_overflow_bitfield,	/* complain_on_overflow */
88307200Ssephe	 bfd_elf_generic_reloc,	/* special_function */
89307206Ssephe	 "R_M68HC11_8",		/* name */
90307174Ssephe	 false,			/* partial_inplace */
91307186Ssephe	 0x00ff,		/* src_mask */
92285236Swhu	 0x00ff,		/* dst_mask */
93308504Ssephe	 false),		/* pcrel_offset */
94307186Ssephe
95307186Ssephe  /* A 8 bit absolute relocation (upper address) */
96307174Ssephe  HOWTO (R_M68HC11_HI8,		/* type */
97285236Swhu	 8,			/* rightshift */
98307186Ssephe	 1,			/* size */
99307186Ssephe	 8,			/* bitsize */
100307186Ssephe	 false,			/* pc_relative */
101307186Ssephe	 0,			/* bitpos */
102307186Ssephe	 complain_overflow_bitfield,	/* complain_on_overflow */
103307186Ssephe	 bfd_elf_generic_reloc,	/* special_function */
104308504Ssephe	 "R_M68HC11_HI8",	/* name */
105307186Ssephe	 false,			/* partial_inplace */
106307174Ssephe	 0x00ff,		/* src_mask */
107307174Ssephe	 0x00ff,		/* dst_mask */
108307174Ssephe	 false),		/* pcrel_offset */
109307174Ssephe
110307174Ssephe  /* A 8 bit absolute relocation (upper address) */
111307186Ssephe  HOWTO (R_M68HC11_LO8,		/* type */
112307174Ssephe	 0,			/* rightshift */
113310757Ssephe	 1,			/* size */
114310757Ssephe	 8,			/* bitsize */
115307186Ssephe	 false,			/* pc_relative */
116307186Ssephe	 0,			/* bitpos */
117307186Ssephe	 complain_overflow_dont,	/* complain_on_overflow */
118307186Ssephe	 bfd_elf_generic_reloc,	/* special_function */
119307186Ssephe	 "R_M68HC11_LO8",	/* name */
120307186Ssephe	 false,			/* partial_inplace */
121307186Ssephe	 0x00ff,		/* src_mask */
122307186Ssephe	 0x00ff,		/* dst_mask */
123307186Ssephe	 false),		/* pcrel_offset */
124307186Ssephe
125307186Ssephe  /* A 8 bit PC-rel relocation */
126307186Ssephe  HOWTO (R_M68HC11_PCREL_8,	/* type */
127307186Ssephe	 0,			/* rightshift */
128307186Ssephe	 1,			/* size */
129307186Ssephe	 8,			/* bitsize */
130307186Ssephe	 true,			/* pc_relative */
131307174Ssephe	 0,			/* bitpos */
132285236Swhu	 complain_overflow_bitfield,	/* complain_on_overflow */
133307174Ssephe	 bfd_elf_generic_reloc,	/* special_function */
134307174Ssephe	 "R_M68HC11_PCREL_8",	/* name */
135307174Ssephe	 false,			/* partial_inplace */
136285236Swhu	 0x00ff,		/* src_mask */
137307174Ssephe	 0x00ff,		/* dst_mask */
138308504Ssephe	 true),			/* pcrel_offset */
139285236Swhu
140285236Swhu  /* A 16 bit absolute relocation */
141250199Sgrehan  HOWTO (R_M68HC11_16,		/* type */
142307206Ssephe	 0,			/* rightshift */
143250199Sgrehan	 2,			/* size */
144307174Ssephe	 16,			/* bitsize */
145307164Ssephe	 false,			/* pc_relative */
146307164Ssephe	 0,			/* bitpos */
147307164Ssephe	 complain_overflow_dont /*bitfield */ ,	/* complain_on_overflow */
148307164Ssephe	 bfd_elf_generic_reloc,	/* special_function */
149307200Ssephe	 "R_M68HC11_16",	/* name */
150250199Sgrehan	 false,			/* partial_inplace */
151307200Ssephe	 0xffff,		/* src_mask */
152307200Ssephe	 0xffff,		/* dst_mask */
153307200Ssephe	 false),		/* pcrel_offset */
154307200Ssephe
155308504Ssephe  /* A 32 bit absolute relocation.  This one is never used for the
156307200Ssephe     code relocation.  It's used by gas for -gstabs generation.  */
157308504Ssephe  HOWTO (R_M68HC11_32,		/* type */
158250199Sgrehan	 0,			/* rightshift */
159250199Sgrehan	 4,			/* size */
160307081Ssephe	 32,			/* bitsize */
161307081Ssephe	 false,			/* pc_relative */
162307081Ssephe	 0,			/* bitpos */
163307081Ssephe	 complain_overflow_bitfield,	/* complain_on_overflow */
164307081Ssephe	 bfd_elf_generic_reloc,	/* special_function */
165250199Sgrehan	 "R_M68HC11_32",	/* name */
166307164Ssephe	 false,			/* partial_inplace */
167307174Ssephe	 0xffffffff,		/* src_mask */
168307164Ssephe	 0xffffffff,		/* dst_mask */
169307206Ssephe	 false),		/* pcrel_offset */
170307164Ssephe
171250199Sgrehan  /* A 3 bit absolute relocation */
172250199Sgrehan  HOWTO (R_M68HC11_3B,		/* type */
173250199Sgrehan	 0,			/* rightshift */
174307164Ssephe	 1,			/* size */
175307164Ssephe	 3,			/* bitsize */
176307164Ssephe	 false,			/* pc_relative */
177250199Sgrehan	 0,			/* bitpos */
178307164Ssephe	 complain_overflow_bitfield,	/* complain_on_overflow */
179307164Ssephe	 bfd_elf_generic_reloc,	/* special_function */
180307164Ssephe	 "R_M68HC11_4B",	/* name */
181307164Ssephe	 false,			/* partial_inplace */
182307164Ssephe	 0x003,			/* src_mask */
183307164Ssephe	 0x003,			/* dst_mask */
184307164Ssephe	 false),		/* pcrel_offset */
185307164Ssephe
186307174Ssephe  /* A 16 bit PC-rel relocation */
187307164Ssephe  HOWTO (R_M68HC11_PCREL_16,	/* type */
188250199Sgrehan	 0,			/* rightshift */
189307186Ssephe	 2,			/* size */
190307186Ssephe	 16,			/* bitsize */
191307186Ssephe	 true,			/* pc_relative */
192307174Ssephe	 0,			/* bitpos */
193307206Ssephe	 complain_overflow_dont,	/* complain_on_overflow */
194307174Ssephe	 bfd_elf_generic_reloc,	/* special_function */
195250199Sgrehan	 "R_M68HC11_PCREL_16",	/* name */
196250199Sgrehan	 false,			/* partial_inplace */
197250199Sgrehan	 0xffff,		/* src_mask */
198307164Ssephe	 0xffff,		/* dst_mask */
199307164Ssephe	 true),			/* pcrel_offset */
200307174Ssephe
201250199Sgrehan  /* GNU extension to record C++ vtable hierarchy */
202307164Ssephe  HOWTO (R_M68HC11_GNU_VTINHERIT,	/* type */
203307206Ssephe	 0,			/* rightshift */
204307164Ssephe	 2,			/* size */
205250199Sgrehan	 0,			/* bitsize */
206250199Sgrehan	 false,			/* pc_relative */
207307174Ssephe	 0,			/* bitpos */
208250199Sgrehan	 complain_overflow_dont,	/* complain_on_overflow */
209307164Ssephe	 NULL,			/* special_function */
210250199Sgrehan	 "R_M68HC11_GNU_VTINHERIT",	/* name */
211250199Sgrehan	 false,			/* partial_inplace */
212307174Ssephe	 0,			/* src_mask */
213307174Ssephe	 0,			/* dst_mask */
214307206Ssephe	 false),		/* pcrel_offset */
215307164Ssephe
216250199Sgrehan  /* GNU extension to record C++ vtable member usage */
217250199Sgrehan  HOWTO (R_M68HC11_GNU_VTENTRY,	/* type */
218250199Sgrehan	 0,			/* rightshift */
219307206Ssephe	 2,			/* size */
220250199Sgrehan	 0,			/* bitsize */
221307174Ssephe	 false,			/* pc_relative */
222307164Ssephe	 0,			/* bitpos */
223307164Ssephe	 complain_overflow_dont,	/* complain_on_overflow */
224307164Ssephe	 _bfd_elf_rel_vtable_reloc_fn,	/* special_function */
225307164Ssephe	 "R_M68HC11_GNU_VTENTRY",	/* name */
226307164Ssephe	 false,			/* partial_inplace */
227250199Sgrehan	 0,			/* src_mask */
228250199Sgrehan	 0,			/* dst_mask */
229307081Ssephe	 false),		/* pcrel_offset */
230307081Ssephe
231307081Ssephe  /* A 24 bit relocation */
232307081Ssephe  HOWTO (R_M68HC11_24,		/* type */
233307081Ssephe	 0,			/* rightshift */
234250199Sgrehan	 2,			/* size */
235307164Ssephe	 24,			/* bitsize */
236308504Ssephe	 false,			/* pc_relative */
237307164Ssephe	 0,			/* bitpos */
238307206Ssephe	 complain_overflow_bitfield,	/* complain_on_overflow */
239250199Sgrehan	 bfd_elf_generic_reloc,	/* special_function */
240250199Sgrehan	 "R_M68HC11_24",	/* name */
241250199Sgrehan	 false,			/* partial_inplace */
242307164Ssephe	 0xffffff,		/* src_mask */
243307164Ssephe	 0xffffff,		/* dst_mask */
244307164Ssephe	 false),		/* pcrel_offset */
245250199Sgrehan
246307164Ssephe  /* A 16-bit low relocation */
247307164Ssephe  HOWTO (R_M68HC11_LO16,	/* type */
248307164Ssephe	 0,			/* rightshift */
249307164Ssephe	 2,			/* size */
250307164Ssephe	 16,			/* bitsize */
251307164Ssephe	 false,			/* pc_relative */
252307164Ssephe	 0,			/* bitpos */
253307164Ssephe	 complain_overflow_bitfield,	/* complain_on_overflow */
254307174Ssephe	 bfd_elf_generic_reloc,	/* special_function */
255307164Ssephe	 "R_M68HC11_LO16",	/* name */
256250199Sgrehan	 false,			/* partial_inplace */
257307186Ssephe	 0xffff,		/* src_mask */
258307186Ssephe	 0xffff,		/* dst_mask */
259307186Ssephe	 false),		/* pcrel_offset */
260307174Ssephe
261307206Ssephe  /* A page relocation */
262307174Ssephe  HOWTO (R_M68HC11_PAGE,	/* type */
263250199Sgrehan	 0,			/* rightshift */
264250199Sgrehan	 1,			/* size */
265250199Sgrehan	 8,			/* bitsize */
266307164Ssephe	 false,			/* pc_relative */
267307164Ssephe	 0,			/* bitpos */
268307164Ssephe	 complain_overflow_bitfield,	/* complain_on_overflow */
269307174Ssephe	 bfd_elf_generic_reloc,	/* special_function */
270307164Ssephe	 "R_M68HC11_PAGE",	/* name */
271307164Ssephe	 false,			/* partial_inplace */
272307206Ssephe	 0x00ff,		/* src_mask */
273307164Ssephe	 0x00ff,		/* dst_mask */
274250199Sgrehan	 false),		/* pcrel_offset */
275250199Sgrehan
276315437Ssephe  EMPTY_HOWTO (14),
277310757Ssephe  EMPTY_HOWTO (15),
278310757Ssephe  EMPTY_HOWTO (16),
279310757Ssephe  EMPTY_HOWTO (17),
280315437Ssephe  EMPTY_HOWTO (18),
281315437Ssephe  EMPTY_HOWTO (19),
282315437Ssephe
283315437Ssephe  /* Mark beginning of a jump instruction (any form).  */
284315437Ssephe  HOWTO (R_M68HC11_RL_JUMP,	/* type */
285315437Ssephe	 0,			/* rightshift */
286315437Ssephe	 2,			/* size */
287310757Ssephe	 0,			/* bitsize */
288310757Ssephe	 false,			/* pc_relative */
289310757Ssephe	 0,			/* bitpos */
290307206Ssephe	 complain_overflow_dont,	/* complain_on_overflow */
291307164Ssephe	 m68hc11_elf_ignore_reloc,	/* special_function */
292250199Sgrehan	 "R_M68HC11_RL_JUMP",	/* name */
293307174Ssephe	 true,			/* partial_inplace */
294308504Ssephe	 0,			/* src_mask */
295308504Ssephe	 0,			/* dst_mask */
296307174Ssephe	 true),			/* pcrel_offset */
297307174Ssephe
298307174Ssephe  /* Mark beginning of Gcc relaxation group instruction.  */
299307174Ssephe  HOWTO (R_M68HC11_RL_GROUP,	/* type */
300307174Ssephe	 0,			/* rightshift */
301307174Ssephe	 2,			/* size */
302307174Ssephe	 0,			/* bitsize */
303250199Sgrehan	 false,			/* pc_relative */
304307174Ssephe	 0,			/* bitpos */
305307174Ssephe	 complain_overflow_dont,	/* complain_on_overflow */
306308503Ssephe	 m68hc11_elf_ignore_reloc,	/* special_function */
307307174Ssephe	 "R_M68HC11_RL_GROUP",	/* name */
308307174Ssephe	 true,			/* partial_inplace */
309307174Ssephe	 0,			/* src_mask */
310307164Ssephe	 0,			/* dst_mask */
311307174Ssephe	 true),			/* pcrel_offset */
312307174Ssephe};
313307164Ssephe
314307206Ssephe/* Map BFD reloc types to M68HC11 ELF reloc types.  */
315250199Sgrehan
316250199Sgrehanstruct m68hc11_reloc_map
317307174Ssephe{
318307174Ssephe  bfd_reloc_code_real_type bfd_reloc_val;
319307206Ssephe  unsigned char elf_reloc_val;
320307164Ssephe};
321250199Sgrehan
322250199Sgrehanstatic const struct m68hc11_reloc_map m68hc11_reloc_map[] = {
323310757Ssephe  {BFD_RELOC_NONE, R_M68HC11_NONE,},
324307206Ssephe  {BFD_RELOC_8, R_M68HC11_8},
325250199Sgrehan  {BFD_RELOC_M68HC11_HI8, R_M68HC11_HI8},
326307206Ssephe  {BFD_RELOC_M68HC11_LO8, R_M68HC11_LO8},
327250199Sgrehan  {BFD_RELOC_8_PCREL, R_M68HC11_PCREL_8},
328307174Ssephe  {BFD_RELOC_16_PCREL, R_M68HC11_PCREL_16},
329307164Ssephe  {BFD_RELOC_16, R_M68HC11_16},
330250199Sgrehan  {BFD_RELOC_32, R_M68HC11_32},
331307164Ssephe  {BFD_RELOC_M68HC11_3B, R_M68HC11_3B},
332307164Ssephe
333307164Ssephe  {BFD_RELOC_VTABLE_INHERIT, R_M68HC11_GNU_VTINHERIT},
334307164Ssephe  {BFD_RELOC_VTABLE_ENTRY, R_M68HC11_GNU_VTENTRY},
335307164Ssephe
336307164Ssephe  {BFD_RELOC_M68HC11_LO16, R_M68HC11_LO16},
337250199Sgrehan  {BFD_RELOC_M68HC11_PAGE, R_M68HC11_PAGE},
338307167Ssephe  {BFD_RELOC_M68HC11_24, R_M68HC11_24},
339307206Ssephe
340307206Ssephe  {BFD_RELOC_M68HC11_RL_JUMP, R_M68HC11_RL_JUMP},
341307174Ssephe  {BFD_RELOC_M68HC11_RL_GROUP, R_M68HC11_RL_GROUP},
342307206Ssephe};
343310757Ssephe
344310757Ssephestatic reloc_howto_type *
345310757Ssephebfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
346310757Ssephe				 bfd_reloc_code_real_type code)
347310757Ssephe{
348310757Ssephe  unsigned int i;
349250199Sgrehan
350307174Ssephe  for (i = 0;
351307250Ssephe       i < sizeof (m68hc11_reloc_map) / sizeof (struct m68hc11_reloc_map);
352307250Ssephe       i++)
353307250Ssephe    {
354310743Ssephe      if (m68hc11_reloc_map[i].bfd_reloc_val == code)
355310743Ssephe	return &elf_m68hc11_howto_table[m68hc11_reloc_map[i].elf_reloc_val];
356310743Ssephe    }
357310743Ssephe
358307250Ssephe  return NULL;
359310743Ssephe}
360310743Ssephe
361307250Ssephestatic reloc_howto_type *
362307250Ssephebfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
363307250Ssephe				 const char *r_name)
364307250Ssephe{
365307250Ssephe  unsigned int i;
366250199Sgrehan
367307206Ssephe  for (i = 0;
368307174Ssephe       i < (sizeof (elf_m68hc11_howto_table)
369250199Sgrehan	    / sizeof (elf_m68hc11_howto_table[0]));
370307174Ssephe       i++)
371250199Sgrehan    if (elf_m68hc11_howto_table[i].name != NULL
372307206Ssephe	&& strcasecmp (elf_m68hc11_howto_table[i].name, r_name) == 0)
373307174Ssephe      return &elf_m68hc11_howto_table[i];
374307206Ssephe
375307174Ssephe  return NULL;
376307206Ssephe}
377310757Ssephe
378250199Sgrehan/* Set the howto pointer for an M68HC11 ELF reloc.  */
379307174Ssephe
380250199Sgrehanstatic bool
381250199Sgrehanm68hc11_info_to_howto_rel (bfd *abfd,
382250199Sgrehan			   arelent *cache_ptr, Elf_Internal_Rela *dst)
383310757Ssephe{
384307206Ssephe  unsigned int r_type;
385250199Sgrehan
386307206Ssephe  r_type = ELF32_R_TYPE (dst->r_info);
387250199Sgrehan  if (r_type >= (unsigned int) R_M68HC11_max)
388307174Ssephe    {
389307164Ssephe      /* xgettext:c-format */
390250199Sgrehan      _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
391307164Ssephe			  abfd, r_type);
392307164Ssephe      bfd_set_error (bfd_error_bad_value);
393307164Ssephe      return false;
394307164Ssephe    }
395307164Ssephe  cache_ptr->howto = &elf_m68hc11_howto_table[r_type];
396307164Ssephe  return true;
397250199Sgrehan}
398307167Ssephe
399307206Ssephe
400307206Ssephe/* Far trampoline generation.  */
401307174Ssephe
402307206Ssephe/* Build a 68HC11 trampoline stub.  */
403310757Ssephestatic bool
404310757Ssephem68hc11_elf_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
405310757Ssephe{
406310757Ssephe  struct elf32_m68hc11_stub_hash_entry *stub_entry;
407310757Ssephe  struct bfd_link_info *info;
408310757Ssephe  struct m68hc11_elf_link_hash_table *htab;
409250199Sgrehan  asection *stub_sec;
410307174Ssephe  bfd *stub_bfd;
411307250Ssephe  bfd_byte *loc;
412307250Ssephe  bfd_vma sym_value, phys_page, phys_addr;
413307250Ssephe
414310743Ssephe  /* Massage our args to the form they really have.  */
415310743Ssephe  stub_entry = (struct elf32_m68hc11_stub_hash_entry *) gen_entry;
416310743Ssephe  info = (struct bfd_link_info *) in_arg;
417310743Ssephe
418307250Ssephe  /* Fail if the target section could not be assigned to an output
419310743Ssephe     section.  The user should fix his linker script.  */
420310743Ssephe  if (stub_entry->target_section->output_section == NULL
421307250Ssephe      && info->non_contiguous_regions)
422307250Ssephe    info->callbacks->einfo (_("%F%P: Could not assign '%pA' to an output section. "
423307250Ssephe			      "Retry without --enable-non-contiguous-regions.\n"),
424307250Ssephe			    stub_entry->target_section);
425307250Ssephe
426307250Ssephe  htab = m68hc11_elf_hash_table (info);
427250199Sgrehan  if (htab == NULL)
428307206Ssephe    return false;
429307174Ssephe
430250199Sgrehan  stub_sec = stub_entry->stub_sec;
431307174Ssephe
432250199Sgrehan  /* Make a note of the offset within the stubs for this entry.  */
433307206Ssephe  stub_entry->stub_offset = stub_sec->size;
434307174Ssephe  stub_sec->size += 10;
435307206Ssephe  loc = stub_sec->contents + stub_entry->stub_offset;
436307174Ssephe
437307206Ssephe  stub_bfd = stub_sec->owner;
438310757Ssephe
439250199Sgrehan  /* Create the trampoline call stub:
440307174Ssephe
441250199Sgrehan     pshb
442250199Sgrehan     ldab #%page(symbol)
443307174Ssephe     ldy #%addr(symbol)
444308503Ssephe     jmp __trampoline
445307174Ssephe
446310757Ssephe  */
447250199Sgrehan  sym_value = (stub_entry->target_value
448250199Sgrehan	       + stub_entry->target_section->output_offset
449250199Sgrehan	       + stub_entry->target_section->output_section->vma);
450250199Sgrehan  phys_addr = m68hc11_phys_addr (&htab->pinfo, sym_value);
451307200Ssephe  phys_page = m68hc11_phys_page (&htab->pinfo, sym_value);
452250199Sgrehan
453307164Ssephe  /* pshb; ldab #%page(sym) */
454307164Ssephe  bfd_put_8 (stub_bfd, 0x37, loc);
455307164Ssephe  bfd_put_8 (stub_bfd, 0xC6, loc + 1);
456307164Ssephe  bfd_put_8 (stub_bfd, phys_page, loc + 2);
457307164Ssephe  loc += 3;
458250199Sgrehan
459307164Ssephe  /* ldy #%addr(sym)  */
460307164Ssephe  bfd_put_8 (stub_bfd, 0x18, loc);
461307164Ssephe  bfd_put_8 (stub_bfd, 0xCE, loc + 1);
462307164Ssephe  bfd_put_16 (stub_bfd, phys_addr, loc + 2);
463307164Ssephe  loc += 4;
464307164Ssephe
465307164Ssephe  /* jmp __trampoline  */
466307164Ssephe  bfd_put_8 (stub_bfd, 0x7E, loc);
467307164Ssephe  bfd_put_16 (stub_bfd, htab->pinfo.trampoline_addr, loc + 1);
468250199Sgrehan
469307186Ssephe  return true;
470307186Ssephe}
471307186Ssephe
472307174Ssephe/* As above, but don't actually build the stub.  Just bump offset so
473307174Ssephe   we know stub section sizes.  */
474307164Ssephe
475307174Ssephestatic bool
476307164Ssephem68hc11_elf_size_one_stub (struct bfd_hash_entry *gen_entry,
477250199Sgrehan			   void *in_arg ATTRIBUTE_UNUSED)
478307164Ssephe{
479307164Ssephe  struct elf32_m68hc11_stub_hash_entry *stub_entry;
480307164Ssephe
481307164Ssephe  /* Massage our args to the form they really have.  */
482307246Ssephe  stub_entry = (struct elf32_m68hc11_stub_hash_entry *) gen_entry;
483307246Ssephe
484307246Ssephe  stub_entry->stub_sec->size += 10;
485307246Ssephe  return true;
486307246Ssephe}
487307246Ssephe
488307246Ssephe/* Create a 68HC11 ELF linker hash table.  */
489307246Ssephe
490307246Ssephestatic struct bfd_link_hash_table *
491250199Sgrehanm68hc11_elf_bfd_link_hash_table_create (bfd *abfd)
492307164Ssephe{
493250199Sgrehan  struct m68hc11_elf_link_hash_table *ret;
494250199Sgrehan
495250199Sgrehan  ret = m68hc11_elf_hash_table_create (abfd);
496250199Sgrehan  if (ret == (struct m68hc11_elf_link_hash_table *) NULL)
497307202Ssephe    return NULL;
498250199Sgrehan
499250199Sgrehan  ret->size_one_stub = m68hc11_elf_size_one_stub;
500307202Ssephe  ret->build_one_stub = m68hc11_elf_build_one_stub;
501250199Sgrehan
502307164Ssephe  return &ret->root.root;
503307164Ssephe}
504250199Sgrehan
505307164Ssephe
506307164Ssephe/* 68HC11 Linker Relaxation.  */
507324466Ssephe
508307164Ssepheconst struct m68hc11_direct_relax
509314123Sdexuan{
510314123Sdexuan  const char *name;
511250199Sgrehan  unsigned char code;
512307167Ssephe  unsigned char direct_code;
513307174Ssephe} m68hc11_direct_relax_table[] = {
514307245Ssephe  { "adca", 0xB9, 0x99 },
515307164Ssephe  { "adcb", 0xF9, 0xD9 },
516307245Ssephe  { "adda", 0xBB, 0x9B },
517307245Ssephe  { "addb", 0xFB, 0xDB },
518307245Ssephe  { "addd", 0xF3, 0xD3 },
519307245Ssephe  { "anda", 0xB4, 0x94 },
520307245Ssephe  { "andb", 0xF4, 0xD4 },
521307245Ssephe  { "cmpa", 0xB1, 0x91 },
522307245Ssephe  { "cmpb", 0xF1, 0xD1 },
523250199Sgrehan  { "cpd",  0xB3, 0x93 },
524250199Sgrehan  { "cpxy", 0xBC, 0x9C },
525250199Sgrehan/* { "cpy",  0xBC, 0x9C }, */
526307202Ssephe  { "eora", 0xB8, 0x98 },
527307202Ssephe  { "eorb", 0xF8, 0xD8 },
528307202Ssephe  { "jsr",  0xBD, 0x9D },
529307202Ssephe  { "ldaa", 0xB6, 0x96 },
530307202Ssephe  { "ldab", 0xF6, 0xD6 },
531307202Ssephe  { "ldd",  0xFC, 0xDC },
532307202Ssephe  { "lds",  0xBE, 0x9E },
533307202Ssephe  { "ldxy", 0xFE, 0xDE },
534307202Ssephe  /*  { "ldy",  0xFE, 0xDE },*/
535307202Ssephe  { "oraa", 0xBA, 0x9A },
536307202Ssephe  { "orab", 0xFA, 0xDA },
537307202Ssephe  { "sbca", 0xB2, 0x92 },
538307202Ssephe  { "sbcb", 0xF2, 0xD2 },
539307202Ssephe  { "staa", 0xB7, 0x97 },
540307202Ssephe  { "stab", 0xF7, 0xD7 },
541307202Ssephe  { "std",  0xFD, 0xDD },
542307202Ssephe  { "sts",  0xBF, 0x9F },
543307202Ssephe  { "stxy", 0xFF, 0xDF },
544307200Ssephe  /*  { "sty",  0xFF, 0xDF },*/
545250199Sgrehan  { "suba", 0xB0, 0x90 },
546307246Ssephe  { "subb", 0xF0, 0xD0 },
547250199Sgrehan  { "subd", 0xB3, 0x93 },
548307245Ssephe  { 0, 0, 0 }
549307245Ssephe};
550307245Ssephe
551307245Ssephestatic const struct m68hc11_direct_relax *
552307245Ssephefind_relaxable_insn (unsigned char code)
553307245Ssephe{
554307245Ssephe  int i;
555307245Ssephe
556307245Ssephe  for (i = 0; m68hc11_direct_relax_table[i].name; i++)
557307245Ssephe    if (m68hc11_direct_relax_table[i].code == code)
558307246Ssephe      return &m68hc11_direct_relax_table[i];
559307246Ssephe
560307246Ssephe  return 0;
561307246Ssephe}
562307246Ssephe
563308494Ssephestatic int
564307246Ssephecompare_reloc (const void *e1, const void *e2)
565308494Ssephe{
566307245Ssephe  const Elf_Internal_Rela *i1 = (const Elf_Internal_Rela *) e1;
567307245Ssephe  const Elf_Internal_Rela *i2 = (const Elf_Internal_Rela *) e2;
568307245Ssephe
569307245Ssephe  if (i1->r_offset == i2->r_offset)
570307245Ssephe    return 0;
571307200Ssephe  else
572307200Ssephe    return i1->r_offset < i2->r_offset ? -1 : 1;
573307200Ssephe}
574307200Ssephe
575307200Ssephe#define M6811_OP_LDX_IMMEDIATE (0xCE)
576307200Ssephe
577307199Ssephestatic void
578307200Ssephem68hc11_relax_group (bfd *abfd, asection *sec, bfd_byte *contents,
579307199Ssephe		     unsigned value, unsigned long offset,
580307200Ssephe		     unsigned long end_group)
581307174Ssephe{
582307181Ssephe  unsigned char code;
583307200Ssephe  unsigned long start_offset;
584307199Ssephe  unsigned long ldx_offset = offset;
585307199Ssephe  unsigned long ldx_size;
586307174Ssephe  int can_delete_ldx;
587308494Ssephe  int relax_ldy = 0;
588250199Sgrehan
589250199Sgrehan  /* First instruction of the relax group must be a
590307200Ssephe     LDX #value or LDY #value.  If this is not the case,
591307200Ssephe     ignore the relax group.  */
592308494Ssephe  code = bfd_get_8 (abfd, contents + offset);
593308494Ssephe  if (code == 0x18)
594308494Ssephe    {
595308494Ssephe      relax_ldy++;
596308494Ssephe      offset++;
597307200Ssephe      code = bfd_get_8 (abfd, contents + offset);
598250199Sgrehan    }
599307206Ssephe  ldx_size = offset - ldx_offset + 3;
600307206Ssephe  offset += 3;
601307200Ssephe  if (code != M6811_OP_LDX_IMMEDIATE || offset >= end_group)
602307206Ssephe    return;
603285236Swhu
604324574Ssephe
605324574Ssephe  /* We can remove the LDX/LDY only when all bset/brclr instructions
606324574Ssephe     of the relax group have been converted to use direct addressing
607324574Ssephe     mode.  */
608324574Ssephe  can_delete_ldx = 1;
609307202Ssephe  while (offset < end_group)
610307202Ssephe    {
611307202Ssephe      unsigned isize;
612307206Ssephe      unsigned new_value;
613307206Ssephe      int bset_use_y;
614307206Ssephe
615307200Ssephe      bset_use_y = 0;
616307202Ssephe      start_offset = offset;
617307202Ssephe      code = bfd_get_8 (abfd, contents + offset);
618307202Ssephe      if (code == 0x18)
619307202Ssephe	{
620307206Ssephe	  bset_use_y++;
621307206Ssephe	  offset++;
622307206Ssephe	  code = bfd_get_8 (abfd, contents + offset);
623307202Ssephe	}
624250199Sgrehan
625250199Sgrehan      /* Check the instruction and translate to use direct addressing mode.  */
626307164Ssephe      switch (code)
627250199Sgrehan	{
628307206Ssephe	  /* bset */
629307206Ssephe	case 0x1C:
630307206Ssephe	  code = 0x14;
631250199Sgrehan	  isize = 3;
632307206Ssephe	  break;
633307206Ssephe
634307206Ssephe	  /* brclr */
635307206Ssephe	case 0x1F:
636307206Ssephe	  code = 0x13;
637307206Ssephe	  isize = 4;
638307206Ssephe	  break;
639307206Ssephe
640307206Ssephe	  /* brset */
641307206Ssephe	case 0x1E:
642307206Ssephe	  code = 0x12;
643310757Ssephe	  isize = 4;
644310757Ssephe	  break;
645307206Ssephe
646310757Ssephe	  /* bclr */
647307206Ssephe	case 0x1D:
648250199Sgrehan	  code = 0x15;
649250199Sgrehan	  isize = 3;
650307250Ssephe	  break;
651307250Ssephe
652250199Sgrehan	  /* This instruction is not recognized and we are not
653307250Ssephe	     at end of the relax group.  Ignore and don't remove
654307250Ssephe	     the first LDX (we don't know what it is used for...).  */
655307206Ssephe	default:
656307206Ssephe	  return;
657250199Sgrehan	}
658250199Sgrehan      new_value = (unsigned) bfd_get_8 (abfd, contents + offset + 1);
659307185Ssephe      new_value += value;
660308504Ssephe      if ((new_value & 0xff00) == 0 && bset_use_y == relax_ldy)
661307174Ssephe	{
662307167Ssephe	  bfd_put_8 (abfd, code, contents + offset);
663307161Ssephe	  bfd_put_8 (abfd, new_value, contents + offset + 1);
664307164Ssephe	  if (start_offset != offset)
665307167Ssephe	    {
666307161Ssephe	      m68hc11_elf_relax_delete_bytes (abfd, sec, start_offset,
667307161Ssephe					      offset - start_offset);
668307161Ssephe	      end_group--;
669308504Ssephe	    }
670307174Ssephe	}
671307167Ssephe      else
672307161Ssephe	{
673307161Ssephe	  can_delete_ldx = 0;
674307161Ssephe	}
675307161Ssephe      offset = start_offset + isize;
676250199Sgrehan    }
677307206Ssephe  if (can_delete_ldx)
678307206Ssephe    {
679307206Ssephe      /* Remove the move instruction (3 or 4 bytes win).  */
680307206Ssephe      m68hc11_elf_relax_delete_bytes (abfd, sec, ldx_offset, ldx_size);
681307206Ssephe    }
682307206Ssephe}
683307206Ssephe
684307206Ssephe/* This function handles relaxing for the 68HC11.
685307206Ssephe
686307206Ssephe
687307206Ssephe	and somewhat more difficult to support.  */
688307206Ssephe
689307206Ssephestatic bool
690307206Ssephem68hc11_elf_relax_section (bfd *abfd, asection *sec,
691307206Ssephe			   struct bfd_link_info *link_info, bool *again)
692307206Ssephe{
693307206Ssephe  Elf_Internal_Shdr *symtab_hdr;
694307206Ssephe  Elf_Internal_Rela *internal_relocs;
695307206Ssephe  Elf_Internal_Rela *free_relocs = NULL;
696307206Ssephe  Elf_Internal_Rela *irel, *irelend;
697307206Ssephe  bfd_byte *contents = NULL;
698307206Ssephe  bfd_byte *free_contents = NULL;
699307206Ssephe  Elf32_External_Sym *free_extsyms = NULL;
700307206Ssephe  Elf_Internal_Rela *prev_insn_branch = NULL;
701307206Ssephe  Elf_Internal_Rela *prev_insn_group = NULL;
702307206Ssephe  unsigned insn_group_value = 0;
703307206Ssephe  Elf_Internal_Sym *isymbuf = NULL;
704307206Ssephe
705307206Ssephe  /* Assume nothing changes.  */
706307206Ssephe  *again = false;
707307206Ssephe
708307206Ssephe  /* We don't have to do anything for a relocatable link, if
709307206Ssephe     this section does not have relocs, or if this is not a
710307206Ssephe     code section.  */
711307206Ssephe  if (bfd_link_relocatable (link_info)
712307206Ssephe      || (sec->flags & SEC_RELOC) == 0
713307206Ssephe      || sec->reloc_count == 0
714307206Ssephe      || (sec->flags & SEC_CODE) == 0)
715307206Ssephe    return true;
716307206Ssephe
717307206Ssephe  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
718307206Ssephe
719307206Ssephe  /* Get a copy of the native relocations.  */
720307206Ssephe  internal_relocs = (_bfd_elf_link_read_relocs
721307206Ssephe		     (abfd, sec, NULL, (Elf_Internal_Rela *) NULL,
722307206Ssephe		      link_info->keep_memory));
723307206Ssephe  if (internal_relocs == NULL)
724307206Ssephe    goto error_return;
725307206Ssephe  if (! link_info->keep_memory)
726308504Ssephe    free_relocs = internal_relocs;
727308504Ssephe
728308504Ssephe  /* Checking for branch relaxation relies on the relocations to
729308504Ssephe     be sorted on 'r_offset'.  This is not guaranteed so we must sort.  */
730308504Ssephe  qsort (internal_relocs, sec->reloc_count, sizeof (Elf_Internal_Rela),
731308504Ssephe	 compare_reloc);
732308504Ssephe
733308504Ssephe  /* Walk through them looking for relaxing opportunities.  */
734308504Ssephe  irelend = internal_relocs + sec->reloc_count;
735314123Sdexuan  for (irel = internal_relocs; irel < irelend; irel++)
736314123Sdexuan    {
737314123Sdexuan      bfd_vma symval;
738314123Sdexuan      bfd_vma value;
739314123Sdexuan      Elf_Internal_Sym *isym;
740314123Sdexuan      asection *sym_sec;
741314123Sdexuan      int is_far = 0;
742314123Sdexuan
743314123Sdexuan      /* If this isn't something that can be relaxed, then ignore
744314123Sdexuan	 this reloc.  */
745314123Sdexuan      if (ELF32_R_TYPE (irel->r_info) != (int) R_M68HC11_16
746314123Sdexuan	  && ELF32_R_TYPE (irel->r_info) != (int) R_M68HC11_RL_JUMP
747	  && ELF32_R_TYPE (irel->r_info) != (int) R_M68HC11_RL_GROUP)
748	{
749	  prev_insn_branch = 0;
750	  prev_insn_group = 0;
751	  continue;
752	}
753
754      /* Get the section contents if we haven't done so already.  */
755      if (contents == NULL)
756	{
757	  /* Get cached copy if it exists.  */
758	  if (elf_section_data (sec)->this_hdr.contents != NULL)
759	    contents = elf_section_data (sec)->this_hdr.contents;
760	  else
761	    {
762	      /* Go get them off disk.  */
763	      if (!bfd_malloc_and_get_section (abfd, sec, &contents))
764		goto error_return;
765	    }
766	}
767
768      /* Try to eliminate an unconditional 8 bit pc-relative branch
769	 which immediately follows a conditional 8 bit pc-relative
770	 branch around the unconditional branch.
771
772	    original:		new:
773	    bCC lab1		bCC' lab2
774	    bra lab2
775	   lab1:	       lab1:
776
777	 This happens when the bCC can't reach lab2 at assembly time,
778	 but due to other relaxations it can reach at link time.  */
779      if (ELF32_R_TYPE (irel->r_info) == (int) R_M68HC11_RL_JUMP)
780	{
781	  Elf_Internal_Rela *nrel;
782	  unsigned char code;
783	  unsigned char roffset;
784
785	  prev_insn_branch = 0;
786	  prev_insn_group = 0;
787
788	  /* Do nothing if this reloc is the last byte in the section.  */
789	  if (irel->r_offset + 2 >= sec->size)
790	    continue;
791
792	  /* See if the next instruction is an unconditional pc-relative
793	     branch, more often than not this test will fail, so we
794	     test it first to speed things up.  */
795	  code = bfd_get_8 (abfd, contents + irel->r_offset + 2);
796	  if (code != 0x7e)
797	    continue;
798
799	  /* Also make sure the next relocation applies to the next
800	     instruction and that it's a pc-relative 8 bit branch.  */
801	  nrel = irel + 1;
802	  if (nrel == irelend
803	      || irel->r_offset + 3 != nrel->r_offset
804	      || ELF32_R_TYPE (nrel->r_info) != (int) R_M68HC11_16)
805	    continue;
806
807	  /* Make sure our destination immediately follows the
808	     unconditional branch.  */
809	  roffset = bfd_get_8 (abfd, contents + irel->r_offset + 1);
810	  if (roffset != 3)
811	    continue;
812
813	  prev_insn_branch = irel;
814	  prev_insn_group = 0;
815	  continue;
816	}
817
818      /* Read this BFD's symbols if we haven't done so already.  */
819      if (isymbuf == NULL && symtab_hdr->sh_info != 0)
820	{
821	  isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
822	  if (isymbuf == NULL)
823	    isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
824					    symtab_hdr->sh_info, 0,
825					    NULL, NULL, NULL);
826	  if (isymbuf == NULL)
827	    goto error_return;
828	}
829
830      /* Get the value of the symbol referred to by the reloc.  */
831      if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
832	{
833	  /* A local symbol.  */
834	  isym = isymbuf + ELF32_R_SYM (irel->r_info);
835	  is_far = isym->st_other & STO_M68HC12_FAR;
836	  sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
837	  symval = (isym->st_value
838		    + sym_sec->output_section->vma
839		    + sym_sec->output_offset);
840	}
841      else
842	{
843	  unsigned long indx;
844	  struct elf_link_hash_entry *h;
845
846	  /* An external symbol.  */
847	  indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
848	  h = elf_sym_hashes (abfd)[indx];
849	  BFD_ASSERT (h != NULL);
850	  if (h->root.type != bfd_link_hash_defined
851	      && h->root.type != bfd_link_hash_defweak)
852	    {
853	      /* This appears to be a reference to an undefined
854		 symbol.  Just ignore it--it will be caught by the
855		 regular reloc processing.  */
856	      prev_insn_branch = 0;
857	      prev_insn_group = 0;
858	      continue;
859	    }
860
861	  is_far = h->other & STO_M68HC12_FAR;
862	  isym = 0;
863	  sym_sec = h->root.u.def.section;
864	  symval = (h->root.u.def.value
865		    + sym_sec->output_section->vma
866		    + sym_sec->output_offset);
867	}
868
869      if (ELF32_R_TYPE (irel->r_info) == (int) R_M68HC11_RL_GROUP)
870	{
871	  prev_insn_branch = 0;
872	  prev_insn_group = 0;
873
874	  /* Do nothing if this reloc is the last byte in the section.  */
875	  if (irel->r_offset == sec->size)
876	    continue;
877
878	  prev_insn_group = irel;
879	  insn_group_value = isym->st_value;
880	  continue;
881	}
882
883      /* When we relax some bytes, the size of our section changes.
884	 This affects the layout of next input sections that go in our
885	 output section.  When the symbol is part of another section that
886	 will go in the same output section as the current one, it's
887	 final address may now be incorrect (too far).  We must let the
888	 linker re-compute all section offsets before processing this
889	 reloc.  Code example:
890
891				Initial		    Final
892	 .sect .text		section size = 6    section size = 4
893	 jmp foo
894	 jmp bar
895	 .sect .text.foo_bar	output_offset = 6   output_offset = 4
896	 foo: rts
897	 bar: rts
898
899	 If we process the reloc now, the jmp bar is replaced by a
900	 relative branch to the initial bar address (output_offset 6).  */
901      if (*again && sym_sec != sec
902	  && sym_sec->output_section == sec->output_section)
903	{
904	  prev_insn_group = 0;
905	  prev_insn_branch = 0;
906	  continue;
907	}
908
909      value = symval;
910      /* Try to turn a far branch to a near branch.  */
911      if (ELF32_R_TYPE (irel->r_info) == (int) R_M68HC11_16
912	  && prev_insn_branch)
913	{
914	  bfd_vma offset;
915	  unsigned char code;
916
917	  offset = value - (prev_insn_branch->r_offset
918			    + sec->output_section->vma
919			    + sec->output_offset + 2);
920
921	  /* If the offset is still out of -128..+127 range,
922	     leave that far branch unchanged.  */
923	  if ((offset & 0xff80) != 0 && (offset & 0xff80) != 0xff80)
924	    {
925	      prev_insn_branch = 0;
926	      continue;
927	    }
928
929	  /* Shrink the branch.  */
930	  code = bfd_get_8 (abfd, contents + prev_insn_branch->r_offset);
931	  if (code == 0x7e)
932	    {
933	      code = 0x20;
934	      bfd_put_8 (abfd, code, contents + prev_insn_branch->r_offset);
935	      bfd_put_8 (abfd, 0xff,
936			 contents + prev_insn_branch->r_offset + 1);
937	      irel->r_offset = prev_insn_branch->r_offset + 1;
938	      irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
939					   R_M68HC11_PCREL_8);
940	      m68hc11_elf_relax_delete_bytes (abfd, sec,
941					      irel->r_offset + 1, 1);
942	    }
943	  else
944	    {
945	      code ^= 0x1;
946	      bfd_put_8 (abfd, code, contents + prev_insn_branch->r_offset);
947	      bfd_put_8 (abfd, 0xff,
948			 contents + prev_insn_branch->r_offset + 1);
949	      irel->r_offset = prev_insn_branch->r_offset + 1;
950	      irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
951					   R_M68HC11_PCREL_8);
952	      m68hc11_elf_relax_delete_bytes (abfd, sec,
953					      irel->r_offset + 1, 3);
954	    }
955	  prev_insn_branch = 0;
956	  *again = true;
957	}
958
959      /* Try to turn a 16 bit address into a 8 bit page0 address.  */
960      else if (ELF32_R_TYPE (irel->r_info) == (int) R_M68HC11_16
961	       && (value & 0xff00) == 0)
962	{
963	  unsigned char code;
964	  unsigned short offset;
965	  const struct m68hc11_direct_relax *rinfo;
966
967	  prev_insn_branch = 0;
968	  offset = bfd_get_16 (abfd, contents + irel->r_offset);
969	  offset += value;
970	  if ((offset & 0xff00) != 0)
971	    {
972	      prev_insn_group = 0;
973	      continue;
974	    }
975
976	  if (prev_insn_group)
977	    {
978	      unsigned long old_sec_size = sec->size;
979
980	      /* Note that we've changed the relocation contents, etc.  */
981	      elf_section_data (sec)->relocs = internal_relocs;
982	      free_relocs = NULL;
983
984	      elf_section_data (sec)->this_hdr.contents = contents;
985	      free_contents = NULL;
986
987	      symtab_hdr->contents = (bfd_byte *) isymbuf;
988	      free_extsyms = NULL;
989
990	      m68hc11_relax_group (abfd, sec, contents, offset,
991				   prev_insn_group->r_offset,
992				   insn_group_value);
993	      irel = prev_insn_group;
994	      prev_insn_group = 0;
995	      irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
996					   R_M68HC11_NONE);
997	      if (sec->size != old_sec_size)
998		*again = true;
999	      continue;
1000	    }
1001
1002	  /* Get the opcode.  */
1003	  code = bfd_get_8 (abfd, contents + irel->r_offset - 1);
1004	  rinfo = find_relaxable_insn (code);
1005	  if (rinfo == 0)
1006	    {
1007	      prev_insn_group = 0;
1008	      continue;
1009	    }
1010
1011	  /* Note that we've changed the relocation contents, etc.  */
1012	  elf_section_data (sec)->relocs = internal_relocs;
1013	  free_relocs = NULL;
1014
1015	  elf_section_data (sec)->this_hdr.contents = contents;
1016	  free_contents = NULL;
1017
1018	  symtab_hdr->contents = (bfd_byte *) isymbuf;
1019	  free_extsyms = NULL;
1020
1021	  /* Fix the opcode.  */
1022	  /* printf ("A relaxable case : 0x%02x (%s)\n",
1023	     code, rinfo->name); */
1024	  bfd_put_8 (abfd, rinfo->direct_code,
1025		     contents + irel->r_offset - 1);
1026
1027	  /* Delete one byte of data (upper byte of address).  */
1028	  m68hc11_elf_relax_delete_bytes (abfd, sec, irel->r_offset, 1);
1029
1030	  /* Fix the relocation's type.  */
1031	  irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
1032				       R_M68HC11_8);
1033
1034	  /* That will change things, so, we should relax again.  */
1035	  *again = true;
1036	}
1037      else if (ELF32_R_TYPE (irel->r_info) == R_M68HC11_16 && !is_far)
1038	{
1039	  unsigned char code;
1040	  bfd_vma offset;
1041
1042	  prev_insn_branch = 0;
1043	  code = bfd_get_8 (abfd, contents + irel->r_offset - 1);
1044	  if (code == 0x7e || code == 0xbd)
1045	    {
1046	      offset = value - (irel->r_offset
1047				+ sec->output_section->vma
1048				+ sec->output_offset + 1);
1049	      offset += bfd_get_16 (abfd, contents + irel->r_offset);
1050
1051	      /* If the offset is still out of -128..+127 range,
1052		 leave that far branch unchanged.  */
1053	      if ((offset & 0xff80) == 0 || (offset & 0xff80) == 0xff80)
1054		{
1055
1056		  /* Note that we've changed the relocation contents, etc.  */
1057		  elf_section_data (sec)->relocs = internal_relocs;
1058		  free_relocs = NULL;
1059
1060		  elf_section_data (sec)->this_hdr.contents = contents;
1061		  free_contents = NULL;
1062
1063		  symtab_hdr->contents = (bfd_byte *) isymbuf;
1064		  free_extsyms = NULL;
1065
1066		  /* Shrink the branch.  */
1067		  code = (code == 0x7e) ? 0x20 : 0x8d;
1068		  bfd_put_8 (abfd, code,
1069			     contents + irel->r_offset - 1);
1070		  bfd_put_8 (abfd, 0xff,
1071			     contents + irel->r_offset);
1072		  irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
1073					       R_M68HC11_PCREL_8);
1074		  m68hc11_elf_relax_delete_bytes (abfd, sec,
1075						  irel->r_offset + 1, 1);
1076		  /* That will change things, so, we should relax again.  */
1077		  *again = true;
1078		}
1079	    }
1080	}
1081      prev_insn_branch = 0;
1082      prev_insn_group = 0;
1083    }
1084
1085  free (free_relocs);
1086  free_relocs = NULL;
1087
1088  if (free_contents != NULL)
1089    {
1090      if (! link_info->keep_memory)
1091	free (free_contents);
1092      else
1093	{
1094	  /* Cache the section contents for elf_link_input_bfd.  */
1095	  elf_section_data (sec)->this_hdr.contents = contents;
1096	}
1097      free_contents = NULL;
1098    }
1099
1100  if (free_extsyms != NULL)
1101    {
1102      if (! link_info->keep_memory)
1103	free (free_extsyms);
1104      else
1105	{
1106	  /* Cache the symbols for elf_link_input_bfd.  */
1107	  symtab_hdr->contents = (unsigned char *) isymbuf;
1108	}
1109      free_extsyms = NULL;
1110    }
1111
1112  return true;
1113
1114 error_return:
1115  free (free_relocs);
1116  free (free_contents);
1117  free (free_extsyms);
1118  return false;
1119}
1120
1121/* Delete some bytes from a section while relaxing.  */
1122
1123static void
1124m68hc11_elf_relax_delete_bytes (bfd *abfd, asection *sec,
1125				bfd_vma addr, int count)
1126{
1127  Elf_Internal_Shdr *symtab_hdr;
1128  unsigned int sec_shndx;
1129  bfd_byte *contents;
1130  Elf_Internal_Rela *irel, *irelend;
1131  bfd_vma toaddr;
1132  Elf_Internal_Sym *isymbuf, *isym, *isymend;
1133  struct elf_link_hash_entry **sym_hashes;
1134  struct elf_link_hash_entry **end_hashes;
1135  unsigned int symcount;
1136
1137  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
1138  isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
1139
1140  sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
1141
1142  contents = elf_section_data (sec)->this_hdr.contents;
1143
1144  toaddr = sec->size;
1145
1146  irel = elf_section_data (sec)->relocs;
1147  irelend = irel + sec->reloc_count;
1148
1149  /* Actually delete the bytes.  */
1150  memmove (contents + addr, contents + addr + count,
1151	   (size_t) (toaddr - addr - count));
1152
1153  sec->size -= count;
1154
1155  /* Adjust all the relocs.  */
1156  for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++)
1157    {
1158      unsigned char code;
1159      unsigned char offset;
1160      unsigned short raddr;
1161      unsigned long old_offset;
1162      int branch_pos;
1163
1164      old_offset = irel->r_offset;
1165
1166      /* See if this reloc was for the bytes we have deleted, in which
1167	 case we no longer care about it.  Don't delete relocs which
1168	 represent addresses, though.  */
1169      if (ELF32_R_TYPE (irel->r_info) != R_M68HC11_RL_JUMP
1170	  && irel->r_offset >= addr && irel->r_offset < addr + count)
1171	irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
1172				     R_M68HC11_NONE);
1173
1174      if (ELF32_R_TYPE (irel->r_info) == R_M68HC11_NONE)
1175	continue;
1176
1177      /* Get the new reloc address.  */
1178      if ((irel->r_offset > addr
1179	   && irel->r_offset < toaddr))
1180	irel->r_offset -= count;
1181
1182      /* If this is a PC relative reloc, see if the range it covers
1183	 includes the bytes we have deleted.  */
1184      switch (ELF32_R_TYPE (irel->r_info))
1185	{
1186	default:
1187	  break;
1188
1189	case R_M68HC11_RL_JUMP:
1190	  code = bfd_get_8 (abfd, contents + irel->r_offset);
1191	  switch (code)
1192	    {
1193	      /* jsr and jmp instruction are also marked with RL_JUMP
1194		 relocs but no adjustment must be made.  */
1195	    case 0x7e:
1196	    case 0x9d:
1197	    case 0xbd:
1198	      continue;
1199
1200	    case 0x12:
1201	    case 0x13:
1202	      branch_pos = 3;
1203	      raddr = 4;
1204
1205	      /* Special case when we translate a brclr N,y into brclr *<addr>
1206		 In this case, the 0x18 page2 prefix is removed.
1207		 The reloc offset is not modified but the instruction
1208		 size is reduced by 1.  */
1209	      if (old_offset == addr)
1210		raddr++;
1211	      break;
1212
1213	    case 0x1e:
1214	    case 0x1f:
1215	      branch_pos = 3;
1216	      raddr = 4;
1217	      break;
1218
1219	    case 0x18:
1220	      branch_pos = 4;
1221	      raddr = 5;
1222	      break;
1223
1224	    default:
1225	      branch_pos = 1;
1226	      raddr = 2;
1227	      break;
1228	    }
1229	  offset = bfd_get_8 (abfd, contents + irel->r_offset + branch_pos);
1230	  raddr += old_offset;
1231	  raddr += ((unsigned short) offset | ((offset & 0x80) ? 0xff00 : 0));
1232	  if (irel->r_offset < addr && raddr > addr)
1233	    {
1234	      offset -= count;
1235	      bfd_put_8 (abfd, offset, contents + irel->r_offset + branch_pos);
1236	    }
1237	  else if (irel->r_offset >= addr && raddr <= addr)
1238	    {
1239	      offset += count;
1240	      bfd_put_8 (abfd, offset, contents + irel->r_offset + branch_pos);
1241	    }
1242	  else
1243	    {
1244	      /*printf ("Not adjusted 0x%04x [0x%4x 0x%4x]\n", raddr,
1245		irel->r_offset, addr);*/
1246	    }
1247
1248	  break;
1249	}
1250    }
1251
1252  /* Adjust the local symbols defined in this section.  */
1253  isymend = isymbuf + symtab_hdr->sh_info;
1254  for (isym = isymbuf; isym < isymend; isym++)
1255    {
1256      if (isym->st_shndx == sec_shndx
1257	  && isym->st_value > addr
1258	  && isym->st_value <= toaddr)
1259	isym->st_value -= count;
1260    }
1261
1262  /* Now adjust the global symbols defined in this section.  */
1263  symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
1264	      - symtab_hdr->sh_info);
1265  sym_hashes = elf_sym_hashes (abfd);
1266  end_hashes = sym_hashes + symcount;
1267  for (; sym_hashes < end_hashes; sym_hashes++)
1268    {
1269      struct elf_link_hash_entry *sym_hash = *sym_hashes;
1270      if ((sym_hash->root.type == bfd_link_hash_defined
1271	   || sym_hash->root.type == bfd_link_hash_defweak)
1272	  && sym_hash->root.u.def.section == sec
1273	  && sym_hash->root.u.def.value > addr
1274	  && sym_hash->root.u.def.value <= toaddr)
1275	{
1276	  sym_hash->root.u.def.value -= count;
1277	}
1278    }
1279}
1280
1281/* Specific sections:
1282   - The .page0 is a data section that is mapped in [0x0000..0x00FF].
1283     Page0 accesses are faster on the M68HC11. Soft registers used by GCC-m6811
1284     are located in .page0.
1285   - The .vectors is the section that represents the interrupt
1286     vectors.  */
1287static const struct bfd_elf_special_section elf32_m68hc11_special_sections[] =
1288{
1289  { STRING_COMMA_LEN (".eeprom"),   0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
1290  { STRING_COMMA_LEN (".page0"),    0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
1291  { STRING_COMMA_LEN (".softregs"), 0, SHT_NOBITS,   SHF_ALLOC + SHF_WRITE },
1292  { STRING_COMMA_LEN (".vectors"),  0, SHT_PROGBITS, SHF_ALLOC },
1293  { NULL,			0,  0, 0,	     0 }
1294};
1295
1296#define ELF_ARCH		bfd_arch_m68hc11
1297#define ELF_TARGET_ID		M68HC11_ELF_DATA
1298#define ELF_MACHINE_CODE	EM_68HC11
1299#define ELF_MAXPAGESIZE		0x1000
1300
1301#define TARGET_BIG_SYM		m68hc11_elf32_vec
1302#define TARGET_BIG_NAME		"elf32-m68hc11"
1303
1304#define elf_info_to_howto	NULL
1305#define elf_info_to_howto_rel	m68hc11_info_to_howto_rel
1306#define bfd_elf32_bfd_relax_section  m68hc11_elf_relax_section
1307#define elf_backend_check_relocs     elf32_m68hc11_check_relocs
1308#define elf_backend_relocate_section elf32_m68hc11_relocate_section
1309#define elf_backend_add_symbol_hook  elf32_m68hc11_add_symbol_hook
1310#define elf_backend_object_p	0
1311#define elf_backend_can_gc_sections		1
1312#define elf_backend_special_sections  elf32_m68hc11_special_sections
1313#define elf_backend_merge_symbol_attribute elf32_m68hc11_merge_symbol_attribute
1314
1315#define bfd_elf32_bfd_link_hash_table_create \
1316				m68hc11_elf_bfd_link_hash_table_create
1317#define bfd_elf32_bfd_merge_private_bfd_data \
1318					_bfd_m68hc11_elf_merge_private_bfd_data
1319#define bfd_elf32_bfd_set_private_flags	_bfd_m68hc11_elf_set_private_flags
1320#define bfd_elf32_bfd_print_private_bfd_data \
1321					_bfd_m68hc11_elf_print_private_bfd_data
1322
1323#include "elf32-target.h"
1324