1/* Renesas / SuperH specific support for Symbian 32-bit ELF files
2   Copyright 2004, 2005
3   Free Software Foundation, Inc.
4   Contributed by Red Hat
5
6   This file is part of BFD, the Binary File Descriptor library.
7
8   This program is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 2 of the License, or
11   (at your option) any later version.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program; if not, write to the Free Software
20   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
21
22/* Stop elf32-sh.c from defining any target vectors.  */
23#define SH_TARGET_ALREADY_DEFINED
24#define sh_find_elf_flags           sh_symbian_find_elf_flags
25#define sh_elf_get_flags_from_mach  sh_symbian_elf_get_flags_from_mach
26#include "elf32-sh.c"
27
28
29//#define DEBUG 1
30#define DEBUG 0
31
32#define DIRECTIVE_HEADER	"#<SYMEDIT>#\n"
33#define DIRECTIVE_IMPORT	"IMPORT "
34#define DIRECTIVE_EXPORT	"EXPORT "
35#define DIRECTIVE_AS		"AS "
36
37/* Macro to advance 's' until either it reaches 'e' or the
38   character pointed to by 's' is equal to 'c'.  If 'e' is
39   reached and DEBUG is enabled then the error message 'm'
40   is displayed.  */
41#define SKIP_UNTIL(s,e,c,m)					\
42  do								\
43    {								\
44      while (s < e && *s != c)					\
45	++ s;							\
46      if (s >= e)						\
47	{							\
48          if (DEBUG)						\
49	    fprintf (stderr, "Corrupt directive: %s\n", m);	\
50	  result = FALSE;					\
51	}							\
52    }								\
53  while (0);							\
54  if (!result)							\
55     break;
56
57/* Like SKIP_UNTIL except there are two terminator characters
58   c1 and c2.  */
59#define SKIP_UNTIL2(s,e,c1,c2,m)				\
60  do								\
61    {								\
62      while (s < e && *s != c1 && *s != c2)			\
63	++ s;							\
64      if (s >= e)						\
65	{							\
66          if (DEBUG)						\
67	    fprintf (stderr, "Corrupt directive: %s\n", m);	\
68	  result = FALSE;					\
69	}							\
70    }								\
71  while (0);							\
72  if (!result)							\
73     break;
74
75/* Macro to advance 's' until either it reaches 'e' or the
76   character pointed to by 's' is not equal to 'c'.  If 'e'
77   is reached and DEBUG is enabled then the error message
78   'm' is displayed.  */
79#define SKIP_WHILE(s,e,c,m)					\
80  do								\
81    {								\
82      while (s < e && *s == c)					\
83	++ s;							\
84      if (s >= e)						\
85	{							\
86          if (DEBUG)						\
87	    fprintf (stderr, "Corrupt directive: %s\n", m);	\
88	  result = FALSE;					\
89	}							\
90    }								\
91  while (0);							\
92  if (!result)							\
93     break;
94
95
96typedef struct symbol_rename
97{
98  struct symbol_rename *       next;
99  char *                       current_name;
100  char *                       new_name;
101  struct elf_link_hash_entry * current_hash;
102  unsigned long                new_symndx;
103}
104symbol_rename;
105
106static symbol_rename * rename_list = NULL;
107
108/* Accumulate a list of symbols to be renamed.  */
109
110static bfd_boolean
111sh_symbian_import_as (struct bfd_link_info *info, bfd * abfd,
112		      char * current_name, char * new_name)
113{
114  struct elf_link_hash_entry * new_hash;
115  symbol_rename * node;
116
117  if (DEBUG)
118    fprintf (stderr, "IMPORT '%s' AS '%s'\n", current_name, new_name);
119
120  for (node = rename_list; node; node = node->next)
121    if (strcmp (node->current_name, current_name) == 0)
122      {
123	if (strcmp (node->new_name, new_name) == 0)
124	  /* Already added to rename list.  */
125	  return TRUE;
126
127	bfd_set_error (bfd_error_invalid_operation);
128	_bfd_error_handler (_("%B: IMPORT AS directive for %s conceals previous IMPORT AS"),
129			    abfd, current_name);
130	return FALSE;
131      }
132
133  if ((node = bfd_malloc (sizeof * node)) == NULL)
134    {
135      if (DEBUG)
136	fprintf (stderr, "IMPORT AS: No mem for new rename node\n");
137      return FALSE;
138    }
139
140  if ((node->current_name = bfd_malloc (strlen (current_name) + 1)) == NULL)
141    {
142      if (DEBUG)
143	fprintf (stderr, "IMPORT AS: No mem for current name field in rename node\n");
144      free (node);
145      return FALSE;
146    }
147  else
148    strcpy (node->current_name, current_name);
149
150  if ((node->new_name = bfd_malloc (strlen (new_name) + 1)) == NULL)
151    {
152      if (DEBUG)
153	fprintf (stderr, "IMPORT AS: No mem for new name field in rename node\n");
154      free (node->current_name);
155      free (node);
156      return FALSE;
157    }
158  else
159    strcpy (node->new_name, new_name);
160
161  node->next = rename_list;
162  node->current_hash = NULL;
163  node->new_symndx = 0;
164  rename_list = node;
165
166  new_hash = elf_link_hash_lookup (elf_hash_table (info), node->new_name, TRUE, FALSE, TRUE);
167  bfd_elf_link_record_dynamic_symbol (info, new_hash);
168  if (new_hash->root.type == bfd_link_hash_new)
169    new_hash->root.type = bfd_link_hash_undefined;
170
171  return TRUE;
172}
173
174
175static bfd_boolean
176sh_symbian_import (bfd * abfd ATTRIBUTE_UNUSED, char * name)
177{
178  if (DEBUG)
179    fprintf (stderr, "IMPORT '%s'\n", name);
180
181  /* XXX: Generate an import somehow ?  */
182
183  return TRUE;
184}
185
186static bfd_boolean
187sh_symbian_export (bfd * abfd ATTRIBUTE_UNUSED, char * name)
188{
189  if (DEBUG)
190    fprintf (stderr, "EXPORT '%s'\n", name);
191
192  /* XXX: Generate an export somehow ?  */
193
194  return TRUE;
195}
196
197/* Process any magic embedded commands in the .directive. section.
198   Returns TRUE upon sucecss, but if it fails it sets bfd_error and
199   returns FALSE.  */
200
201static bfd_boolean
202sh_symbian_process_embedded_commands (struct bfd_link_info *info, bfd * abfd,
203				      asection * sec, bfd_byte * contents)
204{
205  char *s;
206  char *e;
207  bfd_boolean result = TRUE;
208  bfd_size_type sz = sec->rawsize ? sec->rawsize : sec->size;
209
210  for (s = (char *) contents, e = s + sz; s < e;)
211    {
212      char * directive = s;
213
214      switch (*s)
215	{
216	  /* I want to use "case DIRECTIVE_HEADER [0]:" here but gcc won't let me :-(  */
217	case '#':
218	  if (strcmp (s, DIRECTIVE_HEADER))
219	    result = FALSE;
220	  else
221	    /* Just ignore the header.
222	       XXX: Strictly speaking we ought to check that the header
223	       is present and that it is the first thing in the file.  */
224	    s += strlen (DIRECTIVE_HEADER) + 1;
225	  break;
226
227	case 'I':
228	  if (strncmp (s, DIRECTIVE_IMPORT, strlen (DIRECTIVE_IMPORT)))
229	    result = FALSE;
230	  else
231	    {
232	      char * new_name;
233	      char * new_name_end;
234	      char   name_end_char;
235
236	      /* Skip the IMPORT directive.  */
237	      s += strlen (DIRECTIVE_IMPORT);
238
239	      new_name = s;
240	      /* Find the end of the new name.  */
241	      while (s < e && *s != ' ' && *s != '\n')
242		++ s;
243	      if (s >= e)
244		{
245		  /* We have reached the end of the .directive section
246		     without encountering a string terminator.  This is
247		     allowed for IMPORT directives.  */
248		  new_name_end   = e - 1;
249		  name_end_char  = * new_name_end;
250		  * new_name_end = 0;
251		  result = sh_symbian_import (abfd, new_name);
252		  * new_name_end = name_end_char;
253		  break;
254		}
255
256	      /* Remember where the name ends.  */
257	      new_name_end = s;
258	      /* Skip any whitespace before the 'AS'.  */
259	      SKIP_WHILE (s, e, ' ', "IMPORT: Name just followed by spaces");
260	      /* Terminate the new name.  (Do this after skiping...)  */
261	      name_end_char = * new_name_end;
262	      * new_name_end = 0;
263
264	      /* Check to see if 'AS '... is present.  If se we have an IMPORT AS
265		 directive, otherwise we have an IMPORT directive.  */
266	      if (strncmp (s, DIRECTIVE_AS, strlen (DIRECTIVE_AS)))
267		{
268		  /* Skip the new-line at the end of the name.  */
269		  if (DEBUG && name_end_char != '\n')
270		    fprintf (stderr, "IMPORT: No newline at end of directive\n");
271		  else
272		    s ++;
273
274		  result = sh_symbian_import (abfd, new_name);
275
276		  /* Skip past the NUL character.  */
277		  if (* s ++ != 0)
278		    {
279		      if (DEBUG)
280			fprintf (stderr, "IMPORT: No NUL at end of directive\n");
281		    }
282		}
283	      else
284		{
285		  char * current_name;
286		  char * current_name_end;
287		  char   current_name_end_char;
288
289		  /* Skip the 'AS '.  */
290		  s += strlen (DIRECTIVE_AS);
291		  /* Skip any white space after the 'AS '.  */
292		  SKIP_WHILE (s, e, ' ', "IMPORT AS: Nothing after AS");
293		  current_name = s;
294		  /* Find the end of the current name.  */
295		  SKIP_UNTIL2 (s, e, ' ', '\n', "IMPORT AS: No newline at the end of the current name");
296		  /* Skip (backwards) over spaces at the end of the current name.  */
297		  current_name_end = s;
298		  current_name_end_char = * current_name_end;
299
300		  SKIP_WHILE (s, e, ' ', "IMPORT AS: Current name just followed by spaces");
301		  /* Skip past the newline character.  */
302		  if (* s ++ != '\n')
303		    if (DEBUG)
304		      fprintf (stderr, "IMPORT AS: No newline at end of directive\n");
305
306		  /* Terminate the current name after having performed the skips.  */
307		  * current_name_end = 0;
308
309		  result = sh_symbian_import_as (info, abfd, current_name, new_name);
310
311		  /* The next character should be a NUL.  */
312		  if (* s != 0)
313		    {
314		      if (DEBUG)
315			fprintf (stderr, "IMPORT AS: Junk at end of directive\n");
316		      result = FALSE;
317		    }
318		  s ++;
319
320		  * current_name_end = current_name_end_char;
321		}
322
323	      /* Restore the characters we overwrote, since
324		 the .directive section will be emitted.  */
325	      * new_name_end = name_end_char;
326	    }
327	  break;
328
329	case 'E':
330	  if (strncmp (s, DIRECTIVE_EXPORT, strlen (DIRECTIVE_EXPORT)))
331	    result = FALSE;
332	  else
333	    {
334	      char * name;
335	      char * name_end;
336	      char   name_end_char;
337
338	      /* Skip the directive.  */
339	      s += strlen (DIRECTIVE_EXPORT);
340	      name = s;
341	      /* Find the end of the name to be exported.  */
342	      SKIP_UNTIL (s, e, '\n', "EXPORT: no newline at end of directive");
343	      /* Skip (backwards) over spaces at end of exported name.  */
344	      for (name_end = s; name_end[-1] == ' '; name_end --)
345		;
346	      /* name_end now points at the first character after the
347		 end of the exported name, so we can termiante it  */
348	      name_end_char = * name_end;
349	      * name_end = 0;
350	      /* Skip passed the newline character.  */
351	      s ++;
352
353	      result = sh_symbian_export (abfd, name);
354
355	      /* The next character should be a NUL.  */
356	      if (* s != 0)
357		{
358		  if (DEBUG)
359		    fprintf (stderr, "EXPORT: Junk at end of directive\n");
360		  result = FALSE;
361		}
362	      s++;
363
364	      /* Restore the character we deleted.  */
365	      * name_end = name_end_char;
366	    }
367	  break;
368
369	default:
370	  result = FALSE;
371	  break;
372	}
373
374      if (! result)
375	{
376	  if (DEBUG)
377	    fprintf (stderr, "offset into .directive section: %ld\n",
378		     (long) (directive - (char *) contents));
379
380	  bfd_set_error (bfd_error_invalid_operation);
381	  _bfd_error_handler (_("%B: Unrecognised .directive command: %s"),
382			      abfd, directive);
383	  break;
384	}
385    }
386
387  return result;
388}
389
390
391/* Scan a bfd for a .directive section, and if found process it.
392   Returns TRUE upon success, FALSE otherwise.  */
393bfd_boolean bfd_elf32_sh_symbian_process_directives (struct bfd_link_info *info, bfd * abfd);
394
395bfd_boolean
396bfd_elf32_sh_symbian_process_directives (struct bfd_link_info *info, bfd * abfd)
397{
398  bfd_boolean result = FALSE;
399  bfd_byte *  contents;
400  asection *  sec = bfd_get_section_by_name (abfd, ".directive");
401  bfd_size_type sz;
402
403  if (!sec)
404    return TRUE;
405
406  sz = sec->rawsize ? sec->rawsize : sec->size;
407  contents = bfd_malloc (sz);
408
409  if (!contents)
410    bfd_set_error (bfd_error_no_memory);
411  else
412    {
413      if (bfd_get_section_contents (abfd, sec, contents, 0, sz))
414	result = sh_symbian_process_embedded_commands (info, abfd, sec, contents);
415      free (contents);
416    }
417
418  return result;
419}
420
421/* Intercept the normal sh_relocate_section() function
422   and magle the relocs to allow for symbol renaming.  */
423
424static bfd_boolean
425sh_symbian_relocate_section (bfd *                  output_bfd,
426			     struct bfd_link_info * info,
427			     bfd *                  input_bfd,
428			     asection *             input_section,
429			     bfd_byte *             contents,
430			     Elf_Internal_Rela *    relocs,
431			     Elf_Internal_Sym *     local_syms,
432			     asection **            local_sections)
433{
434  /* When performing a final link we implement the IMPORT AS directives.  */
435  if (!info->relocatable)
436    {
437      Elf_Internal_Rela *            rel;
438      Elf_Internal_Rela *            relend;
439      Elf_Internal_Shdr *            symtab_hdr;
440      struct elf_link_hash_entry **  sym_hashes;
441      struct elf_link_hash_entry **  sym_hashes_end;
442      struct elf_link_hash_table *   hash_table;
443      symbol_rename *                ptr;
444      bfd_size_type                  num_global_syms;
445      unsigned long		     num_local_syms;
446
447      BFD_ASSERT (! elf_bad_symtab (input_bfd));
448
449      symtab_hdr       = & elf_tdata (input_bfd)->symtab_hdr;
450      hash_table       = elf_hash_table (info);
451      num_local_syms   = symtab_hdr->sh_info;
452      num_global_syms  = symtab_hdr->sh_size / sizeof (Elf32_External_Sym);
453      num_global_syms -= num_local_syms;
454      sym_hashes       = elf_sym_hashes (input_bfd);
455      sym_hashes_end   = sym_hashes + num_global_syms;
456
457      /* First scan the rename table, caching the hash entry and the new index.  */
458      for (ptr = rename_list; ptr; ptr = ptr->next)
459	{
460	  struct elf_link_hash_entry *   new_hash;
461	  struct elf_link_hash_entry **  h;
462
463	  ptr->current_hash = elf_link_hash_lookup (hash_table, ptr->current_name, FALSE, FALSE, TRUE);
464
465	  if (ptr->current_hash == NULL)
466	    {
467	      if (DEBUG)
468		fprintf (stderr, "IMPORT AS: current symbol '%s' does not exist\n", ptr->current_name);
469	      continue;
470	    }
471
472	  new_hash = elf_link_hash_lookup (hash_table, ptr->new_name, FALSE, FALSE, TRUE);
473
474	  /* If we could not find the symbol then it is a new, undefined symbol.
475	     Symbian want this behaviour - ie they want to be able to rename the
476	     reference in a reloc from one undefined symbol to another, new and
477	     undefined symbol.  So we create that symbol here.  */
478	  if (new_hash == NULL)
479	    {
480	      asection *                     psec = bfd_und_section_ptr;
481	      Elf_Internal_Sym               new_sym;
482	      bfd_vma                        new_value = 0;
483	      bfd_boolean                    skip;
484	      bfd_boolean                    override;
485	      bfd_boolean                    type_change_ok;
486	      bfd_boolean                    size_change_ok;
487
488	      new_sym.st_value = 0;
489	      new_sym.st_size  = 0;
490	      new_sym.st_name  = -1;
491	      new_sym.st_info  = ELF_ST_INFO (STB_GLOBAL, STT_FUNC);
492	      new_sym.st_other = ELF_ST_VISIBILITY (STV_DEFAULT);
493	      new_sym.st_shndx = SHN_UNDEF;
494
495	      if (! _bfd_elf_merge_symbol (input_bfd, info,
496					   ptr->new_name, & new_sym,
497					   & psec, & new_value, NULL,
498					   & new_hash, & skip,
499					   & override, & type_change_ok,
500					   & size_change_ok))
501		{
502		  _bfd_error_handler (_("%B: Failed to add renamed symbol %s"),
503				      input_bfd, ptr->new_name);
504		  continue;
505		}
506	      /* XXX - should we check psec, skip, override etc ?  */
507
508	      new_hash->root.type = bfd_link_hash_undefined;
509
510	      /* Allow the symbol to become local if necessary.  */
511	      if (new_hash->dynindx == -1)
512		new_hash->def_regular = 1;
513
514	      if (DEBUG)
515		fprintf (stderr, "Created new symbol %s\n", ptr->new_name);
516	    }
517
518	  /* Convert the new_hash value into a index into the table of symbol hashes.  */
519	  for (h = sym_hashes; h < sym_hashes_end; h ++)
520	    {
521	      if (* h == new_hash)
522		{
523		  ptr->new_symndx = h - sym_hashes + num_local_syms;
524		  if (DEBUG)
525		    fprintf (stderr, "Converted new hash to index of %ld\n", ptr->new_symndx);
526		  break;
527		}
528	    }
529	  /* If the new symbol is not in the hash table then it must be
530	     because it is one of the newly created undefined symbols
531	     manufactured above.  So we extend the sym has table here to
532	     include this extra symbol.  */
533	  if (h == sym_hashes_end)
534	    {
535	      struct elf_link_hash_entry **  new_sym_hashes;
536
537	      /* This is not very efficient, but it works.  */
538	      ++ num_global_syms;
539	      new_sym_hashes = bfd_alloc (input_bfd, num_global_syms * sizeof * sym_hashes);
540	      if (new_sym_hashes == NULL)
541		{
542		  if (DEBUG)
543		    fprintf (stderr, "Out of memory extending hash table\n");
544		  continue;
545		}
546	      memcpy (new_sym_hashes, sym_hashes, (num_global_syms - 1) * sizeof * sym_hashes);
547	      new_sym_hashes[num_global_syms - 1] = new_hash;
548	      elf_sym_hashes (input_bfd) = sym_hashes = new_sym_hashes;
549	      sym_hashes_end = sym_hashes + num_global_syms;
550	      symtab_hdr->sh_size  = (num_global_syms + num_local_syms) * sizeof (Elf32_External_Sym);
551
552	      ptr->new_symndx = num_global_syms - 1 + num_local_syms;
553
554	      if (DEBUG)
555		fprintf (stderr, "Extended symbol hash table to insert new symbol as index %ld\n",
556			 ptr->new_symndx);
557	    }
558	}
559
560      /* Walk the reloc list looking for references to renamed symbols.
561	 When we find one, we alter the index in the reloc to point to the new symbol.  */
562      for (rel = relocs, relend = relocs + input_section->reloc_count;
563	   rel < relend;
564	   rel ++)
565	{
566	  int                          r_type;
567	  unsigned long                r_symndx;
568	  struct elf_link_hash_entry * h;
569
570	  r_symndx = ELF32_R_SYM (rel->r_info);
571	  r_type = ELF32_R_TYPE (rel->r_info);
572
573	  /* Ignore unused relocs.  */
574	  if ((r_type >= (int) R_SH_GNU_VTINHERIT
575	       && r_type <= (int) R_SH_LABEL)
576	      || r_type == (int) R_SH_NONE
577	      || r_type < 0
578	      || r_type >= R_SH_max)
579	    continue;
580
581	  /* Ignore relocs against local symbols.  */
582	  if (r_symndx < num_local_syms)
583	    continue;
584
585	  BFD_ASSERT (r_symndx < (num_global_syms + num_local_syms));
586	  h = sym_hashes[r_symndx - num_local_syms];
587	  BFD_ASSERT (h != NULL);
588
589	  while (   h->root.type == bfd_link_hash_indirect
590		 || h->root.type == bfd_link_hash_warning)
591	    h = (struct elf_link_hash_entry *) h->root.u.i.link;
592
593	  /* If the symbol is defined there is no need to rename it.
594	     XXX - is this true ?  */
595	  if (   h->root.type == bfd_link_hash_defined
596	      || h->root.type == bfd_link_hash_defweak
597	      || h->root.type == bfd_link_hash_undefweak)
598	    continue;
599
600	  for (ptr = rename_list; ptr; ptr = ptr->next)
601	    if (h == ptr->current_hash)
602	      {
603		BFD_ASSERT (ptr->new_symndx);
604		if (DEBUG)
605		  fprintf (stderr, "convert reloc %lx from using index %ld to using index %ld\n",
606			   (long) rel->r_info, (long) ELF32_R_SYM (rel->r_info), ptr->new_symndx);
607		rel->r_info = ELF32_R_INFO (ptr->new_symndx, r_type);
608		break;
609	      }
610	}
611    }
612
613  return sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
614				  contents, relocs, local_syms, local_sections);
615}
616
617static bfd_boolean
618sh_symbian_check_directives (bfd *abfd, struct bfd_link_info *info)
619{
620  return bfd_elf32_sh_symbian_process_directives (info, abfd);
621}
622
623#define TARGET_LITTLE_SYM	bfd_elf32_shl_symbian_vec
624#define TARGET_LITTLE_NAME      "elf32-shl-symbian"
625
626#undef  elf_backend_relocate_section
627#define elf_backend_relocate_section	sh_symbian_relocate_section
628#undef  elf_backend_check_directives
629#define elf_backend_check_directives    sh_symbian_check_directives
630
631#include "elf32-target.h"
632