1 /* Renesas / SuperH specific support for Symbian 32-bit ELF files
2 Copyright 2004, 2005, 2006, 2007
3 Free Software Foundation, Inc.
6 This file is part of BFD, the Binary File Descriptor library.
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.
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.
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. */
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
31 //#define SYMBIAN_DEBUG 1
32 #define SYMBIAN_DEBUG 0
34 #define DIRECTIVE_HEADER "#<SYMEDIT>#\n"
35 #define DIRECTIVE_IMPORT "IMPORT "
36 #define DIRECTIVE_EXPORT "EXPORT "
37 #define DIRECTIVE_AS "AS "
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'
43 #define SKIP_UNTIL(s,e,c,m) \
46 while (s < e && *s != c) \
51 fprintf (stderr, "Corrupt directive: %s\n", m); \
59 /* Like SKIP_UNTIL except there are two terminator characters
61 #define SKIP_UNTIL2(s,e,c1,c2,m) \
64 while (s < e && *s != c1 && *s != c2) \
69 fprintf (stderr, "Corrupt directive: %s\n", m); \
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
81 #define SKIP_WHILE(s,e,c,m) \
84 while (s < e && *s == c) \
89 fprintf (stderr, "Corrupt directive: %s\n", m); \
98 typedef struct symbol_rename
100 struct symbol_rename * next;
103 struct elf_link_hash_entry * current_hash;
104 unsigned long new_symndx;
108 static symbol_rename * rename_list = NULL;
110 /* Accumulate a list of symbols to be renamed. */
113 sh_symbian_import_as (struct bfd_link_info *info, bfd * abfd,
114 char * current_name, char * new_name)
116 struct elf_link_hash_entry * new_hash;
117 symbol_rename * node;
120 fprintf (stderr, "IMPORT '%s' AS '%s'\n", current_name, new_name);
122 for (node = rename_list; node; node = node->next)
123 if (strcmp (node->current_name, current_name) == 0)
125 if (strcmp (node->new_name, new_name) == 0)
126 /* Already added to rename list. */
129 bfd_set_error (bfd_error_invalid_operation);
130 _bfd_error_handler (_("%B: IMPORT AS directive for %s conceals previous IMPORT AS"),
135 if ((node = bfd_malloc (sizeof * node)) == NULL)
138 fprintf (stderr, "IMPORT AS: No mem for new rename node\n");
142 if ((node->current_name = bfd_malloc (strlen (current_name) + 1)) == NULL)
145 fprintf (stderr, "IMPORT AS: No mem for current name field in rename node\n");
150 strcpy (node->current_name, current_name);
152 if ((node->new_name = bfd_malloc (strlen (new_name) + 1)) == NULL)
155 fprintf (stderr, "IMPORT AS: No mem for new name field in rename node\n");
156 free (node->current_name);
161 strcpy (node->new_name, new_name);
163 node->next = rename_list;
164 node->current_hash = NULL;
165 node->new_symndx = 0;
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;
178 sh_symbian_import (bfd * abfd ATTRIBUTE_UNUSED, char * name)
181 fprintf (stderr, "IMPORT '%s'\n", name);
183 /* XXX: Generate an import somehow ? */
189 sh_symbian_export (bfd * abfd ATTRIBUTE_UNUSED, char * name)
192 fprintf (stderr, "EXPORT '%s'\n", name);
194 /* XXX: Generate an export somehow ? */
199 /* Process any magic embedded commands in the .directive. section.
200 Returns TRUE upon sucecss, but if it fails it sets bfd_error and
204 sh_symbian_process_embedded_commands (struct bfd_link_info *info, bfd * abfd,
205 asection * sec, bfd_byte * contents)
209 bfd_boolean result = TRUE;
210 bfd_size_type sz = sec->rawsize ? sec->rawsize : sec->size;
212 for (s = (char *) contents, e = s + sz; s < e;)
214 char * directive = s;
218 /* I want to use "case DIRECTIVE_HEADER [0]:" here but gcc won't let me :-( */
220 if (strcmp (s, DIRECTIVE_HEADER))
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;
230 if (! CONST_STRNEQ (s, DIRECTIVE_IMPORT))
238 /* Skip the IMPORT directive. */
239 s += strlen (DIRECTIVE_IMPORT);
242 /* Find the end of the new name. */
243 while (s < e && *s != ' ' && *s != '\n')
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;
253 result = sh_symbian_import (abfd, new_name);
254 * new_name_end = name_end_char;
258 /* Remember where the name ends. */
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;
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))
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");
276 result = sh_symbian_import (abfd, new_name);
278 /* Skip past the NUL character. */
282 fprintf (stderr, "IMPORT: No NUL at end of directive\n");
288 char * current_name_end;
289 char current_name_end_char;
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");
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;
302 SKIP_WHILE (s, e, ' ', "IMPORT AS: Current name just followed by spaces");
303 /* Skip past the newline character. */
306 fprintf (stderr, "IMPORT AS: No newline at end of directive\n");
308 /* Terminate the current name after having performed the skips. */
309 * current_name_end = 0;
311 result = sh_symbian_import_as (info, abfd, current_name, new_name);
313 /* The next character should be a NUL. */
317 fprintf (stderr, "IMPORT AS: Junk at end of directive\n");
322 * current_name_end = current_name_end_char;
325 /* Restore the characters we overwrote, since
326 the .directive section will be emitted. */
327 * new_name_end = name_end_char;
332 if (! CONST_STRNEQ (s, DIRECTIVE_EXPORT))
340 /* Skip the directive. */
341 s += strlen (DIRECTIVE_EXPORT);
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 --)
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;
352 /* Skip passed the newline character. */
355 result = sh_symbian_export (abfd, name);
357 /* The next character should be a NUL. */
361 fprintf (stderr, "EXPORT: Junk at end of directive\n");
366 /* Restore the character we deleted. */
367 * name_end = name_end_char;
379 fprintf (stderr, "offset into .directive section: %ld\n",
380 (long) (directive - (char *) contents));
382 bfd_set_error (bfd_error_invalid_operation);
383 _bfd_error_handler (_("%B: Unrecognised .directive command: %s"),
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);
398 bfd_elf32_sh_symbian_process_directives (struct bfd_link_info *info, bfd * abfd)
400 bfd_boolean result = FALSE;
402 asection * sec = bfd_get_section_by_name (abfd, ".directive");
408 sz = sec->rawsize ? sec->rawsize : sec->size;
409 contents = bfd_malloc (sz);
412 bfd_set_error (bfd_error_no_memory);
415 if (bfd_get_section_contents (abfd, sec, contents, 0, sz))
416 result = sh_symbian_process_embedded_commands (info, abfd, sec, contents);
423 /* Intercept the normal sh_relocate_section() function
424 and magle the relocs to allow for symbol renaming. */
427 sh_symbian_relocate_section (bfd * output_bfd,
428 struct bfd_link_info * info,
430 asection * input_section,
432 Elf_Internal_Rela * relocs,
433 Elf_Internal_Sym * local_syms,
434 asection ** local_sections)
436 /* When performing a final link we implement the IMPORT AS directives. */
437 if (!info->relocatable)
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;
446 bfd_size_type num_global_syms;
447 unsigned long num_local_syms;
449 BFD_ASSERT (! elf_bad_symtab (input_bfd));
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;
459 /* First scan the rename table, caching the hash entry and the new index. */
460 for (ptr = rename_list; ptr; ptr = ptr->next)
462 struct elf_link_hash_entry * new_hash;
463 struct elf_link_hash_entry ** h;
465 ptr->current_hash = elf_link_hash_lookup (hash_table, ptr->current_name, FALSE, FALSE, TRUE);
467 if (ptr->current_hash == NULL)
470 fprintf (stderr, "IMPORT AS: current symbol '%s' does not exist\n", ptr->current_name);
474 new_hash = elf_link_hash_lookup (hash_table, ptr->new_name, FALSE, FALSE, TRUE);
476 /* If we could not find the symbol then it is a new, undefined symbol.
477 Symbian want this behaviour - ie they want to be able to rename the
478 reference in a reloc from one undefined symbol to another, new and
479 undefined symbol. So we create that symbol here. */
480 if (new_hash == NULL)
482 asection * psec = bfd_und_section_ptr;
483 Elf_Internal_Sym new_sym;
484 bfd_vma new_value = 0;
486 bfd_boolean override;
487 bfd_boolean type_change_ok;
488 bfd_boolean size_change_ok;
490 new_sym.st_value = 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;
497 if (! _bfd_elf_merge_symbol (input_bfd, info,
498 ptr->new_name, & new_sym,
499 & psec, & new_value, NULL,
501 & override, & type_change_ok,
504 _bfd_error_handler (_("%B: Failed to add renamed symbol %s"),
505 input_bfd, ptr->new_name);
508 /* XXX - should we check psec, skip, override etc ? */
510 new_hash->root.type = bfd_link_hash_undefined;
512 /* Allow the symbol to become local if necessary. */
513 if (new_hash->dynindx == -1)
514 new_hash->def_regular = 1;
517 fprintf (stderr, "Created new symbol %s\n", ptr->new_name);
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 ++)
525 ptr->new_symndx = h - sym_hashes + num_local_syms;
527 fprintf (stderr, "Converted new hash to index of %ld\n", ptr->new_symndx);
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)
537 struct elf_link_hash_entry ** new_sym_hashes;
539 /* This is not very efficient, but it works. */
541 new_sym_hashes = bfd_alloc (input_bfd, num_global_syms * sizeof * sym_hashes);
542 if (new_sym_hashes == NULL)
545 fprintf (stderr, "Out of memory extending hash table\n");
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);
554 ptr->new_symndx = num_global_syms - 1 + num_local_syms;
557 fprintf (stderr, "Extended symbol hash table to insert new symbol as index %ld\n",
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;
569 unsigned long r_symndx;
570 struct elf_link_hash_entry * h;
572 r_symndx = ELF32_R_SYM (rel->r_info);
573 r_type = ELF32_R_TYPE (rel->r_info);
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
580 || r_type >= R_SH_max)
583 /* Ignore relocs against local symbols. */
584 if (r_symndx < num_local_syms)
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);
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;
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)
602 for (ptr = rename_list; ptr; ptr = ptr->next)
603 if (h == ptr->current_hash)
605 BFD_ASSERT (ptr->new_symndx);
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);
615 return sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
616 contents, relocs, local_syms, local_sections);
620 sh_symbian_check_directives (bfd *abfd, struct bfd_link_info *info)
622 return bfd_elf32_sh_symbian_process_directives (info, abfd);
625 #define TARGET_LITTLE_SYM bfd_elf32_shl_symbian_vec
626 #define TARGET_LITTLE_NAME "elf32-shl-symbian"
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
633 #include "elf32-target.h"