Imported Upstream version 7.9
[platform/upstream/gdb.git] / bfd / elf32-sh-symbian.c
1 /* Renesas / SuperH specific support for Symbian 32-bit ELF files
2    Copyright (C) 2004-2015 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
97 typedef 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 }
105 symbol_rename;
106
107 static symbol_rename * rename_list = NULL;
108
109 /* Accumulate a list of symbols to be renamed.  */
110
111 static bfd_boolean
112 sh_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         _bfd_error_handler (_("%B: IMPORT AS directive for %s conceals previous IMPORT AS"),
130                             abfd, current_name);
131         return FALSE;
132       }
133
134   if ((node = bfd_malloc (sizeof * node)) == NULL)
135     {
136       if (SYMBIAN_DEBUG)
137         fprintf (stderr, "IMPORT AS: No mem for new rename node\n");
138       return FALSE;
139     }
140
141   if ((node->current_name = bfd_malloc (strlen (current_name) + 1)) == NULL)
142     {
143       if (SYMBIAN_DEBUG)
144         fprintf (stderr, "IMPORT AS: No mem for current name field in rename node\n");
145       free (node);
146       return FALSE;
147     }
148   else
149     strcpy (node->current_name, current_name);
150
151   if ((node->new_name = bfd_malloc (strlen (new_name) + 1)) == NULL)
152     {
153       if (SYMBIAN_DEBUG)
154         fprintf (stderr, "IMPORT AS: No mem for new name field in rename node\n");
155       free (node->current_name);
156       free (node);
157       return FALSE;
158     }
159   else
160     strcpy (node->new_name, new_name);
161
162   node->next = rename_list;
163   node->current_hash = NULL;
164   node->new_symndx = 0;
165   rename_list = node;
166
167   new_hash = elf_link_hash_lookup (elf_hash_table (info), node->new_name, TRUE, FALSE, TRUE);
168   bfd_elf_link_record_dynamic_symbol (info, new_hash);
169   if (new_hash->root.type == bfd_link_hash_new)
170     new_hash->root.type = bfd_link_hash_undefined;
171
172   return TRUE;
173 }
174
175
176 static bfd_boolean
177 sh_symbian_import (bfd * abfd ATTRIBUTE_UNUSED, char * name)
178 {
179   if (SYMBIAN_DEBUG)
180     fprintf (stderr, "IMPORT '%s'\n", name);
181
182   /* XXX: Generate an import somehow ?  */
183
184   return TRUE;
185 }
186
187 static bfd_boolean
188 sh_symbian_export (bfd * abfd ATTRIBUTE_UNUSED, char * name)
189 {
190   if (SYMBIAN_DEBUG)
191     fprintf (stderr, "EXPORT '%s'\n", name);
192
193   /* XXX: Generate an export somehow ?  */
194
195   return TRUE;
196 }
197
198 /* Process any magic embedded commands in the .directive. section.
199    Returns TRUE upon sucecss, but if it fails it sets bfd_error and
200    returns FALSE.  */
201
202 static bfd_boolean
203 sh_symbian_process_embedded_commands (struct bfd_link_info *info, bfd * abfd,
204                                       asection * sec, bfd_byte * contents)
205 {
206   char *s;
207   char *e;
208   bfd_boolean result = TRUE;
209   bfd_size_type sz = sec->rawsize ? sec->rawsize : sec->size;
210
211   for (s = (char *) contents, e = s + sz; s < e;)
212     {
213       char * directive = s;
214
215       switch (*s)
216         {
217           /* I want to use "case DIRECTIVE_HEADER [0]:" here but gcc won't let me :-(  */
218         case '#':
219           if (strcmp (s, DIRECTIVE_HEADER))
220             result = FALSE;
221           else
222             /* Just ignore the header.
223                XXX: Strictly speaking we ought to check that the header
224                is present and that it is the first thing in the file.  */
225             s += strlen (DIRECTIVE_HEADER) + 1;
226           break;
227
228         case 'I':
229           if (! CONST_STRNEQ (s, DIRECTIVE_IMPORT))
230             result = FALSE;
231           else
232             {
233               char * new_name;
234               char * new_name_end;
235               char   name_end_char;
236
237               /* Skip the IMPORT directive.  */
238               s += strlen (DIRECTIVE_IMPORT);
239
240               new_name = s;
241               /* Find the end of the new name.  */
242               while (s < e && *s != ' ' && *s != '\n')
243                 ++ s;
244               if (s >= e)
245                 {
246                   /* We have reached the end of the .directive section
247                      without encountering a string terminator.  This is
248                      allowed for IMPORT directives.  */
249                   new_name_end   = e - 1;
250                   name_end_char  = * new_name_end;
251                   * new_name_end = 0;
252                   result = sh_symbian_import (abfd, new_name);
253                   * new_name_end = name_end_char;
254                   break;
255                 }
256
257               /* Remember where the name ends.  */
258               new_name_end = s;
259               /* Skip any whitespace before the 'AS'.  */
260               SKIP_WHILE (s, e, ' ', "IMPORT: Name just followed by spaces");
261               /* Terminate the new name.  (Do this after skiping...)  */
262               name_end_char = * new_name_end;
263               * new_name_end = 0;
264
265               /* Check to see if 'AS '... is present.  If so we have an
266                  IMPORT AS directive, otherwise we have an IMPORT directive.  */
267               if (! CONST_STRNEQ (s, DIRECTIVE_AS))
268                 {
269                   /* Skip the new-line at the end of the name.  */
270                   if (SYMBIAN_DEBUG && name_end_char != '\n')
271                     fprintf (stderr, "IMPORT: No newline at end of directive\n");
272                   else
273                     s ++;
274
275                   result = sh_symbian_import (abfd, new_name);
276
277                   /* Skip past the NUL character.  */
278                   if (* s ++ != 0)
279                     {
280                       if (SYMBIAN_DEBUG)
281                         fprintf (stderr, "IMPORT: No NUL at end of directive\n");
282                     }
283                 }
284               else
285                 {
286                   char * current_name;
287                   char * current_name_end;
288                   char   current_name_end_char;
289
290                   /* Skip the 'AS '.  */
291                   s += strlen (DIRECTIVE_AS);
292                   /* Skip any white space after the 'AS '.  */
293                   SKIP_WHILE (s, e, ' ', "IMPORT AS: Nothing after AS");
294                   current_name = s;
295                   /* Find the end of the current name.  */
296                   SKIP_UNTIL2 (s, e, ' ', '\n', "IMPORT AS: No newline at the end of the current name");
297                   /* Skip (backwards) over spaces at the end of the current name.  */
298                   current_name_end = s;
299                   current_name_end_char = * current_name_end;
300
301                   SKIP_WHILE (s, e, ' ', "IMPORT AS: Current name just followed by spaces");
302                   /* Skip past the newline character.  */
303                   if (* s ++ != '\n')
304                     if (SYMBIAN_DEBUG)
305                       fprintf (stderr, "IMPORT AS: No newline at end of directive\n");
306
307                   /* Terminate the current name after having performed the skips.  */
308                   * current_name_end = 0;
309
310                   result = sh_symbian_import_as (info, abfd, current_name, new_name);
311
312                   /* The next character should be a NUL.  */
313                   if (* s != 0)
314                     {
315                       if (SYMBIAN_DEBUG)
316                         fprintf (stderr, "IMPORT AS: Junk at end of directive\n");
317                       result = FALSE;
318                     }
319                   s ++;
320
321                   * current_name_end = current_name_end_char;
322                 }
323
324               /* Restore the characters we overwrote, since
325                  the .directive section will be emitted.  */
326               * new_name_end = name_end_char;
327             }
328           break;
329
330         case 'E':
331           if (! CONST_STRNEQ (s, DIRECTIVE_EXPORT))
332             result = FALSE;
333           else
334             {
335               char * name;
336               char * name_end;
337               char   name_end_char;
338
339               /* Skip the directive.  */
340               s += strlen (DIRECTIVE_EXPORT);
341               name = s;
342               /* Find the end of the name to be exported.  */
343               SKIP_UNTIL (s, e, '\n', "EXPORT: no newline at end of directive");
344               /* Skip (backwards) over spaces at end of exported name.  */
345               for (name_end = s; name_end[-1] == ' '; name_end --)
346                 ;
347               /* name_end now points at the first character after the
348                  end of the exported name, so we can termiante it  */
349               name_end_char = * name_end;
350               * name_end = 0;
351               /* Skip passed the newline character.  */
352               s ++;
353
354               result = sh_symbian_export (abfd, name);
355
356               /* The next character should be a NUL.  */
357               if (* s != 0)
358                 {
359                   if (SYMBIAN_DEBUG)
360                     fprintf (stderr, "EXPORT: Junk at end of directive\n");
361                   result = FALSE;
362                 }
363               s++;
364
365               /* Restore the character we deleted.  */
366               * name_end = name_end_char;
367             }
368           break;
369
370         default:
371           result = FALSE;
372           break;
373         }
374
375       if (! result)
376         {
377           if (SYMBIAN_DEBUG)
378             fprintf (stderr, "offset into .directive section: %ld\n",
379                      (long) (directive - (char *) contents));
380
381           bfd_set_error (bfd_error_invalid_operation);
382           _bfd_error_handler (_("%B: Unrecognised .directive command: %s"),
383                               abfd, directive);
384           break;
385         }
386     }
387
388   return result;
389 }
390
391
392 /* Scan a bfd for a .directive section, and if found process it.
393    Returns TRUE upon success, FALSE otherwise.  */
394
395 static bfd_boolean
396 sh_symbian_process_directives (bfd *abfd, struct bfd_link_info *info)
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
424 static bfd_boolean
425 sh_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 (SYMBIAN_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,
473                                            FALSE, FALSE, TRUE);
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               struct bfd_link_hash_entry *bh = NULL;
481               bfd_boolean collect = get_elf_backend_data (input_bfd)->collect;
482               if (_bfd_generic_link_add_one_symbol (info, input_bfd,
483                                                     ptr->new_name, BSF_GLOBAL,
484                                                     bfd_und_section_ptr, 0,
485                                                     NULL, FALSE, collect,
486                                                     &bh))
487                 {
488                   new_hash = (struct elf_link_hash_entry *) bh;
489                   new_hash->type = STT_FUNC;
490                   new_hash->non_elf = 0;
491
492                   if (SYMBIAN_DEBUG)
493                     fprintf (stderr, "Created new symbol %s\n", ptr->new_name);
494                 }
495             }
496
497           if (new_hash == NULL)
498             {
499               _bfd_error_handler (_("%B: Failed to add renamed symbol %s"),
500                                   input_bfd, ptr->new_name);
501               continue;
502             }
503
504           /* Convert the new_hash value into a index into the table of symbol hashes.  */
505           for (h = sym_hashes; h < sym_hashes_end; h ++)
506             {
507               if (* h == new_hash)
508                 {
509                   ptr->new_symndx = h - sym_hashes + num_local_syms;
510                   if (SYMBIAN_DEBUG)
511                     fprintf (stderr, "Converted new hash to index of %ld\n", ptr->new_symndx);
512                   break;
513                 }
514             }
515           /* If the new symbol is not in the hash table then it must be
516              because it is one of the newly created undefined symbols
517              manufactured above.  So we extend the sym has table here to
518              include this extra symbol.  */
519           if (h == sym_hashes_end)
520             {
521               struct elf_link_hash_entry **  new_sym_hashes;
522
523               /* This is not very efficient, but it works.  */
524               ++ num_global_syms;
525               new_sym_hashes = bfd_alloc (input_bfd, num_global_syms * sizeof * sym_hashes);
526               if (new_sym_hashes == NULL)
527                 {
528                   if (SYMBIAN_DEBUG)
529                     fprintf (stderr, "Out of memory extending hash table\n");
530                   continue;
531                 }
532               memcpy (new_sym_hashes, sym_hashes, (num_global_syms - 1) * sizeof * sym_hashes);
533               new_sym_hashes[num_global_syms - 1] = new_hash;
534               elf_sym_hashes (input_bfd) = sym_hashes = new_sym_hashes;
535               sym_hashes_end = sym_hashes + num_global_syms;
536               symtab_hdr->sh_size  = (num_global_syms + num_local_syms) * sizeof (Elf32_External_Sym);
537
538               ptr->new_symndx = num_global_syms - 1 + num_local_syms;
539
540               if (SYMBIAN_DEBUG)
541                 fprintf (stderr, "Extended symbol hash table to insert new symbol as index %ld\n",
542                          ptr->new_symndx);
543             }
544         }
545
546       /* Walk the reloc list looking for references to renamed symbols.
547          When we find one, we alter the index in the reloc to point to the new symbol.  */
548       for (rel = relocs, relend = relocs + input_section->reloc_count;
549            rel < relend;
550            rel ++)
551         {
552           int                          r_type;
553           unsigned long                r_symndx;
554           struct elf_link_hash_entry * h;
555
556           r_symndx = ELF32_R_SYM (rel->r_info);
557           r_type = ELF32_R_TYPE (rel->r_info);
558
559           /* Ignore unused relocs.  */
560           if ((r_type >= (int) R_SH_GNU_VTINHERIT
561                && r_type <= (int) R_SH_LABEL)
562               || r_type == (int) R_SH_NONE
563               || r_type < 0
564               || r_type >= R_SH_max)
565             continue;
566
567           /* Ignore relocs against local symbols.  */
568           if (r_symndx < num_local_syms)
569             continue;
570
571           BFD_ASSERT (r_symndx < (num_global_syms + num_local_syms));
572           h = sym_hashes[r_symndx - num_local_syms];
573           BFD_ASSERT (h != NULL);
574
575           while (   h->root.type == bfd_link_hash_indirect
576                  || h->root.type == bfd_link_hash_warning)
577             h = (struct elf_link_hash_entry *) h->root.u.i.link;
578
579           /* If the symbol is defined there is no need to rename it.
580              XXX - is this true ?  */
581           if (   h->root.type == bfd_link_hash_defined
582               || h->root.type == bfd_link_hash_defweak
583               || h->root.type == bfd_link_hash_undefweak)
584             continue;
585
586           for (ptr = rename_list; ptr; ptr = ptr->next)
587             if (h == ptr->current_hash)
588               {
589                 BFD_ASSERT (ptr->new_symndx);
590                 if (SYMBIAN_DEBUG)
591                   fprintf (stderr, "convert reloc %lx from using index %ld to using index %ld\n",
592                            (unsigned long) rel->r_info,
593                            (long) ELF32_R_SYM (rel->r_info), ptr->new_symndx);
594                 rel->r_info = ELF32_R_INFO (ptr->new_symndx, r_type);
595                 break;
596               }
597         }
598     }
599
600   return sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
601                                   contents, relocs, local_syms, local_sections);
602 }
603
604 #define TARGET_LITTLE_SYM       sh_elf32_symbian_le_vec
605 #define TARGET_LITTLE_NAME      "elf32-shl-symbian"
606
607 #undef  elf_backend_relocate_section
608 #define elf_backend_relocate_section    sh_symbian_relocate_section
609 #undef  elf_backend_check_directives
610 #define elf_backend_check_directives    sh_symbian_process_directives
611
612 #include "elf32-target.h"