1/* Renesas / SuperH specific support for Symbian 32-bit ELF files
2   Copyright (C) 2004-2017 Free Software Foundation, Inc.
3   Contributed by Red Hat
4
5   This file is part of BFD, the Binary File Descriptor library.
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 3 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20   MA 02110-1301, USA.  */
21
22
23/* Stop elf32-sh.c from defining any target vectors.  */
24#define SH_TARGET_ALREADY_DEFINED
25#define sh_find_elf_flags           sh_symbian_find_elf_flags
26#define sh_elf_get_flags_from_mach  sh_symbian_elf_get_flags_from_mach
27#include "elf32-sh.c"
28
29
30//#define SYMBIAN_DEBUG 1
31#define SYMBIAN_DEBUG 0
32
33#define DIRECTIVE_HEADER	"#<SYMEDIT>#\n"
34#define DIRECTIVE_IMPORT	"IMPORT "
35#define DIRECTIVE_EXPORT	"EXPORT "
36#define DIRECTIVE_AS		"AS "
37
38/* Macro to advance 's' until either it reaches 'e' or the
39   character pointed to by 's' is equal to 'c'.  If 'e' is
40   reached and SYMBIAN_DEBUG is enabled then the error message 'm'
41   is displayed.  */
42#define SKIP_UNTIL(s,e,c,m)					\
43  do								\
44    {								\
45      while (s < e && *s != c)					\
46	++ s;							\
47      if (s >= e)						\
48	{							\
49          if (SYMBIAN_DEBUG)					\
50	    fprintf (stderr, "Corrupt directive: %s\n", m);	\
51	  result = FALSE;					\
52	}							\
53    }								\
54  while (0);							\
55  if (!result)							\
56     break;
57
58/* Like SKIP_UNTIL except there are two terminator characters
59   c1 and c2.  */
60#define SKIP_UNTIL2(s,e,c1,c2,m)				\
61  do								\
62    {								\
63      while (s < e && *s != c1 && *s != c2)			\
64	++ s;							\
65      if (s >= e)						\
66	{							\
67          if (SYMBIAN_DEBUG)					\
68	    fprintf (stderr, "Corrupt directive: %s\n", m);	\
69	  result = FALSE;					\
70	}							\
71    }								\
72  while (0);							\
73  if (!result)							\
74     break;
75
76/* Macro to advance 's' until either it reaches 'e' or the
77   character pointed to by 's' is not equal to 'c'.  If 'e'
78   is reached and SYMBIAN_DEBUG is enabled then the error message
79   'm' is displayed.  */
80#define SKIP_WHILE(s,e,c,m)					\
81  do								\
82    {								\
83      while (s < e && *s == c)					\
84	++ s;							\
85      if (s >= e)						\
86	{							\
87          if (SYMBIAN_DEBUG)					\
88	    fprintf (stderr, "Corrupt directive: %s\n", m);	\
89	  result = FALSE;					\
90	}							\
91    }								\
92  while (0);							\
93  if (!result)							\
94     break;
95
96
97typedef struct symbol_rename
98{
99  struct symbol_rename *       next;
100  char *                       current_name;
101  char *                       new_name;
102  struct elf_link_hash_entry * current_hash;
103  unsigned long                new_symndx;
104}
105symbol_rename;
106
107static symbol_rename * rename_list = NULL;
108
109/* Accumulate a list of symbols to be renamed.  */
110
111static bfd_boolean
112sh_symbian_import_as (struct bfd_link_info *info, bfd * abfd,
113		      char * current_name, char * new_name)
114{
115  struct elf_link_hash_entry * new_hash;
116  symbol_rename * node;
117
118  if (SYMBIAN_DEBUG)
119    fprintf (stderr, "IMPORT '%s' AS '%s'\n", current_name, new_name);
120
121  for (node = rename_list; node; node = node->next)
122    if (strcmp (node->current_name, current_name) == 0)
123      {
124	if (strcmp (node->new_name, new_name) == 0)
125	  /* Already added to rename list.  */
126	  return TRUE;
127
128	bfd_set_error (bfd_error_invalid_operation);
129	/* xgettext:c-format */
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	  /* xgettext:c-format */
384	  _bfd_error_handler (_("%B: Unrecognised .directive command: %s"),
385			      abfd, directive);
386	  break;
387	}
388    }
389
390  return result;
391}
392
393
394/* Scan a bfd for a .directive section, and if found process it.
395   Returns TRUE upon success, FALSE otherwise.  */
396
397static bfd_boolean
398sh_symbian_process_directives (bfd *abfd, struct bfd_link_info *info)
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 (!bfd_link_relocatable (info))
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,
475					   FALSE, FALSE, TRUE);
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	      struct bfd_link_hash_entry *bh = NULL;
483	      bfd_boolean collect = get_elf_backend_data (input_bfd)->collect;
484	      if (_bfd_generic_link_add_one_symbol (info, input_bfd,
485						    ptr->new_name, BSF_GLOBAL,
486						    bfd_und_section_ptr, 0,
487						    NULL, FALSE, collect,
488						    &bh))
489		{
490		  new_hash = (struct elf_link_hash_entry *) bh;
491		  new_hash->type = STT_FUNC;
492		  new_hash->non_elf = 0;
493
494		  if (SYMBIAN_DEBUG)
495		    fprintf (stderr, "Created new symbol %s\n", ptr->new_name);
496		}
497	    }
498
499	  if (new_hash == NULL)
500	    {
501	      /* xgettext:c-format */
502	      _bfd_error_handler (_("%B: Failed to add renamed symbol %s"),
503				  input_bfd, ptr->new_name);
504	      continue;
505	    }
506
507	  /* Convert the new_hash value into a index into the table of symbol hashes.  */
508	  for (h = sym_hashes; h < sym_hashes_end; h ++)
509	    {
510	      if (* h == new_hash)
511		{
512		  ptr->new_symndx = h - sym_hashes + num_local_syms;
513		  if (SYMBIAN_DEBUG)
514		    fprintf (stderr, "Converted new hash to index of %ld\n", ptr->new_symndx);
515		  break;
516		}
517	    }
518	  /* If the new symbol is not in the hash table then it must be
519	     because it is one of the newly created undefined symbols
520	     manufactured above.  So we extend the sym has table here to
521	     include this extra symbol.  */
522	  if (h == sym_hashes_end)
523	    {
524	      struct elf_link_hash_entry **  new_sym_hashes;
525
526	      /* This is not very efficient, but it works.  */
527	      ++ num_global_syms;
528	      new_sym_hashes = bfd_alloc (input_bfd, num_global_syms * sizeof * sym_hashes);
529	      if (new_sym_hashes == NULL)
530		{
531		  if (SYMBIAN_DEBUG)
532		    fprintf (stderr, "Out of memory extending hash table\n");
533		  continue;
534		}
535	      memcpy (new_sym_hashes, sym_hashes, (num_global_syms - 1) * sizeof * sym_hashes);
536	      new_sym_hashes[num_global_syms - 1] = new_hash;
537	      elf_sym_hashes (input_bfd) = sym_hashes = new_sym_hashes;
538	      sym_hashes_end = sym_hashes + num_global_syms;
539	      symtab_hdr->sh_size  = (num_global_syms + num_local_syms) * sizeof (Elf32_External_Sym);
540
541	      ptr->new_symndx = num_global_syms - 1 + num_local_syms;
542
543	      if (SYMBIAN_DEBUG)
544		fprintf (stderr, "Extended symbol hash table to insert new symbol as index %ld\n",
545			 ptr->new_symndx);
546	    }
547	}
548
549      /* Walk the reloc list looking for references to renamed symbols.
550	 When we find one, we alter the index in the reloc to point to the new symbol.  */
551      for (rel = relocs, relend = relocs + input_section->reloc_count;
552	   rel < relend;
553	   rel ++)
554	{
555	  int                          r_type;
556	  unsigned long                r_symndx;
557	  struct elf_link_hash_entry * h;
558
559	  r_symndx = ELF32_R_SYM (rel->r_info);
560	  r_type = ELF32_R_TYPE (rel->r_info);
561
562	  /* Ignore unused relocs.  */
563	  if ((r_type >= (int) R_SH_GNU_VTINHERIT
564	       && r_type <= (int) R_SH_LABEL)
565	      || r_type == (int) R_SH_NONE
566	      || r_type < 0
567	      || r_type >= R_SH_max)
568	    continue;
569
570	  /* Ignore relocs against local symbols.  */
571	  if (r_symndx < num_local_syms)
572	    continue;
573
574	  BFD_ASSERT (r_symndx < (num_global_syms + num_local_syms));
575	  h = sym_hashes[r_symndx - num_local_syms];
576	  BFD_ASSERT (h != NULL);
577
578	  while (   h->root.type == bfd_link_hash_indirect
579		 || h->root.type == bfd_link_hash_warning)
580	    h = (struct elf_link_hash_entry *) h->root.u.i.link;
581
582	  /* If the symbol is defined there is no need to rename it.
583	     XXX - is this true ?  */
584	  if (   h->root.type == bfd_link_hash_defined
585	      || h->root.type == bfd_link_hash_defweak
586	      || h->root.type == bfd_link_hash_undefweak)
587	    continue;
588
589	  for (ptr = rename_list; ptr; ptr = ptr->next)
590	    if (h == ptr->current_hash)
591	      {
592		BFD_ASSERT (ptr->new_symndx);
593		if (SYMBIAN_DEBUG)
594		  fprintf (stderr, "convert reloc %lx from using index %ld to using index %ld\n",
595			   (unsigned long) rel->r_info,
596			   (long) ELF32_R_SYM (rel->r_info), ptr->new_symndx);
597		rel->r_info = ELF32_R_INFO (ptr->new_symndx, r_type);
598		break;
599	      }
600	}
601    }
602
603  return sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
604				  contents, relocs, local_syms, local_sections);
605}
606
607#define TARGET_LITTLE_SYM	sh_elf32_symbian_le_vec
608#define TARGET_LITTLE_NAME      "elf32-shl-symbian"
609
610#undef  elf_backend_relocate_section
611#define elf_backend_relocate_section	sh_symbian_relocate_section
612#undef  elf_backend_check_directives
613#define elf_backend_check_directives    sh_symbian_process_directives
614
615#include "elf32-target.h"
616