1/* Renesas / SuperH specific support for Symbian 32-bit ELF files
2   Copyright 2004
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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  bfd_byte *                   current_name;
100  bfd_byte *                   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		      bfd_byte * current_name, bfd_byte * 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, bfd_byte * 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, bfd_byte * 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  bfd_byte *s;
206  bfd_byte *e;
207  bfd_boolean result = TRUE;
208  bfd_size_type sz = sec->rawsize ? sec->rawsize : sec->size;
209
210  for (s = contents, e = s + sz; s < e;)
211    {
212      bfd_byte * 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	      bfd_byte * new_name;
233	      bfd_byte * new_name_end;
234	      bfd_byte   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		  bfd_byte * current_name;
286		  bfd_byte * current_name_end;
287		  bfd_byte   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	      bfd_byte * name;
335	      bfd_byte * name_end;
336	      bfd_byte   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: %d\n", directive - contents);
378
379	  bfd_set_error (bfd_error_invalid_operation);
380	  _bfd_error_handler (_("%B: Unrecognised .directive command: %s"),
381			      abfd, directive);
382	  break;
383	}
384    }
385
386  return result;
387}
388
389
390/* Scan a bfd for a .directive section, and if found process it.
391   Returns TRUE upon success, FALSE otherwise.  */
392bfd_boolean bfd_elf32_sh_symbian_process_directives (struct bfd_link_info *info, bfd * abfd);
393
394bfd_boolean
395bfd_elf32_sh_symbian_process_directives (struct bfd_link_info *info, bfd * abfd)
396{
397  bfd_boolean result = FALSE;
398  bfd_byte *  contents;
399  asection *  sec = bfd_get_section_by_name (abfd, ".directive");
400  bfd_size_type sz;
401
402  if (!sec)
403    return TRUE;
404
405  sz = sec->rawsize ? sec->rawsize : sec->size;
406  contents = bfd_malloc (sz);
407
408  if (!contents)
409    bfd_set_error (bfd_error_no_memory);
410  else
411    {
412      if (bfd_get_section_contents (abfd, sec, contents, 0, sz))
413	result = sh_symbian_process_embedded_commands (info, abfd, sec, contents);
414      free (contents);
415    }
416
417  return result;
418}
419
420/* Intercept the normal sh_relocate_section() function
421   and magle the relocs to allow for symbol renaming.  */
422
423static bfd_boolean
424sh_symbian_relocate_section (bfd *                  output_bfd,
425			     struct bfd_link_info * info,
426			     bfd *                  input_bfd,
427			     asection *             input_section,
428			     bfd_byte *             contents,
429			     Elf_Internal_Rela *    relocs,
430			     Elf_Internal_Sym *     local_syms,
431			     asection **            local_sections)
432{
433  /* When performing a final link we implement the IMPORT AS directives.  */
434  if (!info->relocatable)
435    {
436      Elf_Internal_Rela *            rel;
437      Elf_Internal_Rela *            relend;
438      Elf_Internal_Shdr *            symtab_hdr;
439      struct elf_link_hash_entry **  sym_hashes;
440      struct elf_link_hash_entry **  sym_hashes_end;
441      struct elf_link_hash_table *   hash_table;
442      symbol_rename *                ptr;
443      bfd_size_type                  num_global_syms;
444      unsigned long		     num_local_syms;
445
446      BFD_ASSERT (! elf_bad_symtab (input_bfd));
447
448      symtab_hdr       = & elf_tdata (input_bfd)->symtab_hdr;
449      hash_table       = elf_hash_table (info);
450      num_local_syms   = symtab_hdr->sh_info;
451      num_global_syms  = symtab_hdr->sh_size / sizeof (Elf32_External_Sym);
452      num_global_syms -= num_local_syms;
453      sym_hashes       = elf_sym_hashes (input_bfd);
454      sym_hashes_end   = sym_hashes + num_global_syms;
455
456      /* First scan the rename table, caching the hash entry and the new index.  */
457      for (ptr = rename_list; ptr; ptr = ptr->next)
458	{
459	  struct elf_link_hash_entry *   new_hash;
460	  struct elf_link_hash_entry **  h;
461
462	  ptr->current_hash = elf_link_hash_lookup (hash_table, ptr->current_name, FALSE, FALSE, TRUE);
463
464	  if (ptr->current_hash == NULL)
465	    {
466	      if (DEBUG)
467		fprintf (stderr, "IMPORT AS: current symbol '%s' does not exist\n", ptr->current_name);
468	      continue;
469	    }
470
471	  new_hash = elf_link_hash_lookup (hash_table, ptr->new_name, FALSE, FALSE, TRUE);
472
473	  /* If we could not find the symbol then it is a new, undefined symbol.
474	     Symbian want this behaviour - ie they want to be able to rename the
475	     reference in a reloc from one undefined symbol to another, new and
476	     undefined symbol.  So we create that symbol here.  */
477	  if (new_hash == NULL)
478	    {
479	      asection *                     psec = bfd_und_section_ptr;
480	      Elf_Internal_Sym               new_sym;
481	      bfd_vma                        new_value = 0;
482	      bfd_boolean                    skip;
483	      bfd_boolean                    override;
484	      bfd_boolean                    type_change_ok;
485	      bfd_boolean                    size_change_ok;
486
487	      new_sym.st_value = 0;
488	      new_sym.st_size  = 0;
489	      new_sym.st_name  = -1;
490	      new_sym.st_info  = ELF_ST_INFO (STB_GLOBAL, STT_FUNC);
491	      new_sym.st_other = ELF_ST_VISIBILITY (STV_DEFAULT);
492	      new_sym.st_shndx = SHN_UNDEF;
493
494	      if (! _bfd_elf_merge_symbol (input_bfd, info, ptr->new_name, & new_sym, & psec,
495					   & new_value, & new_hash, & skip, & override, & type_change_ok,
496					   & size_change_ok))
497		{
498		  _bfd_error_handler (_("%B: Failed to add renamed symbol %s"),
499				      input_bfd, ptr->new_name);
500		  continue;
501		}
502	      /* XXX - should we check psec, skip, override etc ?  */
503
504	      new_hash->root.type = bfd_link_hash_undefined;
505
506	      /* Allow the symbol to become local if necessary.  */
507	      if (new_hash->dynindx == -1)
508		new_hash->def_regular = 1;
509
510	      if (DEBUG)
511		fprintf (stderr, "Created new symbol %s\n", ptr->new_name);
512	    }
513
514	  /* Convert the new_hash value into a index into the table of symbol hashes.  */
515	  for (h = sym_hashes; h < sym_hashes_end; h ++)
516	    {
517	      if (* h == new_hash)
518		{
519		  ptr->new_symndx = h - sym_hashes + num_local_syms;
520		  if (DEBUG)
521		    fprintf (stderr, "Converted new hash to index of %ld\n", ptr->new_symndx);
522		  break;
523		}
524	    }
525	  /* If the new symbol is not in the hash table then it must be
526	     because it is one of the newly created undefined symbols
527	     manufactured above.  So we extend the sym has table here to
528	     include this extra symbol.  */
529	  if (h == sym_hashes_end)
530	    {
531	      struct elf_link_hash_entry **  new_sym_hashes;
532
533	      /* This is not very efficient, but it works.  */
534	      ++ num_global_syms;
535	      new_sym_hashes = bfd_alloc (input_bfd, num_global_syms * sizeof * sym_hashes);
536	      if (new_sym_hashes == NULL)
537		{
538		  if (DEBUG)
539		    fprintf (stderr, "Out of memory extending hash table\n");
540		  continue;
541		}
542	      memcpy (new_sym_hashes, sym_hashes, (num_global_syms - 1) * sizeof * sym_hashes);
543	      new_sym_hashes[num_global_syms - 1] = new_hash;
544	      elf_sym_hashes (input_bfd) = sym_hashes = new_sym_hashes;
545	      sym_hashes_end = sym_hashes + num_global_syms;
546	      symtab_hdr->sh_size  = (num_global_syms + num_local_syms) * sizeof (Elf32_External_Sym);
547
548	      ptr->new_symndx = num_global_syms - 1 + num_local_syms;
549
550	      if (DEBUG)
551		fprintf (stderr, "Extended symbol hash table to insert new symbol as index %ld\n",
552			 ptr->new_symndx);
553	    }
554	}
555
556      /* Walk the reloc list looking for references to renamed symbols.
557	 When we find one, we alter the index in the reloc to point to the new symbol.  */
558      for (rel = relocs, relend = relocs + input_section->reloc_count;
559	   rel < relend;
560	   rel ++)
561	{
562	  int                          r_type;
563	  unsigned long                r_symndx;
564	  struct elf_link_hash_entry * h;
565
566	  r_symndx = ELF32_R_SYM (rel->r_info);
567	  r_type = ELF32_R_TYPE (rel->r_info);
568
569	  /* Ignore unused relocs.  */
570	  if ((r_type >= (int) R_SH_GNU_VTINHERIT
571	       && r_type <= (int) R_SH_LABEL)
572	      || r_type == (int) R_SH_NONE
573	      || r_type < 0
574	      || r_type >= R_SH_max)
575	    continue;
576
577	  /* Ignore relocs against local symbols.  */
578	  if (r_symndx < num_local_syms)
579	    continue;
580
581	  BFD_ASSERT (r_symndx < (num_global_syms + num_local_syms));
582	  h = sym_hashes[r_symndx - num_local_syms];
583	  BFD_ASSERT (h != NULL);
584
585	  while (   h->root.type == bfd_link_hash_indirect
586		 || h->root.type == bfd_link_hash_warning)
587	    h = (struct elf_link_hash_entry *) h->root.u.i.link;
588
589	  /* If the symbol is defined there is no need to rename it.
590	     XXX - is this true ?  */
591	  if (   h->root.type == bfd_link_hash_defined
592	      || h->root.type == bfd_link_hash_defweak
593	      || h->root.type == bfd_link_hash_undefweak)
594	    continue;
595
596	  for (ptr = rename_list; ptr; ptr = ptr->next)
597	    if (h == ptr->current_hash)
598	      {
599		BFD_ASSERT (ptr->new_symndx);
600		if (DEBUG)
601		  fprintf (stderr, "convert reloc %lx from using index %ld to using index %ld\n",
602			   (long) rel->r_info, (long) ELF32_R_SYM (rel->r_info), ptr->new_symndx);
603		rel->r_info = ELF32_R_INFO (ptr->new_symndx, r_type);
604		break;
605	      }
606	}
607    }
608
609  return sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
610				  contents, relocs, local_syms, local_sections);
611}
612
613static bfd_boolean
614sh_symbian_check_directives (bfd *abfd, struct bfd_link_info *info)
615{
616  return bfd_elf32_sh_symbian_process_directives (info, abfd);
617}
618
619#define TARGET_LITTLE_SYM	bfd_elf32_shl_symbian_vec
620#define TARGET_LITTLE_NAME      "elf32-shl-symbian"
621
622#undef  elf_backend_relocate_section
623#define elf_backend_relocate_section	sh_symbian_relocate_section
624#undef  elf_backend_check_directives
625#define elf_backend_check_directives    sh_symbian_check_directives
626
627#include "elf32-target.h"
628