1d2201f2fSdrahn /* Motorola 68HC11/HC12-specific support for 32-bit ELF
2*cf2f2c56Smiod    Copyright 1999, 2000, 2001, 2002, 2003, 2004
3*cf2f2c56Smiod    Free Software Foundation, Inc.
4d2201f2fSdrahn    Contributed by Stephane Carrez (stcarrez@nerim.fr)
5d2201f2fSdrahn 
6d2201f2fSdrahn This file is part of BFD, the Binary File Descriptor library.
7d2201f2fSdrahn 
8d2201f2fSdrahn This program is free software; you can redistribute it and/or modify
9d2201f2fSdrahn it under the terms of the GNU General Public License as published by
10d2201f2fSdrahn the Free Software Foundation; either version 2 of the License, or
11d2201f2fSdrahn (at your option) any later version.
12d2201f2fSdrahn 
13d2201f2fSdrahn This program is distributed in the hope that it will be useful,
14d2201f2fSdrahn but WITHOUT ANY WARRANTY; without even the implied warranty of
15d2201f2fSdrahn MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16d2201f2fSdrahn GNU General Public License for more details.
17d2201f2fSdrahn 
18d2201f2fSdrahn You should have received a copy of the GNU General Public License
19d2201f2fSdrahn along with this program; if not, write to the Free Software
20d2201f2fSdrahn Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
21d2201f2fSdrahn 
22d2201f2fSdrahn #include "bfd.h"
23d2201f2fSdrahn #include "sysdep.h"
24d2201f2fSdrahn #include "bfdlink.h"
25d2201f2fSdrahn #include "libbfd.h"
26d2201f2fSdrahn #include "elf-bfd.h"
27d2201f2fSdrahn #include "elf32-m68hc1x.h"
28d2201f2fSdrahn #include "elf/m68hc11.h"
29d2201f2fSdrahn #include "opcode/m68hc11.h"
30d2201f2fSdrahn 
31d2201f2fSdrahn 
32d2201f2fSdrahn #define m68hc12_stub_hash_lookup(table, string, create, copy) \
33d2201f2fSdrahn   ((struct elf32_m68hc11_stub_hash_entry *) \
34d2201f2fSdrahn    bfd_hash_lookup ((table), (string), (create), (copy)))
35d2201f2fSdrahn 
36d2201f2fSdrahn static struct elf32_m68hc11_stub_hash_entry* m68hc12_add_stub
37*cf2f2c56Smiod   (const char *stub_name,
38d2201f2fSdrahn    asection *section,
39*cf2f2c56Smiod    struct m68hc11_elf_link_hash_table *htab);
40d2201f2fSdrahn 
41d2201f2fSdrahn static struct bfd_hash_entry *stub_hash_newfunc
42*cf2f2c56Smiod   (struct bfd_hash_entry *, struct bfd_hash_table *, const char *);
43d2201f2fSdrahn 
44*cf2f2c56Smiod static void m68hc11_elf_set_symbol (bfd* abfd, struct bfd_link_info *info,
45*cf2f2c56Smiod                                     const char* name, bfd_vma value,
46*cf2f2c56Smiod                                     asection* sec);
47d2201f2fSdrahn 
48d2201f2fSdrahn static bfd_boolean m68hc11_elf_export_one_stub
49*cf2f2c56Smiod   (struct bfd_hash_entry *gen_entry, void *in_arg);
50d2201f2fSdrahn 
51*cf2f2c56Smiod static void scan_sections_for_abi (bfd*, asection*, PTR);
52d2201f2fSdrahn 
53d2201f2fSdrahn struct m68hc11_scan_param
54d2201f2fSdrahn {
55d2201f2fSdrahn    struct m68hc11_page_info* pinfo;
56d2201f2fSdrahn    bfd_boolean use_memory_banks;
57d2201f2fSdrahn };
58d2201f2fSdrahn 
59d2201f2fSdrahn 
60d2201f2fSdrahn /* Create a 68HC11/68HC12 ELF linker hash table.  */
61d2201f2fSdrahn 
62d2201f2fSdrahn struct m68hc11_elf_link_hash_table*
m68hc11_elf_hash_table_create(bfd * abfd)63*cf2f2c56Smiod m68hc11_elf_hash_table_create (bfd *abfd)
64d2201f2fSdrahn {
65d2201f2fSdrahn   struct m68hc11_elf_link_hash_table *ret;
66d2201f2fSdrahn   bfd_size_type amt = sizeof (struct m68hc11_elf_link_hash_table);
67d2201f2fSdrahn 
68d2201f2fSdrahn   ret = (struct m68hc11_elf_link_hash_table *) bfd_malloc (amt);
69d2201f2fSdrahn   if (ret == (struct m68hc11_elf_link_hash_table *) NULL)
70d2201f2fSdrahn     return NULL;
71d2201f2fSdrahn 
72d2201f2fSdrahn   memset (ret, 0, amt);
73d2201f2fSdrahn   if (! _bfd_elf_link_hash_table_init (&ret->root, abfd,
74d2201f2fSdrahn 				       _bfd_elf_link_hash_newfunc))
75d2201f2fSdrahn     {
76d2201f2fSdrahn       free (ret);
77d2201f2fSdrahn       return NULL;
78d2201f2fSdrahn     }
79d2201f2fSdrahn 
80d2201f2fSdrahn   /* Init the stub hash table too.  */
81d2201f2fSdrahn   amt = sizeof (struct bfd_hash_table);
82d2201f2fSdrahn   ret->stub_hash_table = (struct bfd_hash_table*) bfd_malloc (amt);
83d2201f2fSdrahn   if (ret->stub_hash_table == NULL)
84d2201f2fSdrahn     {
85d2201f2fSdrahn       free (ret);
86d2201f2fSdrahn       return NULL;
87d2201f2fSdrahn     }
88d2201f2fSdrahn   if (!bfd_hash_table_init (ret->stub_hash_table, stub_hash_newfunc))
89d2201f2fSdrahn     return NULL;
90d2201f2fSdrahn 
91d2201f2fSdrahn   ret->stub_bfd = NULL;
92d2201f2fSdrahn   ret->stub_section = 0;
93d2201f2fSdrahn   ret->add_stub_section = NULL;
94d2201f2fSdrahn   ret->sym_sec.abfd = NULL;
95d2201f2fSdrahn 
96d2201f2fSdrahn   return ret;
97d2201f2fSdrahn }
98d2201f2fSdrahn 
99d2201f2fSdrahn /* Free the derived linker hash table.  */
100d2201f2fSdrahn 
101d2201f2fSdrahn void
m68hc11_elf_bfd_link_hash_table_free(struct bfd_link_hash_table * hash)102*cf2f2c56Smiod m68hc11_elf_bfd_link_hash_table_free (struct bfd_link_hash_table *hash)
103d2201f2fSdrahn {
104d2201f2fSdrahn   struct m68hc11_elf_link_hash_table *ret
105d2201f2fSdrahn     = (struct m68hc11_elf_link_hash_table *) hash;
106d2201f2fSdrahn 
107d2201f2fSdrahn   bfd_hash_table_free (ret->stub_hash_table);
108d2201f2fSdrahn   free (ret->stub_hash_table);
109d2201f2fSdrahn   _bfd_generic_link_hash_table_free (hash);
110d2201f2fSdrahn }
111d2201f2fSdrahn 
112d2201f2fSdrahn /* Assorted hash table functions.  */
113d2201f2fSdrahn 
114d2201f2fSdrahn /* Initialize an entry in the stub hash table.  */
115d2201f2fSdrahn 
116d2201f2fSdrahn static struct bfd_hash_entry *
stub_hash_newfunc(struct bfd_hash_entry * entry,struct bfd_hash_table * table,const char * string)117*cf2f2c56Smiod stub_hash_newfunc (struct bfd_hash_entry *entry, struct bfd_hash_table *table,
118*cf2f2c56Smiod                    const char *string)
119d2201f2fSdrahn {
120d2201f2fSdrahn   /* Allocate the structure if it has not already been allocated by a
121d2201f2fSdrahn      subclass.  */
122d2201f2fSdrahn   if (entry == NULL)
123d2201f2fSdrahn     {
124d2201f2fSdrahn       entry = bfd_hash_allocate (table,
125d2201f2fSdrahn 				 sizeof (struct elf32_m68hc11_stub_hash_entry));
126d2201f2fSdrahn       if (entry == NULL)
127d2201f2fSdrahn 	return entry;
128d2201f2fSdrahn     }
129d2201f2fSdrahn 
130d2201f2fSdrahn   /* Call the allocation method of the superclass.  */
131d2201f2fSdrahn   entry = bfd_hash_newfunc (entry, table, string);
132d2201f2fSdrahn   if (entry != NULL)
133d2201f2fSdrahn     {
134d2201f2fSdrahn       struct elf32_m68hc11_stub_hash_entry *eh;
135d2201f2fSdrahn 
136d2201f2fSdrahn       /* Initialize the local fields.  */
137d2201f2fSdrahn       eh = (struct elf32_m68hc11_stub_hash_entry *) entry;
138d2201f2fSdrahn       eh->stub_sec = NULL;
139d2201f2fSdrahn       eh->stub_offset = 0;
140d2201f2fSdrahn       eh->target_value = 0;
141d2201f2fSdrahn       eh->target_section = NULL;
142d2201f2fSdrahn     }
143d2201f2fSdrahn 
144d2201f2fSdrahn   return entry;
145d2201f2fSdrahn }
146d2201f2fSdrahn 
147d2201f2fSdrahn /* Add a new stub entry to the stub hash.  Not all fields of the new
148d2201f2fSdrahn    stub entry are initialised.  */
149d2201f2fSdrahn 
150d2201f2fSdrahn static struct elf32_m68hc11_stub_hash_entry *
m68hc12_add_stub(const char * stub_name,asection * section,struct m68hc11_elf_link_hash_table * htab)151*cf2f2c56Smiod m68hc12_add_stub (const char *stub_name, asection *section,
152*cf2f2c56Smiod                   struct m68hc11_elf_link_hash_table *htab)
153d2201f2fSdrahn {
154d2201f2fSdrahn   struct elf32_m68hc11_stub_hash_entry *stub_entry;
155d2201f2fSdrahn 
156d2201f2fSdrahn   /* Enter this entry into the linker stub hash table.  */
157d2201f2fSdrahn   stub_entry = m68hc12_stub_hash_lookup (htab->stub_hash_table, stub_name,
158d2201f2fSdrahn                                          TRUE, FALSE);
159d2201f2fSdrahn   if (stub_entry == NULL)
160d2201f2fSdrahn     {
161d2201f2fSdrahn       (*_bfd_error_handler) (_("%s: cannot create stub entry %s"),
162d2201f2fSdrahn 			     bfd_archive_filename (section->owner),
163d2201f2fSdrahn 			     stub_name);
164d2201f2fSdrahn       return NULL;
165d2201f2fSdrahn     }
166d2201f2fSdrahn 
167d2201f2fSdrahn   if (htab->stub_section == 0)
168d2201f2fSdrahn     {
169d2201f2fSdrahn       htab->stub_section = (*htab->add_stub_section) (".tramp",
170d2201f2fSdrahn                                                       htab->tramp_section);
171d2201f2fSdrahn     }
172d2201f2fSdrahn 
173d2201f2fSdrahn   stub_entry->stub_sec = htab->stub_section;
174d2201f2fSdrahn   stub_entry->stub_offset = 0;
175d2201f2fSdrahn   return stub_entry;
176d2201f2fSdrahn }
177d2201f2fSdrahn 
178d2201f2fSdrahn /* Hook called by the linker routine which adds symbols from an object
179d2201f2fSdrahn    file.  We use it for identify far symbols and force a loading of
180d2201f2fSdrahn    the trampoline handler.  */
181d2201f2fSdrahn 
182d2201f2fSdrahn bfd_boolean
elf32_m68hc11_add_symbol_hook(bfd * abfd,struct bfd_link_info * info,Elf_Internal_Sym * sym,const char ** namep ATTRIBUTE_UNUSED,flagword * flagsp ATTRIBUTE_UNUSED,asection ** secp ATTRIBUTE_UNUSED,bfd_vma * valp ATTRIBUTE_UNUSED)183*cf2f2c56Smiod elf32_m68hc11_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
184*cf2f2c56Smiod                                Elf_Internal_Sym *sym,
185*cf2f2c56Smiod                                const char **namep ATTRIBUTE_UNUSED,
186*cf2f2c56Smiod                                flagword *flagsp ATTRIBUTE_UNUSED,
187*cf2f2c56Smiod                                asection **secp ATTRIBUTE_UNUSED,
188*cf2f2c56Smiod                                bfd_vma *valp ATTRIBUTE_UNUSED)
189d2201f2fSdrahn {
190d2201f2fSdrahn   if (sym->st_other & STO_M68HC12_FAR)
191d2201f2fSdrahn     {
192d2201f2fSdrahn       struct elf_link_hash_entry *h;
193d2201f2fSdrahn 
194d2201f2fSdrahn       h = (struct elf_link_hash_entry *)
195d2201f2fSdrahn 	bfd_link_hash_lookup (info->hash, "__far_trampoline",
196d2201f2fSdrahn                               FALSE, FALSE, FALSE);
197d2201f2fSdrahn       if (h == NULL)
198d2201f2fSdrahn         {
199d2201f2fSdrahn           struct bfd_link_hash_entry* entry = NULL;
200d2201f2fSdrahn 
201d2201f2fSdrahn           _bfd_generic_link_add_one_symbol (info, abfd,
202d2201f2fSdrahn                                             "__far_trampoline",
203d2201f2fSdrahn                                             BSF_GLOBAL,
204d2201f2fSdrahn                                             bfd_und_section_ptr,
205d2201f2fSdrahn                                             (bfd_vma) 0, (const char*) NULL,
206d2201f2fSdrahn                                             FALSE, FALSE, &entry);
207d2201f2fSdrahn         }
208d2201f2fSdrahn 
209d2201f2fSdrahn     }
210d2201f2fSdrahn   return TRUE;
211d2201f2fSdrahn }
212d2201f2fSdrahn 
213d2201f2fSdrahn /* External entry points for sizing and building linker stubs.  */
214d2201f2fSdrahn 
215d2201f2fSdrahn /* Set up various things so that we can make a list of input sections
216d2201f2fSdrahn    for each output section included in the link.  Returns -1 on error,
217d2201f2fSdrahn    0 when no stubs will be needed, and 1 on success.  */
218d2201f2fSdrahn 
219d2201f2fSdrahn int
elf32_m68hc11_setup_section_lists(bfd * output_bfd,struct bfd_link_info * info)220*cf2f2c56Smiod elf32_m68hc11_setup_section_lists (bfd *output_bfd, struct bfd_link_info *info)
221d2201f2fSdrahn {
222d2201f2fSdrahn   bfd *input_bfd;
223d2201f2fSdrahn   unsigned int bfd_count;
224d2201f2fSdrahn   int top_id, top_index;
225d2201f2fSdrahn   asection *section;
226d2201f2fSdrahn   asection **input_list, **list;
227d2201f2fSdrahn   bfd_size_type amt;
228d2201f2fSdrahn   asection *text_section;
229d2201f2fSdrahn   struct m68hc11_elf_link_hash_table *htab;
230d2201f2fSdrahn 
231d2201f2fSdrahn   htab = m68hc11_elf_hash_table (info);
232d2201f2fSdrahn 
233d2201f2fSdrahn   if (htab->root.root.creator->flavour != bfd_target_elf_flavour)
234d2201f2fSdrahn     return 0;
235d2201f2fSdrahn 
236d2201f2fSdrahn   /* Count the number of input BFDs and find the top input section id.
237d2201f2fSdrahn      Also search for an existing ".tramp" section so that we know
238d2201f2fSdrahn      where generated trampolines must go.  Default to ".text" if we
239d2201f2fSdrahn      can't find it.  */
240d2201f2fSdrahn   htab->tramp_section = 0;
241d2201f2fSdrahn   text_section = 0;
242d2201f2fSdrahn   for (input_bfd = info->input_bfds, bfd_count = 0, top_id = 0;
243d2201f2fSdrahn        input_bfd != NULL;
244d2201f2fSdrahn        input_bfd = input_bfd->link_next)
245d2201f2fSdrahn     {
246d2201f2fSdrahn       bfd_count += 1;
247d2201f2fSdrahn       for (section = input_bfd->sections;
248d2201f2fSdrahn 	   section != NULL;
249d2201f2fSdrahn 	   section = section->next)
250d2201f2fSdrahn 	{
251d2201f2fSdrahn           const char* name = bfd_get_section_name (input_bfd, section);
252d2201f2fSdrahn 
253d2201f2fSdrahn           if (!strcmp (name, ".tramp"))
254d2201f2fSdrahn             htab->tramp_section = section;
255d2201f2fSdrahn 
256d2201f2fSdrahn           if (!strcmp (name, ".text"))
257d2201f2fSdrahn             text_section = section;
258d2201f2fSdrahn 
259d2201f2fSdrahn 	  if (top_id < section->id)
260d2201f2fSdrahn 	    top_id = section->id;
261d2201f2fSdrahn 	}
262d2201f2fSdrahn     }
263d2201f2fSdrahn   htab->bfd_count = bfd_count;
264d2201f2fSdrahn   if (htab->tramp_section == 0)
265d2201f2fSdrahn     htab->tramp_section = text_section;
266d2201f2fSdrahn 
267d2201f2fSdrahn   /* We can't use output_bfd->section_count here to find the top output
268d2201f2fSdrahn      section index as some sections may have been removed, and
269d2201f2fSdrahn      _bfd_strip_section_from_output doesn't renumber the indices.  */
270d2201f2fSdrahn   for (section = output_bfd->sections, top_index = 0;
271d2201f2fSdrahn        section != NULL;
272d2201f2fSdrahn        section = section->next)
273d2201f2fSdrahn     {
274d2201f2fSdrahn       if (top_index < section->index)
275d2201f2fSdrahn 	top_index = section->index;
276d2201f2fSdrahn     }
277d2201f2fSdrahn 
278d2201f2fSdrahn   htab->top_index = top_index;
279d2201f2fSdrahn   amt = sizeof (asection *) * (top_index + 1);
280d2201f2fSdrahn   input_list = (asection **) bfd_malloc (amt);
281d2201f2fSdrahn   htab->input_list = input_list;
282d2201f2fSdrahn   if (input_list == NULL)
283d2201f2fSdrahn     return -1;
284d2201f2fSdrahn 
285d2201f2fSdrahn   /* For sections we aren't interested in, mark their entries with a
286d2201f2fSdrahn      value we can check later.  */
287d2201f2fSdrahn   list = input_list + top_index;
288d2201f2fSdrahn   do
289d2201f2fSdrahn     *list = bfd_abs_section_ptr;
290d2201f2fSdrahn   while (list-- != input_list);
291d2201f2fSdrahn 
292d2201f2fSdrahn   for (section = output_bfd->sections;
293d2201f2fSdrahn        section != NULL;
294d2201f2fSdrahn        section = section->next)
295d2201f2fSdrahn     {
296d2201f2fSdrahn       if ((section->flags & SEC_CODE) != 0)
297d2201f2fSdrahn 	input_list[section->index] = NULL;
298d2201f2fSdrahn     }
299d2201f2fSdrahn 
300d2201f2fSdrahn   return 1;
301d2201f2fSdrahn }
302d2201f2fSdrahn 
303d2201f2fSdrahn /* Determine and set the size of the stub section for a final link.
304d2201f2fSdrahn 
305d2201f2fSdrahn    The basic idea here is to examine all the relocations looking for
306d2201f2fSdrahn    PC-relative calls to a target that is unreachable with a "bl"
307d2201f2fSdrahn    instruction.  */
308d2201f2fSdrahn 
309d2201f2fSdrahn bfd_boolean
elf32_m68hc11_size_stubs(bfd * output_bfd,bfd * stub_bfd,struct bfd_link_info * info,asection * (* add_stub_section)(const char *,asection *))310*cf2f2c56Smiod elf32_m68hc11_size_stubs (bfd *output_bfd, bfd *stub_bfd,
311*cf2f2c56Smiod                           struct bfd_link_info *info,
312*cf2f2c56Smiod                           asection * (*add_stub_section) (const char*, asection*))
313d2201f2fSdrahn {
314d2201f2fSdrahn   bfd *input_bfd;
315d2201f2fSdrahn   asection *section;
316d2201f2fSdrahn   Elf_Internal_Sym *local_syms, **all_local_syms;
317d2201f2fSdrahn   unsigned int bfd_indx, bfd_count;
318d2201f2fSdrahn   bfd_size_type amt;
319d2201f2fSdrahn   asection *stub_sec;
320d2201f2fSdrahn 
321d2201f2fSdrahn   struct m68hc11_elf_link_hash_table *htab = m68hc11_elf_hash_table (info);
322d2201f2fSdrahn 
323d2201f2fSdrahn   /* Stash our params away.  */
324d2201f2fSdrahn   htab->stub_bfd = stub_bfd;
325d2201f2fSdrahn   htab->add_stub_section = add_stub_section;
326d2201f2fSdrahn 
327d2201f2fSdrahn   /* Count the number of input BFDs and find the top input section id.  */
328d2201f2fSdrahn   for (input_bfd = info->input_bfds, bfd_count = 0;
329d2201f2fSdrahn        input_bfd != NULL;
330d2201f2fSdrahn        input_bfd = input_bfd->link_next)
331d2201f2fSdrahn     {
332d2201f2fSdrahn       bfd_count += 1;
333d2201f2fSdrahn     }
334d2201f2fSdrahn 
335d2201f2fSdrahn   /* We want to read in symbol extension records only once.  To do this
336d2201f2fSdrahn      we need to read in the local symbols in parallel and save them for
337d2201f2fSdrahn      later use; so hold pointers to the local symbols in an array.  */
338d2201f2fSdrahn   amt = sizeof (Elf_Internal_Sym *) * bfd_count;
339d2201f2fSdrahn   all_local_syms = (Elf_Internal_Sym **) bfd_zmalloc (amt);
340d2201f2fSdrahn   if (all_local_syms == NULL)
341d2201f2fSdrahn     return FALSE;
342d2201f2fSdrahn 
343d2201f2fSdrahn   /* Walk over all the input BFDs, swapping in local symbols.  */
344d2201f2fSdrahn   for (input_bfd = info->input_bfds, bfd_indx = 0;
345d2201f2fSdrahn        input_bfd != NULL;
346d2201f2fSdrahn        input_bfd = input_bfd->link_next, bfd_indx++)
347d2201f2fSdrahn     {
348d2201f2fSdrahn       Elf_Internal_Shdr *symtab_hdr;
349d2201f2fSdrahn 
350d2201f2fSdrahn       /* We'll need the symbol table in a second.  */
351d2201f2fSdrahn       symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
352d2201f2fSdrahn       if (symtab_hdr->sh_info == 0)
353d2201f2fSdrahn 	continue;
354d2201f2fSdrahn 
355*cf2f2c56Smiod       /* We need an array of the local symbols attached to the input bfd.  */
356*cf2f2c56Smiod       local_syms = (Elf_Internal_Sym *) symtab_hdr->contents;
357d2201f2fSdrahn       if (local_syms == NULL)
358*cf2f2c56Smiod 	{
359*cf2f2c56Smiod 	  local_syms = bfd_elf_get_elf_syms (input_bfd, symtab_hdr,
360*cf2f2c56Smiod 					     symtab_hdr->sh_info, 0,
361*cf2f2c56Smiod 					     NULL, NULL, NULL);
362*cf2f2c56Smiod 	  /* Cache them for elf_link_input_bfd.  */
363*cf2f2c56Smiod 	  symtab_hdr->contents = (unsigned char *) local_syms;
364*cf2f2c56Smiod 	}
365*cf2f2c56Smiod       if (local_syms == NULL)
366*cf2f2c56Smiod         {
367*cf2f2c56Smiod           free (all_local_syms);
368*cf2f2c56Smiod 	  return FALSE;
369*cf2f2c56Smiod         }
370d2201f2fSdrahn 
371d2201f2fSdrahn       all_local_syms[bfd_indx] = local_syms;
372d2201f2fSdrahn     }
373d2201f2fSdrahn 
374d2201f2fSdrahn   for (input_bfd = info->input_bfds, bfd_indx = 0;
375d2201f2fSdrahn        input_bfd != NULL;
376d2201f2fSdrahn        input_bfd = input_bfd->link_next, bfd_indx++)
377d2201f2fSdrahn     {
378d2201f2fSdrahn       Elf_Internal_Shdr *symtab_hdr;
379d2201f2fSdrahn       Elf_Internal_Sym *local_syms;
380d2201f2fSdrahn       struct elf_link_hash_entry ** sym_hashes;
381d2201f2fSdrahn 
382d2201f2fSdrahn       sym_hashes = elf_sym_hashes (input_bfd);
383d2201f2fSdrahn 
384d2201f2fSdrahn       /* We'll need the symbol table in a second.  */
385d2201f2fSdrahn       symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
386d2201f2fSdrahn       if (symtab_hdr->sh_info == 0)
387d2201f2fSdrahn         continue;
388d2201f2fSdrahn 
389d2201f2fSdrahn       local_syms = all_local_syms[bfd_indx];
390d2201f2fSdrahn 
391d2201f2fSdrahn       /* Walk over each section attached to the input bfd.  */
392d2201f2fSdrahn       for (section = input_bfd->sections;
393d2201f2fSdrahn            section != NULL;
394d2201f2fSdrahn            section = section->next)
395d2201f2fSdrahn         {
396d2201f2fSdrahn           Elf_Internal_Rela *internal_relocs, *irelaend, *irela;
397d2201f2fSdrahn 
398d2201f2fSdrahn           /* If there aren't any relocs, then there's nothing more
399d2201f2fSdrahn              to do.  */
400d2201f2fSdrahn           if ((section->flags & SEC_RELOC) == 0
401d2201f2fSdrahn               || section->reloc_count == 0)
402d2201f2fSdrahn             continue;
403d2201f2fSdrahn 
404d2201f2fSdrahn           /* If this section is a link-once section that will be
405d2201f2fSdrahn              discarded, then don't create any stubs.  */
406d2201f2fSdrahn           if (section->output_section == NULL
407d2201f2fSdrahn               || section->output_section->owner != output_bfd)
408d2201f2fSdrahn             continue;
409d2201f2fSdrahn 
410d2201f2fSdrahn           /* Get the relocs.  */
411d2201f2fSdrahn           internal_relocs
412*cf2f2c56Smiod             = _bfd_elf_link_read_relocs (input_bfd, section, NULL,
413d2201f2fSdrahn 					 (Elf_Internal_Rela *) NULL,
414d2201f2fSdrahn 					 info->keep_memory);
415d2201f2fSdrahn           if (internal_relocs == NULL)
416d2201f2fSdrahn             goto error_ret_free_local;
417d2201f2fSdrahn 
418d2201f2fSdrahn           /* Now examine each relocation.  */
419d2201f2fSdrahn           irela = internal_relocs;
420d2201f2fSdrahn           irelaend = irela + section->reloc_count;
421d2201f2fSdrahn           for (; irela < irelaend; irela++)
422d2201f2fSdrahn             {
423d2201f2fSdrahn               unsigned int r_type, r_indx;
424d2201f2fSdrahn               struct elf32_m68hc11_stub_hash_entry *stub_entry;
425d2201f2fSdrahn               asection *sym_sec;
426d2201f2fSdrahn               bfd_vma sym_value;
427d2201f2fSdrahn               struct elf_link_hash_entry *hash;
428d2201f2fSdrahn               const char *stub_name;
429d2201f2fSdrahn               Elf_Internal_Sym *sym;
430d2201f2fSdrahn 
431d2201f2fSdrahn               r_type = ELF32_R_TYPE (irela->r_info);
432d2201f2fSdrahn 
433d2201f2fSdrahn               /* Only look at 16-bit relocs.  */
434d2201f2fSdrahn               if (r_type != (unsigned int) R_M68HC11_16)
435d2201f2fSdrahn                 continue;
436d2201f2fSdrahn 
437d2201f2fSdrahn               /* Now determine the call target, its name, value,
438d2201f2fSdrahn                  section.  */
439d2201f2fSdrahn               r_indx = ELF32_R_SYM (irela->r_info);
440d2201f2fSdrahn               if (r_indx < symtab_hdr->sh_info)
441d2201f2fSdrahn                 {
442d2201f2fSdrahn                   /* It's a local symbol.  */
443d2201f2fSdrahn                   Elf_Internal_Shdr *hdr;
444d2201f2fSdrahn                   bfd_boolean is_far;
445d2201f2fSdrahn 
446d2201f2fSdrahn                   sym = local_syms + r_indx;
447d2201f2fSdrahn                   is_far = (sym && (sym->st_other & STO_M68HC12_FAR));
448d2201f2fSdrahn                   if (!is_far)
449d2201f2fSdrahn                     continue;
450*cf2f2c56Smiod 
451*cf2f2c56Smiod                   hdr = elf_elfsections (input_bfd)[sym->st_shndx];
452*cf2f2c56Smiod                   sym_sec = hdr->bfd_section;
453d2201f2fSdrahn                   stub_name = (bfd_elf_string_from_elf_section
454d2201f2fSdrahn                                (input_bfd, symtab_hdr->sh_link,
455d2201f2fSdrahn                                 sym->st_name));
456d2201f2fSdrahn                   sym_value = sym->st_value;
457d2201f2fSdrahn                   hash = NULL;
458d2201f2fSdrahn                 }
459d2201f2fSdrahn               else
460d2201f2fSdrahn                 {
461d2201f2fSdrahn                   /* It's an external symbol.  */
462d2201f2fSdrahn                   int e_indx;
463d2201f2fSdrahn 
464d2201f2fSdrahn                   e_indx = r_indx - symtab_hdr->sh_info;
465d2201f2fSdrahn                   hash = (struct elf_link_hash_entry *)
466d2201f2fSdrahn                     (sym_hashes[e_indx]);
467d2201f2fSdrahn 
468d2201f2fSdrahn                   while (hash->root.type == bfd_link_hash_indirect
469d2201f2fSdrahn                          || hash->root.type == bfd_link_hash_warning)
470d2201f2fSdrahn                     hash = ((struct elf_link_hash_entry *)
471d2201f2fSdrahn                             hash->root.u.i.link);
472d2201f2fSdrahn 
473d2201f2fSdrahn                   if (hash->root.type == bfd_link_hash_defined
474d2201f2fSdrahn                       || hash->root.type == bfd_link_hash_defweak)
475d2201f2fSdrahn                     {
476d2201f2fSdrahn                       if (!(hash->other & STO_M68HC12_FAR))
477d2201f2fSdrahn                         continue;
478d2201f2fSdrahn                     }
479d2201f2fSdrahn                   else if (hash->root.type == bfd_link_hash_undefweak)
480d2201f2fSdrahn                     {
481d2201f2fSdrahn                       continue;
482d2201f2fSdrahn                     }
483d2201f2fSdrahn                   else if (hash->root.type == bfd_link_hash_undefined)
484d2201f2fSdrahn                     {
485d2201f2fSdrahn                       continue;
486d2201f2fSdrahn                     }
487d2201f2fSdrahn                   else
488d2201f2fSdrahn                     {
489d2201f2fSdrahn                       bfd_set_error (bfd_error_bad_value);
490d2201f2fSdrahn                       goto error_ret_free_internal;
491d2201f2fSdrahn                     }
492d2201f2fSdrahn                   sym_sec = hash->root.u.def.section;
493d2201f2fSdrahn                   sym_value = hash->root.u.def.value;
494d2201f2fSdrahn                   stub_name = hash->root.root.string;
495d2201f2fSdrahn                 }
496d2201f2fSdrahn 
497d2201f2fSdrahn               if (!stub_name)
498d2201f2fSdrahn                 goto error_ret_free_internal;
499d2201f2fSdrahn 
500d2201f2fSdrahn               stub_entry = m68hc12_stub_hash_lookup
501d2201f2fSdrahn                 (htab->stub_hash_table,
502d2201f2fSdrahn                  stub_name,
503d2201f2fSdrahn                  FALSE, FALSE);
504d2201f2fSdrahn               if (stub_entry == NULL)
505d2201f2fSdrahn                 {
506d2201f2fSdrahn                   if (add_stub_section == 0)
507d2201f2fSdrahn                     continue;
508d2201f2fSdrahn 
509d2201f2fSdrahn                   stub_entry = m68hc12_add_stub (stub_name, section, htab);
510d2201f2fSdrahn                   if (stub_entry == NULL)
511d2201f2fSdrahn                     {
512d2201f2fSdrahn                     error_ret_free_internal:
513d2201f2fSdrahn                       if (elf_section_data (section)->relocs == NULL)
514d2201f2fSdrahn                         free (internal_relocs);
515d2201f2fSdrahn                       goto error_ret_free_local;
516d2201f2fSdrahn                     }
517d2201f2fSdrahn                 }
518d2201f2fSdrahn 
519d2201f2fSdrahn               stub_entry->target_value = sym_value;
520d2201f2fSdrahn               stub_entry->target_section = sym_sec;
521d2201f2fSdrahn             }
522d2201f2fSdrahn 
523d2201f2fSdrahn           /* We're done with the internal relocs, free them.  */
524d2201f2fSdrahn           if (elf_section_data (section)->relocs == NULL)
525d2201f2fSdrahn             free (internal_relocs);
526d2201f2fSdrahn         }
527d2201f2fSdrahn     }
528d2201f2fSdrahn 
529d2201f2fSdrahn   if (add_stub_section)
530d2201f2fSdrahn     {
531d2201f2fSdrahn       /* OK, we've added some stubs.  Find out the new size of the
532d2201f2fSdrahn          stub sections.  */
533d2201f2fSdrahn       for (stub_sec = htab->stub_bfd->sections;
534d2201f2fSdrahn            stub_sec != NULL;
535d2201f2fSdrahn            stub_sec = stub_sec->next)
536d2201f2fSdrahn         {
537d2201f2fSdrahn           stub_sec->_raw_size = 0;
538d2201f2fSdrahn           stub_sec->_cooked_size = 0;
539d2201f2fSdrahn         }
540d2201f2fSdrahn 
541d2201f2fSdrahn       bfd_hash_traverse (htab->stub_hash_table, htab->size_one_stub, htab);
542d2201f2fSdrahn     }
543*cf2f2c56Smiod   free (all_local_syms);
544d2201f2fSdrahn   return TRUE;
545d2201f2fSdrahn 
546d2201f2fSdrahn  error_ret_free_local:
547*cf2f2c56Smiod   free (all_local_syms);
548d2201f2fSdrahn   return FALSE;
549d2201f2fSdrahn }
550d2201f2fSdrahn 
551d2201f2fSdrahn /* Export the trampoline addresses in the symbol table.  */
552d2201f2fSdrahn static bfd_boolean
m68hc11_elf_export_one_stub(struct bfd_hash_entry * gen_entry,void * in_arg)553*cf2f2c56Smiod m68hc11_elf_export_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
554d2201f2fSdrahn {
555d2201f2fSdrahn   struct bfd_link_info *info;
556d2201f2fSdrahn   struct m68hc11_elf_link_hash_table *htab;
557d2201f2fSdrahn   struct elf32_m68hc11_stub_hash_entry *stub_entry;
558d2201f2fSdrahn   char* name;
559d2201f2fSdrahn   bfd_boolean result;
560d2201f2fSdrahn 
561d2201f2fSdrahn   info = (struct bfd_link_info *) in_arg;
562d2201f2fSdrahn   htab = m68hc11_elf_hash_table (info);
563d2201f2fSdrahn 
564d2201f2fSdrahn   /* Massage our args to the form they really have.  */
565d2201f2fSdrahn   stub_entry = (struct elf32_m68hc11_stub_hash_entry *) gen_entry;
566d2201f2fSdrahn 
567d2201f2fSdrahn   /* Generate the trampoline according to HC11 or HC12.  */
568d2201f2fSdrahn   result = (* htab->build_one_stub) (gen_entry, in_arg);
569d2201f2fSdrahn 
570d2201f2fSdrahn   /* Make a printable name that does not conflict with the real function.  */
571d2201f2fSdrahn   name = alloca (strlen (stub_entry->root.string) + 16);
572d2201f2fSdrahn   sprintf (name, "tramp.%s", stub_entry->root.string);
573d2201f2fSdrahn 
574d2201f2fSdrahn   /* Export the symbol for debugging/disassembling.  */
575d2201f2fSdrahn   m68hc11_elf_set_symbol (htab->stub_bfd, info, name,
576d2201f2fSdrahn                           stub_entry->stub_offset,
577d2201f2fSdrahn                           stub_entry->stub_sec);
578d2201f2fSdrahn   return result;
579d2201f2fSdrahn }
580d2201f2fSdrahn 
581d2201f2fSdrahn /* Export a symbol or set its value and section.  */
582d2201f2fSdrahn static void
m68hc11_elf_set_symbol(bfd * abfd,struct bfd_link_info * info,const char * name,bfd_vma value,asection * sec)583*cf2f2c56Smiod m68hc11_elf_set_symbol (bfd *abfd, struct bfd_link_info *info,
584*cf2f2c56Smiod                         const char *name, bfd_vma value, asection *sec)
585d2201f2fSdrahn {
586d2201f2fSdrahn   struct elf_link_hash_entry *h;
587d2201f2fSdrahn 
588d2201f2fSdrahn   h = (struct elf_link_hash_entry *)
589d2201f2fSdrahn     bfd_link_hash_lookup (info->hash, name, FALSE, FALSE, FALSE);
590d2201f2fSdrahn   if (h == NULL)
591d2201f2fSdrahn     {
592d2201f2fSdrahn       _bfd_generic_link_add_one_symbol (info, abfd,
593d2201f2fSdrahn                                         name,
594d2201f2fSdrahn                                         BSF_GLOBAL,
595d2201f2fSdrahn                                         sec,
596d2201f2fSdrahn                                         value,
597d2201f2fSdrahn                                         (const char*) NULL,
598d2201f2fSdrahn                                         TRUE, FALSE, NULL);
599d2201f2fSdrahn     }
600d2201f2fSdrahn   else
601d2201f2fSdrahn     {
602d2201f2fSdrahn       h->root.type = bfd_link_hash_defined;
603d2201f2fSdrahn       h->root.u.def.value = value;
604d2201f2fSdrahn       h->root.u.def.section = sec;
605d2201f2fSdrahn     }
606d2201f2fSdrahn }
607d2201f2fSdrahn 
608d2201f2fSdrahn 
609d2201f2fSdrahn /* Build all the stubs associated with the current output file.  The
610d2201f2fSdrahn    stubs are kept in a hash table attached to the main linker hash
611d2201f2fSdrahn    table.  This function is called via m68hc12elf_finish in the
612d2201f2fSdrahn    linker.  */
613d2201f2fSdrahn 
614d2201f2fSdrahn bfd_boolean
elf32_m68hc11_build_stubs(bfd * abfd,struct bfd_link_info * info)615*cf2f2c56Smiod elf32_m68hc11_build_stubs (bfd *abfd, struct bfd_link_info *info)
616d2201f2fSdrahn {
617d2201f2fSdrahn   asection *stub_sec;
618d2201f2fSdrahn   struct bfd_hash_table *table;
619d2201f2fSdrahn   struct m68hc11_elf_link_hash_table *htab;
620d2201f2fSdrahn   struct m68hc11_scan_param param;
621d2201f2fSdrahn 
622d2201f2fSdrahn   m68hc11_elf_get_bank_parameters (info);
623d2201f2fSdrahn   htab = m68hc11_elf_hash_table (info);
624d2201f2fSdrahn 
625d2201f2fSdrahn   for (stub_sec = htab->stub_bfd->sections;
626d2201f2fSdrahn        stub_sec != NULL;
627d2201f2fSdrahn        stub_sec = stub_sec->next)
628d2201f2fSdrahn     {
629d2201f2fSdrahn       bfd_size_type size;
630d2201f2fSdrahn 
631d2201f2fSdrahn       /* Allocate memory to hold the linker stubs.  */
632d2201f2fSdrahn       size = stub_sec->_raw_size;
633d2201f2fSdrahn       stub_sec->contents = (unsigned char *) bfd_zalloc (htab->stub_bfd, size);
634d2201f2fSdrahn       if (stub_sec->contents == NULL && size != 0)
635d2201f2fSdrahn 	return FALSE;
636d2201f2fSdrahn       stub_sec->_raw_size = 0;
637d2201f2fSdrahn     }
638d2201f2fSdrahn 
639d2201f2fSdrahn   /* Build the stubs as directed by the stub hash table.  */
640d2201f2fSdrahn   table = htab->stub_hash_table;
641d2201f2fSdrahn   bfd_hash_traverse (table, m68hc11_elf_export_one_stub, info);
642d2201f2fSdrahn 
643d2201f2fSdrahn   /* Scan the output sections to see if we use the memory banks.
644d2201f2fSdrahn      If so, export the symbols that define how the memory banks
645d2201f2fSdrahn      are mapped.  This is used by gdb and the simulator to obtain
646d2201f2fSdrahn      the information.  It can be used by programs to burn the eprom
647d2201f2fSdrahn      at the good addresses.  */
648d2201f2fSdrahn   param.use_memory_banks = FALSE;
649d2201f2fSdrahn   param.pinfo = &htab->pinfo;
650d2201f2fSdrahn   bfd_map_over_sections (abfd, scan_sections_for_abi, &param);
651d2201f2fSdrahn   if (param.use_memory_banks)
652d2201f2fSdrahn     {
653d2201f2fSdrahn       m68hc11_elf_set_symbol (abfd, info, BFD_M68HC11_BANK_START_NAME,
654d2201f2fSdrahn                               htab->pinfo.bank_physical,
655d2201f2fSdrahn                               bfd_abs_section_ptr);
656d2201f2fSdrahn       m68hc11_elf_set_symbol (abfd, info, BFD_M68HC11_BANK_VIRTUAL_NAME,
657d2201f2fSdrahn                               htab->pinfo.bank_virtual,
658d2201f2fSdrahn                               bfd_abs_section_ptr);
659d2201f2fSdrahn       m68hc11_elf_set_symbol (abfd, info, BFD_M68HC11_BANK_SIZE_NAME,
660d2201f2fSdrahn                               htab->pinfo.bank_size,
661d2201f2fSdrahn                               bfd_abs_section_ptr);
662d2201f2fSdrahn     }
663d2201f2fSdrahn 
664d2201f2fSdrahn   return TRUE;
665d2201f2fSdrahn }
666d2201f2fSdrahn 
667d2201f2fSdrahn void
m68hc11_elf_get_bank_parameters(struct bfd_link_info * info)668*cf2f2c56Smiod m68hc11_elf_get_bank_parameters (struct bfd_link_info *info)
669d2201f2fSdrahn {
670d2201f2fSdrahn   unsigned i;
671d2201f2fSdrahn   struct m68hc11_page_info *pinfo;
672d2201f2fSdrahn   struct bfd_link_hash_entry *h;
673d2201f2fSdrahn 
674d2201f2fSdrahn   pinfo = &m68hc11_elf_hash_table (info)->pinfo;
675d2201f2fSdrahn   if (pinfo->bank_param_initialized)
676d2201f2fSdrahn     return;
677d2201f2fSdrahn 
678d2201f2fSdrahn   pinfo->bank_virtual = M68HC12_BANK_VIRT;
679d2201f2fSdrahn   pinfo->bank_mask = M68HC12_BANK_MASK;
680d2201f2fSdrahn   pinfo->bank_physical = M68HC12_BANK_BASE;
681d2201f2fSdrahn   pinfo->bank_shift = M68HC12_BANK_SHIFT;
682d2201f2fSdrahn   pinfo->bank_size = 1 << M68HC12_BANK_SHIFT;
683d2201f2fSdrahn 
684d2201f2fSdrahn   h = bfd_link_hash_lookup (info->hash, BFD_M68HC11_BANK_START_NAME,
685d2201f2fSdrahn                             FALSE, FALSE, TRUE);
686d2201f2fSdrahn   if (h != (struct bfd_link_hash_entry*) NULL
687d2201f2fSdrahn       && h->type == bfd_link_hash_defined)
688d2201f2fSdrahn     pinfo->bank_physical = (h->u.def.value
689d2201f2fSdrahn                             + h->u.def.section->output_section->vma
690d2201f2fSdrahn                             + h->u.def.section->output_offset);
691d2201f2fSdrahn 
692d2201f2fSdrahn   h = bfd_link_hash_lookup (info->hash, BFD_M68HC11_BANK_VIRTUAL_NAME,
693d2201f2fSdrahn                             FALSE, FALSE, TRUE);
694d2201f2fSdrahn   if (h != (struct bfd_link_hash_entry*) NULL
695d2201f2fSdrahn       && h->type == bfd_link_hash_defined)
696d2201f2fSdrahn     pinfo->bank_virtual = (h->u.def.value
697d2201f2fSdrahn                            + h->u.def.section->output_section->vma
698d2201f2fSdrahn                            + h->u.def.section->output_offset);
699d2201f2fSdrahn 
700d2201f2fSdrahn   h = bfd_link_hash_lookup (info->hash, BFD_M68HC11_BANK_SIZE_NAME,
701d2201f2fSdrahn                             FALSE, FALSE, TRUE);
702d2201f2fSdrahn   if (h != (struct bfd_link_hash_entry*) NULL
703d2201f2fSdrahn       && h->type == bfd_link_hash_defined)
704d2201f2fSdrahn     pinfo->bank_size = (h->u.def.value
705d2201f2fSdrahn                         + h->u.def.section->output_section->vma
706d2201f2fSdrahn                         + h->u.def.section->output_offset);
707d2201f2fSdrahn 
708d2201f2fSdrahn   pinfo->bank_shift = 0;
709d2201f2fSdrahn   for (i = pinfo->bank_size; i != 0; i >>= 1)
710d2201f2fSdrahn     pinfo->bank_shift++;
711d2201f2fSdrahn   pinfo->bank_shift--;
712d2201f2fSdrahn   pinfo->bank_mask = (1 << pinfo->bank_shift) - 1;
713d2201f2fSdrahn   pinfo->bank_physical_end = pinfo->bank_physical + pinfo->bank_size;
714d2201f2fSdrahn   pinfo->bank_param_initialized = 1;
715d2201f2fSdrahn 
716d2201f2fSdrahn   h = bfd_link_hash_lookup (info->hash, "__far_trampoline", FALSE,
717d2201f2fSdrahn                             FALSE, TRUE);
718d2201f2fSdrahn   if (h != (struct bfd_link_hash_entry*) NULL
719d2201f2fSdrahn       && h->type == bfd_link_hash_defined)
720d2201f2fSdrahn     pinfo->trampoline_addr = (h->u.def.value
721d2201f2fSdrahn                               + h->u.def.section->output_section->vma
722d2201f2fSdrahn                               + h->u.def.section->output_offset);
723d2201f2fSdrahn }
724d2201f2fSdrahn 
725d2201f2fSdrahn /* Return 1 if the address is in banked memory.
726d2201f2fSdrahn    This can be applied to a virtual address and to a physical address.  */
727d2201f2fSdrahn int
m68hc11_addr_is_banked(struct m68hc11_page_info * pinfo,bfd_vma addr)728*cf2f2c56Smiod m68hc11_addr_is_banked (struct m68hc11_page_info *pinfo, bfd_vma addr)
729d2201f2fSdrahn {
730d2201f2fSdrahn   if (addr >= pinfo->bank_virtual)
731d2201f2fSdrahn     return 1;
732d2201f2fSdrahn 
733d2201f2fSdrahn   if (addr >= pinfo->bank_physical && addr <= pinfo->bank_physical_end)
734d2201f2fSdrahn     return 1;
735d2201f2fSdrahn 
736d2201f2fSdrahn   return 0;
737d2201f2fSdrahn }
738d2201f2fSdrahn 
739d2201f2fSdrahn /* Return the physical address seen by the processor, taking
740d2201f2fSdrahn    into account banked memory.  */
741d2201f2fSdrahn bfd_vma
m68hc11_phys_addr(struct m68hc11_page_info * pinfo,bfd_vma addr)742*cf2f2c56Smiod m68hc11_phys_addr (struct m68hc11_page_info *pinfo, bfd_vma addr)
743d2201f2fSdrahn {
744d2201f2fSdrahn   if (addr < pinfo->bank_virtual)
745d2201f2fSdrahn     return addr;
746d2201f2fSdrahn 
747d2201f2fSdrahn   /* Map the address to the memory bank.  */
748d2201f2fSdrahn   addr -= pinfo->bank_virtual;
749d2201f2fSdrahn   addr &= pinfo->bank_mask;
750d2201f2fSdrahn   addr += pinfo->bank_physical;
751d2201f2fSdrahn   return addr;
752d2201f2fSdrahn }
753d2201f2fSdrahn 
754d2201f2fSdrahn /* Return the page number corresponding to an address in banked memory.  */
755d2201f2fSdrahn bfd_vma
m68hc11_phys_page(struct m68hc11_page_info * pinfo,bfd_vma addr)756*cf2f2c56Smiod m68hc11_phys_page (struct m68hc11_page_info *pinfo, bfd_vma addr)
757d2201f2fSdrahn {
758d2201f2fSdrahn   if (addr < pinfo->bank_virtual)
759d2201f2fSdrahn     return 0;
760d2201f2fSdrahn 
761d2201f2fSdrahn   /* Map the address to the memory bank.  */
762d2201f2fSdrahn   addr -= pinfo->bank_virtual;
763d2201f2fSdrahn   addr >>= pinfo->bank_shift;
764d2201f2fSdrahn   addr &= 0x0ff;
765d2201f2fSdrahn   return addr;
766d2201f2fSdrahn }
767d2201f2fSdrahn 
768d2201f2fSdrahn /* This function is used for relocs which are only used for relaxing,
769d2201f2fSdrahn    which the linker should otherwise ignore.  */
770d2201f2fSdrahn 
771d2201f2fSdrahn bfd_reloc_status_type
m68hc11_elf_ignore_reloc(bfd * abfd ATTRIBUTE_UNUSED,arelent * reloc_entry,asymbol * symbol ATTRIBUTE_UNUSED,void * data ATTRIBUTE_UNUSED,asection * input_section,bfd * output_bfd,char ** error_message ATTRIBUTE_UNUSED)772*cf2f2c56Smiod m68hc11_elf_ignore_reloc (bfd *abfd ATTRIBUTE_UNUSED,
773*cf2f2c56Smiod                           arelent *reloc_entry,
774*cf2f2c56Smiod                           asymbol *symbol ATTRIBUTE_UNUSED,
775*cf2f2c56Smiod                           void *data ATTRIBUTE_UNUSED,
776*cf2f2c56Smiod                           asection *input_section,
777*cf2f2c56Smiod                           bfd *output_bfd,
778*cf2f2c56Smiod                           char **error_message ATTRIBUTE_UNUSED)
779d2201f2fSdrahn {
780d2201f2fSdrahn   if (output_bfd != NULL)
781d2201f2fSdrahn     reloc_entry->address += input_section->output_offset;
782d2201f2fSdrahn   return bfd_reloc_ok;
783d2201f2fSdrahn }
784d2201f2fSdrahn 
785d2201f2fSdrahn bfd_reloc_status_type
m68hc11_elf_special_reloc(bfd * abfd ATTRIBUTE_UNUSED,arelent * reloc_entry,asymbol * symbol,void * data ATTRIBUTE_UNUSED,asection * input_section,bfd * output_bfd,char ** error_message ATTRIBUTE_UNUSED)786*cf2f2c56Smiod m68hc11_elf_special_reloc (bfd *abfd ATTRIBUTE_UNUSED,
787*cf2f2c56Smiod                            arelent *reloc_entry,
788*cf2f2c56Smiod                            asymbol *symbol,
789*cf2f2c56Smiod                            void *data ATTRIBUTE_UNUSED,
790*cf2f2c56Smiod                            asection *input_section,
791*cf2f2c56Smiod                            bfd *output_bfd,
792*cf2f2c56Smiod                            char **error_message ATTRIBUTE_UNUSED)
793d2201f2fSdrahn {
794d2201f2fSdrahn   if (output_bfd != (bfd *) NULL
795d2201f2fSdrahn       && (symbol->flags & BSF_SECTION_SYM) == 0
796d2201f2fSdrahn       && (! reloc_entry->howto->partial_inplace
797d2201f2fSdrahn 	  || reloc_entry->addend == 0))
798d2201f2fSdrahn     {
799d2201f2fSdrahn       reloc_entry->address += input_section->output_offset;
800d2201f2fSdrahn       return bfd_reloc_ok;
801d2201f2fSdrahn     }
802d2201f2fSdrahn 
803d2201f2fSdrahn   if (output_bfd != NULL)
804d2201f2fSdrahn     return bfd_reloc_continue;
805d2201f2fSdrahn 
806d2201f2fSdrahn   if (reloc_entry->address > input_section->_cooked_size)
807d2201f2fSdrahn     return bfd_reloc_outofrange;
808d2201f2fSdrahn 
809d2201f2fSdrahn   abort();
810d2201f2fSdrahn }
811d2201f2fSdrahn 
812d2201f2fSdrahn asection *
elf32_m68hc11_gc_mark_hook(asection * sec,struct bfd_link_info * info ATTRIBUTE_UNUSED,Elf_Internal_Rela * rel,struct elf_link_hash_entry * h,Elf_Internal_Sym * sym)813*cf2f2c56Smiod elf32_m68hc11_gc_mark_hook (asection *sec,
814*cf2f2c56Smiod                             struct bfd_link_info *info ATTRIBUTE_UNUSED,
815*cf2f2c56Smiod                             Elf_Internal_Rela *rel,
816*cf2f2c56Smiod                             struct elf_link_hash_entry *h,
817*cf2f2c56Smiod                             Elf_Internal_Sym *sym)
818d2201f2fSdrahn {
819d2201f2fSdrahn   if (h != NULL)
820d2201f2fSdrahn     {
821d2201f2fSdrahn       switch (ELF32_R_TYPE (rel->r_info))
822d2201f2fSdrahn 	{
823d2201f2fSdrahn 	default:
824d2201f2fSdrahn 	  switch (h->root.type)
825d2201f2fSdrahn 	    {
826d2201f2fSdrahn 	    case bfd_link_hash_defined:
827d2201f2fSdrahn 	    case bfd_link_hash_defweak:
828d2201f2fSdrahn 	      return h->root.u.def.section;
829d2201f2fSdrahn 
830d2201f2fSdrahn 	    case bfd_link_hash_common:
831d2201f2fSdrahn 	      return h->root.u.c.p->section;
832d2201f2fSdrahn 
833d2201f2fSdrahn 	    default:
834d2201f2fSdrahn 	      break;
835d2201f2fSdrahn 	    }
836d2201f2fSdrahn 	}
837d2201f2fSdrahn     }
838d2201f2fSdrahn   else
839d2201f2fSdrahn     return bfd_section_from_elf_index (sec->owner, sym->st_shndx);
840d2201f2fSdrahn 
841d2201f2fSdrahn   return NULL;
842d2201f2fSdrahn }
843d2201f2fSdrahn 
844d2201f2fSdrahn bfd_boolean
elf32_m68hc11_gc_sweep_hook(bfd * abfd ATTRIBUTE_UNUSED,struct bfd_link_info * info ATTRIBUTE_UNUSED,asection * sec ATTRIBUTE_UNUSED,const Elf_Internal_Rela * relocs ATTRIBUTE_UNUSED)845*cf2f2c56Smiod elf32_m68hc11_gc_sweep_hook (bfd *abfd ATTRIBUTE_UNUSED,
846*cf2f2c56Smiod                              struct bfd_link_info *info ATTRIBUTE_UNUSED,
847*cf2f2c56Smiod                              asection *sec ATTRIBUTE_UNUSED,
848*cf2f2c56Smiod                              const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED)
849d2201f2fSdrahn {
850d2201f2fSdrahn   /* We don't use got and plt entries for 68hc11/68hc12.  */
851d2201f2fSdrahn   return TRUE;
852d2201f2fSdrahn }
853d2201f2fSdrahn 
854d2201f2fSdrahn /* Look through the relocs for a section during the first phase.
855d2201f2fSdrahn    Since we don't do .gots or .plts, we just need to consider the
856d2201f2fSdrahn    virtual table relocs for gc.  */
857d2201f2fSdrahn 
858d2201f2fSdrahn bfd_boolean
elf32_m68hc11_check_relocs(bfd * abfd,struct bfd_link_info * info,asection * sec,const Elf_Internal_Rela * relocs)859*cf2f2c56Smiod elf32_m68hc11_check_relocs (bfd *abfd, struct bfd_link_info *info,
860*cf2f2c56Smiod                             asection *sec, const Elf_Internal_Rela *relocs)
861d2201f2fSdrahn {
862d2201f2fSdrahn   Elf_Internal_Shdr *           symtab_hdr;
863d2201f2fSdrahn   struct elf_link_hash_entry ** sym_hashes;
864d2201f2fSdrahn   struct elf_link_hash_entry ** sym_hashes_end;
865d2201f2fSdrahn   const Elf_Internal_Rela *     rel;
866d2201f2fSdrahn   const Elf_Internal_Rela *     rel_end;
867d2201f2fSdrahn 
868*cf2f2c56Smiod   if (info->relocatable)
869d2201f2fSdrahn     return TRUE;
870d2201f2fSdrahn 
871d2201f2fSdrahn   symtab_hdr = & elf_tdata (abfd)->symtab_hdr;
872d2201f2fSdrahn   sym_hashes = elf_sym_hashes (abfd);
873d2201f2fSdrahn   sym_hashes_end = sym_hashes + symtab_hdr->sh_size / sizeof (Elf32_External_Sym);
874d2201f2fSdrahn   if (!elf_bad_symtab (abfd))
875d2201f2fSdrahn     sym_hashes_end -= symtab_hdr->sh_info;
876d2201f2fSdrahn 
877d2201f2fSdrahn   rel_end = relocs + sec->reloc_count;
878d2201f2fSdrahn 
879d2201f2fSdrahn   for (rel = relocs; rel < rel_end; rel++)
880d2201f2fSdrahn     {
881d2201f2fSdrahn       struct elf_link_hash_entry * h;
882d2201f2fSdrahn       unsigned long r_symndx;
883d2201f2fSdrahn 
884d2201f2fSdrahn       r_symndx = ELF32_R_SYM (rel->r_info);
885d2201f2fSdrahn 
886d2201f2fSdrahn       if (r_symndx < symtab_hdr->sh_info)
887d2201f2fSdrahn         h = NULL;
888d2201f2fSdrahn       else
889d2201f2fSdrahn         h = sym_hashes [r_symndx - symtab_hdr->sh_info];
890d2201f2fSdrahn 
891d2201f2fSdrahn       switch (ELF32_R_TYPE (rel->r_info))
892d2201f2fSdrahn         {
893d2201f2fSdrahn         /* This relocation describes the C++ object vtable hierarchy.
894d2201f2fSdrahn            Reconstruct it for later use during GC.  */
895d2201f2fSdrahn         case R_M68HC11_GNU_VTINHERIT:
896*cf2f2c56Smiod           if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
897d2201f2fSdrahn             return FALSE;
898d2201f2fSdrahn           break;
899d2201f2fSdrahn 
900d2201f2fSdrahn         /* This relocation describes which C++ vtable entries are actually
901d2201f2fSdrahn            used.  Record for later use during GC.  */
902d2201f2fSdrahn         case R_M68HC11_GNU_VTENTRY:
903*cf2f2c56Smiod           if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
904d2201f2fSdrahn             return FALSE;
905d2201f2fSdrahn           break;
906d2201f2fSdrahn         }
907d2201f2fSdrahn     }
908d2201f2fSdrahn 
909d2201f2fSdrahn   return TRUE;
910d2201f2fSdrahn }
911d2201f2fSdrahn 
912d2201f2fSdrahn static bfd_boolean
m68hc11_get_relocation_value(bfd * input_bfd,struct bfd_link_info * info,asection * input_section,asection ** local_sections,Elf_Internal_Sym * local_syms,Elf_Internal_Rela * rel,const char ** name,bfd_vma * relocation,bfd_boolean * is_far)913*cf2f2c56Smiod m68hc11_get_relocation_value (bfd *input_bfd, struct bfd_link_info *info,
914*cf2f2c56Smiod 			      asection *input_section,
915*cf2f2c56Smiod                               asection **local_sections,
916*cf2f2c56Smiod                               Elf_Internal_Sym *local_syms,
917*cf2f2c56Smiod                               Elf_Internal_Rela *rel,
918*cf2f2c56Smiod                               const char **name,
919*cf2f2c56Smiod                               bfd_vma *relocation, bfd_boolean *is_far)
920d2201f2fSdrahn {
921d2201f2fSdrahn   Elf_Internal_Shdr *symtab_hdr;
922d2201f2fSdrahn   struct elf_link_hash_entry **sym_hashes;
923d2201f2fSdrahn   unsigned long r_symndx;
924d2201f2fSdrahn   asection *sec;
925d2201f2fSdrahn   struct elf_link_hash_entry *h;
926d2201f2fSdrahn   Elf_Internal_Sym *sym;
927d2201f2fSdrahn   const char* stub_name = 0;
928d2201f2fSdrahn 
929*cf2f2c56Smiod   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
930*cf2f2c56Smiod   sym_hashes = elf_sym_hashes (input_bfd);
931d2201f2fSdrahn 
932d2201f2fSdrahn   r_symndx = ELF32_R_SYM (rel->r_info);
933d2201f2fSdrahn 
934d2201f2fSdrahn   /* This is a final link.  */
935d2201f2fSdrahn   h = NULL;
936d2201f2fSdrahn   sym = NULL;
937d2201f2fSdrahn   sec = NULL;
938d2201f2fSdrahn   if (r_symndx < symtab_hdr->sh_info)
939d2201f2fSdrahn     {
940d2201f2fSdrahn       sym = local_syms + r_symndx;
941d2201f2fSdrahn       sec = local_sections[r_symndx];
942d2201f2fSdrahn       *relocation = (sec->output_section->vma
943d2201f2fSdrahn                      + sec->output_offset
944d2201f2fSdrahn                      + sym->st_value);
945d2201f2fSdrahn       *is_far = (sym && (sym->st_other & STO_M68HC12_FAR));
946d2201f2fSdrahn       if (*is_far)
947d2201f2fSdrahn         stub_name = (bfd_elf_string_from_elf_section
948*cf2f2c56Smiod                      (input_bfd, symtab_hdr->sh_link,
949d2201f2fSdrahn                       sym->st_name));
950d2201f2fSdrahn     }
951d2201f2fSdrahn   else
952d2201f2fSdrahn     {
953*cf2f2c56Smiod       bfd_boolean unresolved_reloc, warned;
954*cf2f2c56Smiod 
955*cf2f2c56Smiod       RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
956*cf2f2c56Smiod 			       r_symndx, symtab_hdr, sym_hashes,
957*cf2f2c56Smiod 			       h, sec, *relocation, unresolved_reloc, warned);
958*cf2f2c56Smiod 
959d2201f2fSdrahn       *is_far = (h && (h->other & STO_M68HC12_FAR));
960d2201f2fSdrahn       stub_name = h->root.root.string;
961d2201f2fSdrahn     }
962d2201f2fSdrahn 
963d2201f2fSdrahn   if (h != NULL)
964d2201f2fSdrahn     *name = h->root.root.string;
965d2201f2fSdrahn   else
966d2201f2fSdrahn     {
967d2201f2fSdrahn       *name = (bfd_elf_string_from_elf_section
968*cf2f2c56Smiod                (input_bfd, symtab_hdr->sh_link, sym->st_name));
969d2201f2fSdrahn       if (*name == NULL || **name == '\0')
970d2201f2fSdrahn         *name = bfd_section_name (input_bfd, sec);
971d2201f2fSdrahn     }
972d2201f2fSdrahn 
973d2201f2fSdrahn   if (*is_far && ELF32_R_TYPE (rel->r_info) == R_M68HC11_16)
974d2201f2fSdrahn     {
975d2201f2fSdrahn       struct elf32_m68hc11_stub_hash_entry* stub;
976d2201f2fSdrahn       struct m68hc11_elf_link_hash_table *htab;
977d2201f2fSdrahn 
978d2201f2fSdrahn       htab = m68hc11_elf_hash_table (info);
979d2201f2fSdrahn       stub = m68hc12_stub_hash_lookup (htab->stub_hash_table,
980d2201f2fSdrahn                                        *name, FALSE, FALSE);
981d2201f2fSdrahn       if (stub)
982d2201f2fSdrahn         {
983d2201f2fSdrahn           *relocation = stub->stub_offset
984d2201f2fSdrahn             + stub->stub_sec->output_section->vma
985d2201f2fSdrahn             + stub->stub_sec->output_offset;
986d2201f2fSdrahn           *is_far = FALSE;
987d2201f2fSdrahn         }
988d2201f2fSdrahn     }
989d2201f2fSdrahn   return TRUE;
990d2201f2fSdrahn }
991d2201f2fSdrahn 
992d2201f2fSdrahn /* Relocate a 68hc11/68hc12 ELF section.  */
993d2201f2fSdrahn bfd_boolean
elf32_m68hc11_relocate_section(bfd * output_bfd ATTRIBUTE_UNUSED,struct bfd_link_info * info,bfd * input_bfd,asection * input_section,bfd_byte * contents,Elf_Internal_Rela * relocs,Elf_Internal_Sym * local_syms,asection ** local_sections)994*cf2f2c56Smiod elf32_m68hc11_relocate_section (bfd *output_bfd ATTRIBUTE_UNUSED,
995*cf2f2c56Smiod                                 struct bfd_link_info *info,
996*cf2f2c56Smiod                                 bfd *input_bfd, asection *input_section,
997*cf2f2c56Smiod                                 bfd_byte *contents, Elf_Internal_Rela *relocs,
998*cf2f2c56Smiod                                 Elf_Internal_Sym *local_syms,
999*cf2f2c56Smiod                                 asection **local_sections)
1000d2201f2fSdrahn {
1001d2201f2fSdrahn   Elf_Internal_Shdr *symtab_hdr;
1002d2201f2fSdrahn   struct elf_link_hash_entry **sym_hashes;
1003d2201f2fSdrahn   Elf_Internal_Rela *rel, *relend;
1004d2201f2fSdrahn   const char *name;
1005d2201f2fSdrahn   struct m68hc11_page_info *pinfo;
1006*cf2f2c56Smiod   const struct elf_backend_data * const ebd = get_elf_backend_data (input_bfd);
1007d2201f2fSdrahn 
1008d2201f2fSdrahn   symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
1009d2201f2fSdrahn   sym_hashes = elf_sym_hashes (input_bfd);
1010d2201f2fSdrahn 
1011d2201f2fSdrahn   /* Get memory bank parameters.  */
1012d2201f2fSdrahn   m68hc11_elf_get_bank_parameters (info);
1013d2201f2fSdrahn   pinfo = &m68hc11_elf_hash_table (info)->pinfo;
1014d2201f2fSdrahn 
1015d2201f2fSdrahn   rel = relocs;
1016d2201f2fSdrahn   relend = relocs + input_section->reloc_count;
1017d2201f2fSdrahn   for (; rel < relend; rel++)
1018d2201f2fSdrahn     {
1019d2201f2fSdrahn       int r_type;
1020d2201f2fSdrahn       arelent arel;
1021d2201f2fSdrahn       reloc_howto_type *howto;
1022d2201f2fSdrahn       unsigned long r_symndx;
1023d2201f2fSdrahn       Elf_Internal_Sym *sym;
1024d2201f2fSdrahn       asection *sec;
1025d2201f2fSdrahn       bfd_vma relocation;
1026d2201f2fSdrahn       bfd_reloc_status_type r = bfd_reloc_undefined;
1027d2201f2fSdrahn       bfd_vma phys_page;
1028d2201f2fSdrahn       bfd_vma phys_addr;
1029d2201f2fSdrahn       bfd_vma insn_addr;
1030d2201f2fSdrahn       bfd_vma insn_page;
1031d2201f2fSdrahn       bfd_boolean is_far;
1032d2201f2fSdrahn 
1033d2201f2fSdrahn       r_symndx = ELF32_R_SYM (rel->r_info);
1034d2201f2fSdrahn       r_type = ELF32_R_TYPE (rel->r_info);
1035d2201f2fSdrahn 
1036d2201f2fSdrahn       if (r_type == R_M68HC11_GNU_VTENTRY
1037d2201f2fSdrahn           || r_type == R_M68HC11_GNU_VTINHERIT )
1038d2201f2fSdrahn         continue;
1039d2201f2fSdrahn 
1040*cf2f2c56Smiod       if (info->relocatable)
1041d2201f2fSdrahn 	{
1042*cf2f2c56Smiod 	  /* This is a relocatable link.  We don't have to change
1043d2201f2fSdrahn 	     anything, unless the reloc is against a section symbol,
1044d2201f2fSdrahn 	     in which case we have to adjust according to where the
1045d2201f2fSdrahn 	     section symbol winds up in the output section.  */
1046d2201f2fSdrahn 	  if (r_symndx < symtab_hdr->sh_info)
1047d2201f2fSdrahn 	    {
1048d2201f2fSdrahn 	      sym = local_syms + r_symndx;
1049d2201f2fSdrahn 	      if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
1050d2201f2fSdrahn 		{
1051d2201f2fSdrahn 		  sec = local_sections[r_symndx];
1052d2201f2fSdrahn 		  rel->r_addend += sec->output_offset + sym->st_value;
1053d2201f2fSdrahn 		}
1054d2201f2fSdrahn 	    }
1055d2201f2fSdrahn 
1056d2201f2fSdrahn 	  continue;
1057d2201f2fSdrahn 	}
1058d2201f2fSdrahn       (*ebd->elf_info_to_howto_rel) (input_bfd, &arel, rel);
1059d2201f2fSdrahn       howto = arel.howto;
1060d2201f2fSdrahn 
1061*cf2f2c56Smiod       m68hc11_get_relocation_value (input_bfd, info, input_section,
1062d2201f2fSdrahn 				    local_sections, local_syms,
1063d2201f2fSdrahn                                     rel, &name, &relocation, &is_far);
1064d2201f2fSdrahn 
1065d2201f2fSdrahn       /* Do the memory bank mapping.  */
1066d2201f2fSdrahn       phys_addr = m68hc11_phys_addr (pinfo, relocation + rel->r_addend);
1067d2201f2fSdrahn       phys_page = m68hc11_phys_page (pinfo, relocation + rel->r_addend);
1068d2201f2fSdrahn       switch (r_type)
1069d2201f2fSdrahn         {
1070d2201f2fSdrahn         case R_M68HC11_24:
1071d2201f2fSdrahn           /* Reloc used by 68HC12 call instruction.  */
1072d2201f2fSdrahn           bfd_put_16 (input_bfd, phys_addr,
1073d2201f2fSdrahn                       (bfd_byte*) contents + rel->r_offset);
1074d2201f2fSdrahn           bfd_put_8 (input_bfd, phys_page,
1075d2201f2fSdrahn                      (bfd_byte*) contents + rel->r_offset + 2);
1076d2201f2fSdrahn           r = bfd_reloc_ok;
1077d2201f2fSdrahn           r_type = R_M68HC11_NONE;
1078d2201f2fSdrahn           break;
1079d2201f2fSdrahn 
1080d2201f2fSdrahn         case R_M68HC11_NONE:
1081d2201f2fSdrahn           r = bfd_reloc_ok;
1082d2201f2fSdrahn           break;
1083d2201f2fSdrahn 
1084d2201f2fSdrahn         case R_M68HC11_LO16:
1085d2201f2fSdrahn           /* Reloc generated by %addr(expr) gas to obtain the
1086d2201f2fSdrahn              address as mapped in the memory bank window.  */
1087d2201f2fSdrahn           relocation = phys_addr;
1088d2201f2fSdrahn           break;
1089d2201f2fSdrahn 
1090d2201f2fSdrahn         case R_M68HC11_PAGE:
1091d2201f2fSdrahn           /* Reloc generated by %page(expr) gas to obtain the
1092d2201f2fSdrahn              page number associated with the address.  */
1093d2201f2fSdrahn           relocation = phys_page;
1094d2201f2fSdrahn           break;
1095d2201f2fSdrahn 
1096d2201f2fSdrahn         case R_M68HC11_16:
1097d2201f2fSdrahn           /* Get virtual address of instruction having the relocation.  */
1098d2201f2fSdrahn           if (is_far)
1099d2201f2fSdrahn             {
1100d2201f2fSdrahn               const char* msg;
1101d2201f2fSdrahn               char* buf;
1102d2201f2fSdrahn               msg = _("Reference to the far symbol `%s' using a wrong "
1103d2201f2fSdrahn                       "relocation may result in incorrect execution");
1104d2201f2fSdrahn               buf = alloca (strlen (msg) + strlen (name) + 10);
1105d2201f2fSdrahn               sprintf (buf, msg, name);
1106d2201f2fSdrahn 
1107d2201f2fSdrahn               (* info->callbacks->warning)
1108d2201f2fSdrahn                 (info, buf, name, input_bfd, NULL, rel->r_offset);
1109d2201f2fSdrahn             }
1110d2201f2fSdrahn 
1111d2201f2fSdrahn           /* Get virtual address of instruction having the relocation.  */
1112d2201f2fSdrahn           insn_addr = input_section->output_section->vma
1113d2201f2fSdrahn             + input_section->output_offset
1114d2201f2fSdrahn             + rel->r_offset;
1115d2201f2fSdrahn 
1116d2201f2fSdrahn           insn_page = m68hc11_phys_page (pinfo, insn_addr);
1117d2201f2fSdrahn 
1118d2201f2fSdrahn           if (m68hc11_addr_is_banked (pinfo, relocation + rel->r_addend)
1119d2201f2fSdrahn               && m68hc11_addr_is_banked (pinfo, insn_addr)
1120d2201f2fSdrahn               && phys_page != insn_page)
1121d2201f2fSdrahn             {
1122d2201f2fSdrahn               const char* msg;
1123d2201f2fSdrahn               char* buf;
1124d2201f2fSdrahn 
1125d2201f2fSdrahn               msg = _("banked address [%lx:%04lx] (%lx) is not in the same bank "
1126d2201f2fSdrahn                       "as current banked address [%lx:%04lx] (%lx)");
1127d2201f2fSdrahn 
1128d2201f2fSdrahn               buf = alloca (strlen (msg) + 128);
1129d2201f2fSdrahn               sprintf (buf, msg, phys_page, phys_addr,
1130d2201f2fSdrahn                        (long) (relocation + rel->r_addend),
1131d2201f2fSdrahn                        insn_page, m68hc11_phys_addr (pinfo, insn_addr),
1132d2201f2fSdrahn                        (long) (insn_addr));
1133d2201f2fSdrahn               if (!((*info->callbacks->warning)
1134d2201f2fSdrahn                     (info, buf, name, input_bfd, input_section,
1135d2201f2fSdrahn                      rel->r_offset)))
1136d2201f2fSdrahn                 return FALSE;
1137d2201f2fSdrahn               break;
1138d2201f2fSdrahn             }
1139d2201f2fSdrahn           if (phys_page != 0 && insn_page == 0)
1140d2201f2fSdrahn             {
1141d2201f2fSdrahn               const char* msg;
1142d2201f2fSdrahn               char* buf;
1143d2201f2fSdrahn 
1144d2201f2fSdrahn               msg = _("reference to a banked address [%lx:%04lx] in the "
1145d2201f2fSdrahn                       "normal address space at %04lx");
1146d2201f2fSdrahn 
1147d2201f2fSdrahn               buf = alloca (strlen (msg) + 128);
1148d2201f2fSdrahn               sprintf (buf, msg, phys_page, phys_addr, insn_addr);
1149d2201f2fSdrahn               if (!((*info->callbacks->warning)
1150d2201f2fSdrahn                     (info, buf, name, input_bfd, input_section,
1151d2201f2fSdrahn                      insn_addr)))
1152d2201f2fSdrahn                 return FALSE;
1153d2201f2fSdrahn 
1154d2201f2fSdrahn               relocation = phys_addr;
1155d2201f2fSdrahn               break;
1156d2201f2fSdrahn             }
1157d2201f2fSdrahn 
1158d2201f2fSdrahn           /* If this is a banked address use the phys_addr so that
1159d2201f2fSdrahn              we stay in the banked window.  */
1160d2201f2fSdrahn           if (m68hc11_addr_is_banked (pinfo, relocation + rel->r_addend))
1161d2201f2fSdrahn             relocation = phys_addr;
1162d2201f2fSdrahn           break;
1163d2201f2fSdrahn         }
1164d2201f2fSdrahn       if (r_type != R_M68HC11_NONE)
1165d2201f2fSdrahn         r = _bfd_final_link_relocate (howto, input_bfd, input_section,
1166d2201f2fSdrahn                                       contents, rel->r_offset,
1167d2201f2fSdrahn                                       relocation, rel->r_addend);
1168d2201f2fSdrahn 
1169d2201f2fSdrahn       if (r != bfd_reloc_ok)
1170d2201f2fSdrahn 	{
1171d2201f2fSdrahn 	  const char * msg = (const char *) 0;
1172d2201f2fSdrahn 
1173d2201f2fSdrahn 	  switch (r)
1174d2201f2fSdrahn 	    {
1175d2201f2fSdrahn 	    case bfd_reloc_overflow:
1176d2201f2fSdrahn 	      if (!((*info->callbacks->reloc_overflow)
1177d2201f2fSdrahn 		    (info, name, howto->name, (bfd_vma) 0,
1178d2201f2fSdrahn 		     input_bfd, input_section, rel->r_offset)))
1179d2201f2fSdrahn 		return FALSE;
1180d2201f2fSdrahn 	      break;
1181d2201f2fSdrahn 
1182d2201f2fSdrahn 	    case bfd_reloc_undefined:
1183d2201f2fSdrahn 	      if (!((*info->callbacks->undefined_symbol)
1184d2201f2fSdrahn 		    (info, name, input_bfd, input_section,
1185d2201f2fSdrahn 		     rel->r_offset, TRUE)))
1186d2201f2fSdrahn 		return FALSE;
1187d2201f2fSdrahn 	      break;
1188d2201f2fSdrahn 
1189d2201f2fSdrahn 	    case bfd_reloc_outofrange:
1190d2201f2fSdrahn 	      msg = _ ("internal error: out of range error");
1191d2201f2fSdrahn 	      goto common_error;
1192d2201f2fSdrahn 
1193d2201f2fSdrahn 	    case bfd_reloc_notsupported:
1194d2201f2fSdrahn 	      msg = _ ("internal error: unsupported relocation error");
1195d2201f2fSdrahn 	      goto common_error;
1196d2201f2fSdrahn 
1197d2201f2fSdrahn 	    case bfd_reloc_dangerous:
1198d2201f2fSdrahn 	      msg = _ ("internal error: dangerous error");
1199d2201f2fSdrahn 	      goto common_error;
1200d2201f2fSdrahn 
1201d2201f2fSdrahn 	    default:
1202d2201f2fSdrahn 	      msg = _ ("internal error: unknown error");
1203d2201f2fSdrahn 	      /* fall through */
1204d2201f2fSdrahn 
1205d2201f2fSdrahn 	    common_error:
1206d2201f2fSdrahn 	      if (!((*info->callbacks->warning)
1207d2201f2fSdrahn 		    (info, msg, name, input_bfd, input_section,
1208d2201f2fSdrahn 		     rel->r_offset)))
1209d2201f2fSdrahn 		return FALSE;
1210d2201f2fSdrahn 	      break;
1211d2201f2fSdrahn 	    }
1212d2201f2fSdrahn 	}
1213d2201f2fSdrahn     }
1214d2201f2fSdrahn 
1215d2201f2fSdrahn   return TRUE;
1216d2201f2fSdrahn }
1217d2201f2fSdrahn 
1218d2201f2fSdrahn 
1219d2201f2fSdrahn 
1220d2201f2fSdrahn /* Set and control ELF flags in ELF header.  */
1221d2201f2fSdrahn 
1222d2201f2fSdrahn bfd_boolean
_bfd_m68hc11_elf_set_private_flags(bfd * abfd,flagword flags)1223*cf2f2c56Smiod _bfd_m68hc11_elf_set_private_flags (bfd *abfd, flagword flags)
1224d2201f2fSdrahn {
1225d2201f2fSdrahn   BFD_ASSERT (!elf_flags_init (abfd)
1226d2201f2fSdrahn 	      || elf_elfheader (abfd)->e_flags == flags);
1227d2201f2fSdrahn 
1228d2201f2fSdrahn   elf_elfheader (abfd)->e_flags = flags;
1229d2201f2fSdrahn   elf_flags_init (abfd) = TRUE;
1230d2201f2fSdrahn   return TRUE;
1231d2201f2fSdrahn }
1232d2201f2fSdrahn 
1233d2201f2fSdrahn /* Merge backend specific data from an object file to the output
1234d2201f2fSdrahn    object file when linking.  */
1235d2201f2fSdrahn 
1236d2201f2fSdrahn bfd_boolean
_bfd_m68hc11_elf_merge_private_bfd_data(bfd * ibfd,bfd * obfd)1237*cf2f2c56Smiod _bfd_m68hc11_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
1238d2201f2fSdrahn {
1239d2201f2fSdrahn   flagword old_flags;
1240d2201f2fSdrahn   flagword new_flags;
1241d2201f2fSdrahn   bfd_boolean ok = TRUE;
1242d2201f2fSdrahn 
1243d2201f2fSdrahn   /* Check if we have the same endianess */
1244d2201f2fSdrahn   if (!_bfd_generic_verify_endian_match (ibfd, obfd))
1245d2201f2fSdrahn     return FALSE;
1246d2201f2fSdrahn 
1247d2201f2fSdrahn   if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
1248d2201f2fSdrahn       || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
1249d2201f2fSdrahn     return TRUE;
1250d2201f2fSdrahn 
1251d2201f2fSdrahn   new_flags = elf_elfheader (ibfd)->e_flags;
1252d2201f2fSdrahn   elf_elfheader (obfd)->e_flags |= new_flags & EF_M68HC11_ABI;
1253d2201f2fSdrahn   old_flags = elf_elfheader (obfd)->e_flags;
1254d2201f2fSdrahn 
1255d2201f2fSdrahn   if (! elf_flags_init (obfd))
1256d2201f2fSdrahn     {
1257d2201f2fSdrahn       elf_flags_init (obfd) = TRUE;
1258d2201f2fSdrahn       elf_elfheader (obfd)->e_flags = new_flags;
1259d2201f2fSdrahn       elf_elfheader (obfd)->e_ident[EI_CLASS]
1260d2201f2fSdrahn 	= elf_elfheader (ibfd)->e_ident[EI_CLASS];
1261d2201f2fSdrahn 
1262d2201f2fSdrahn       if (bfd_get_arch (obfd) == bfd_get_arch (ibfd)
1263d2201f2fSdrahn 	  && bfd_get_arch_info (obfd)->the_default)
1264d2201f2fSdrahn 	{
1265d2201f2fSdrahn 	  if (! bfd_set_arch_mach (obfd, bfd_get_arch (ibfd),
1266d2201f2fSdrahn 				   bfd_get_mach (ibfd)))
1267d2201f2fSdrahn 	    return FALSE;
1268d2201f2fSdrahn 	}
1269d2201f2fSdrahn 
1270d2201f2fSdrahn       return TRUE;
1271d2201f2fSdrahn     }
1272d2201f2fSdrahn 
1273d2201f2fSdrahn   /* Check ABI compatibility.  */
1274d2201f2fSdrahn   if ((new_flags & E_M68HC11_I32) != (old_flags & E_M68HC11_I32))
1275d2201f2fSdrahn     {
1276d2201f2fSdrahn       (*_bfd_error_handler)
1277d2201f2fSdrahn 	(_("%s: linking files compiled for 16-bit integers (-mshort) "
1278d2201f2fSdrahn            "and others for 32-bit integers"),
1279d2201f2fSdrahn 	 bfd_archive_filename (ibfd));
1280d2201f2fSdrahn       ok = FALSE;
1281d2201f2fSdrahn     }
1282d2201f2fSdrahn   if ((new_flags & E_M68HC11_F64) != (old_flags & E_M68HC11_F64))
1283d2201f2fSdrahn     {
1284d2201f2fSdrahn       (*_bfd_error_handler)
1285d2201f2fSdrahn 	(_("%s: linking files compiled for 32-bit double (-fshort-double) "
1286d2201f2fSdrahn            "and others for 64-bit double"),
1287d2201f2fSdrahn 	 bfd_archive_filename (ibfd));
1288d2201f2fSdrahn       ok = FALSE;
1289d2201f2fSdrahn     }
1290d2201f2fSdrahn 
1291d2201f2fSdrahn   /* Processor compatibility.  */
1292d2201f2fSdrahn   if (!EF_M68HC11_CAN_MERGE_MACH (new_flags, old_flags))
1293d2201f2fSdrahn     {
1294d2201f2fSdrahn       (*_bfd_error_handler)
1295d2201f2fSdrahn 	(_("%s: linking files compiled for HCS12 with "
1296d2201f2fSdrahn            "others compiled for HC12"),
1297d2201f2fSdrahn 	 bfd_archive_filename (ibfd));
1298d2201f2fSdrahn       ok = FALSE;
1299d2201f2fSdrahn     }
1300d2201f2fSdrahn   new_flags = ((new_flags & ~EF_M68HC11_MACH_MASK)
1301d2201f2fSdrahn                | (EF_M68HC11_MERGE_MACH (new_flags, old_flags)));
1302d2201f2fSdrahn 
1303d2201f2fSdrahn   elf_elfheader (obfd)->e_flags = new_flags;
1304d2201f2fSdrahn 
1305*cf2f2c56Smiod   new_flags &= ~(EF_M68HC11_ABI | EF_M68HC11_MACH_MASK);
1306*cf2f2c56Smiod   old_flags &= ~(EF_M68HC11_ABI | EF_M68HC11_MACH_MASK);
1307d2201f2fSdrahn 
1308d2201f2fSdrahn   /* Warn about any other mismatches */
1309d2201f2fSdrahn   if (new_flags != old_flags)
1310d2201f2fSdrahn     {
1311d2201f2fSdrahn       (*_bfd_error_handler)
1312d2201f2fSdrahn 	(_("%s: uses different e_flags (0x%lx) fields than previous modules (0x%lx)"),
1313d2201f2fSdrahn 	 bfd_archive_filename (ibfd), (unsigned long) new_flags,
1314d2201f2fSdrahn 	 (unsigned long) old_flags);
1315d2201f2fSdrahn       ok = FALSE;
1316d2201f2fSdrahn     }
1317d2201f2fSdrahn 
1318d2201f2fSdrahn   if (! ok)
1319d2201f2fSdrahn     {
1320d2201f2fSdrahn       bfd_set_error (bfd_error_bad_value);
1321d2201f2fSdrahn       return FALSE;
1322d2201f2fSdrahn     }
1323d2201f2fSdrahn 
1324d2201f2fSdrahn   return TRUE;
1325d2201f2fSdrahn }
1326d2201f2fSdrahn 
1327d2201f2fSdrahn bfd_boolean
_bfd_m68hc11_elf_print_private_bfd_data(bfd * abfd,void * ptr)1328*cf2f2c56Smiod _bfd_m68hc11_elf_print_private_bfd_data (bfd *abfd, void *ptr)
1329d2201f2fSdrahn {
1330d2201f2fSdrahn   FILE *file = (FILE *) ptr;
1331d2201f2fSdrahn 
1332d2201f2fSdrahn   BFD_ASSERT (abfd != NULL && ptr != NULL);
1333d2201f2fSdrahn 
1334d2201f2fSdrahn   /* Print normal ELF private data.  */
1335d2201f2fSdrahn   _bfd_elf_print_private_bfd_data (abfd, ptr);
1336d2201f2fSdrahn 
1337d2201f2fSdrahn   /* xgettext:c-format */
1338d2201f2fSdrahn   fprintf (file, _("private flags = %lx:"), elf_elfheader (abfd)->e_flags);
1339d2201f2fSdrahn 
1340d2201f2fSdrahn   if (elf_elfheader (abfd)->e_flags & E_M68HC11_I32)
1341d2201f2fSdrahn     fprintf (file, _("[abi=32-bit int, "));
1342d2201f2fSdrahn   else
1343d2201f2fSdrahn     fprintf (file, _("[abi=16-bit int, "));
1344d2201f2fSdrahn 
1345d2201f2fSdrahn   if (elf_elfheader (abfd)->e_flags & E_M68HC11_F64)
1346d2201f2fSdrahn     fprintf (file, _("64-bit double, "));
1347d2201f2fSdrahn   else
1348d2201f2fSdrahn     fprintf (file, _("32-bit double, "));
1349d2201f2fSdrahn 
1350d2201f2fSdrahn   if (strcmp (bfd_get_target (abfd), "elf32-m68hc11") == 0)
1351d2201f2fSdrahn     fprintf (file, _("cpu=HC11]"));
1352d2201f2fSdrahn   else if (elf_elfheader (abfd)->e_flags & EF_M68HCS12_MACH)
1353d2201f2fSdrahn     fprintf (file, _("cpu=HCS12]"));
1354d2201f2fSdrahn   else
1355d2201f2fSdrahn     fprintf (file, _("cpu=HC12]"));
1356d2201f2fSdrahn 
1357d2201f2fSdrahn   if (elf_elfheader (abfd)->e_flags & E_M68HC12_BANKS)
1358d2201f2fSdrahn     fprintf (file, _(" [memory=bank-model]"));
1359d2201f2fSdrahn   else
1360d2201f2fSdrahn     fprintf (file, _(" [memory=flat]"));
1361d2201f2fSdrahn 
1362d2201f2fSdrahn   fputc ('\n', file);
1363d2201f2fSdrahn 
1364d2201f2fSdrahn   return TRUE;
1365d2201f2fSdrahn }
1366d2201f2fSdrahn 
scan_sections_for_abi(bfd * abfd ATTRIBUTE_UNUSED,asection * asect,void * arg)1367*cf2f2c56Smiod static void scan_sections_for_abi (bfd *abfd ATTRIBUTE_UNUSED,
1368*cf2f2c56Smiod                                    asection *asect, void *arg)
1369d2201f2fSdrahn {
1370d2201f2fSdrahn   struct m68hc11_scan_param* p = (struct m68hc11_scan_param*) arg;
1371d2201f2fSdrahn 
1372d2201f2fSdrahn   if (asect->vma >= p->pinfo->bank_virtual)
1373d2201f2fSdrahn     p->use_memory_banks = TRUE;
1374d2201f2fSdrahn }
1375d2201f2fSdrahn 
1376d2201f2fSdrahn /* Tweak the OSABI field of the elf header.  */
1377d2201f2fSdrahn 
1378d2201f2fSdrahn void
elf32_m68hc11_post_process_headers(bfd * abfd,struct bfd_link_info * link_info)1379*cf2f2c56Smiod elf32_m68hc11_post_process_headers (bfd *abfd, struct bfd_link_info *link_info)
1380d2201f2fSdrahn {
1381d2201f2fSdrahn   struct m68hc11_scan_param param;
1382d2201f2fSdrahn 
1383d2201f2fSdrahn   if (link_info == 0)
1384d2201f2fSdrahn     return;
1385d2201f2fSdrahn 
1386d2201f2fSdrahn   m68hc11_elf_get_bank_parameters (link_info);
1387d2201f2fSdrahn 
1388d2201f2fSdrahn   param.use_memory_banks = FALSE;
1389d2201f2fSdrahn   param.pinfo = &m68hc11_elf_hash_table (link_info)->pinfo;
1390d2201f2fSdrahn   bfd_map_over_sections (abfd, scan_sections_for_abi, &param);
1391d2201f2fSdrahn   if (param.use_memory_banks)
1392d2201f2fSdrahn     {
1393d2201f2fSdrahn       Elf_Internal_Ehdr * i_ehdrp;
1394d2201f2fSdrahn 
1395d2201f2fSdrahn       i_ehdrp = elf_elfheader (abfd);
1396d2201f2fSdrahn       i_ehdrp->e_flags |= E_M68HC12_BANKS;
1397d2201f2fSdrahn     }
1398d2201f2fSdrahn }
1399d2201f2fSdrahn 
1400