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