OSDN Git Service

Rename sh-symbian-elf toolchain to sh-*-symbianelf
[pf3gnuchains/pf3gnuchains3x.git] / bfd / elf32-sh-symbian.c
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
96 typedef 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 }
104 symbol_rename;
105
106 static symbol_rename * rename_list = NULL;
107
108 /* Accumulate a list of symbols to be renamed.  */
109
110 static bfd_boolean
111 sh_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 (_("%s: IMPORT AS directive for %s conceals previous IMPORT AS"),
129                             bfd_archive_filename (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
175 static bfd_boolean
176 sh_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
186 static bfd_boolean
187 sh_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
201 static bfd_boolean
202 sh_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 (_("%s: Unrecognised .directive command: %s"),
381                               bfd_archive_filename (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.  */
392 bfd_boolean bfd_elf32_sh_symbian_process_directives (struct bfd_link_info *info, bfd * abfd);
393
394 bfd_boolean
395 bfd_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
423 static bfd_boolean
424 sh_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 (_("%s: Failed to add renamed symbol %s"),
499                                       bfd_archive_filename (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->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
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
613 static bfd_boolean
614 sh_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"