daily update
[external/binutils.git] / bfd / elf32-sh-symbian.c
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
98 typedef 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 }
106 symbol_rename;
107
108 static symbol_rename * rename_list = NULL;
109
110 /* Accumulate a list of symbols to be renamed.  */
111
112 static bfd_boolean
113 sh_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
177 static bfd_boolean
178 sh_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
188 static bfd_boolean
189 sh_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
203 static bfd_boolean
204 sh_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.  */
395 bfd_boolean bfd_elf32_sh_symbian_process_directives (struct bfd_link_info *info, bfd * abfd);
396
397 bfd_boolean
398 bfd_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
426 static bfd_boolean
427 sh_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
619 static bfd_boolean
620 sh_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"