1 /* Renesas / SuperH specific support for Symbian 32-bit ELF files
2 Copyright (C) 2004-2016 Free Software Foundation, Inc.
5 This file is part of BFD, the Binary File Descriptor library.
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.
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.
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. */
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
30 //#define SYMBIAN_DEBUG 1
31 #define SYMBIAN_DEBUG 0
33 #define DIRECTIVE_HEADER "#<SYMEDIT>#\n"
34 #define DIRECTIVE_IMPORT "IMPORT "
35 #define DIRECTIVE_EXPORT "EXPORT "
36 #define DIRECTIVE_AS "AS "
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'
42 #define SKIP_UNTIL(s,e,c,m) \
45 while (s < e && *s != c) \
50 fprintf (stderr, "Corrupt directive: %s\n", m); \
58 /* Like SKIP_UNTIL except there are two terminator characters
60 #define SKIP_UNTIL2(s,e,c1,c2,m) \
63 while (s < e && *s != c1 && *s != c2) \
68 fprintf (stderr, "Corrupt directive: %s\n", m); \
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
80 #define SKIP_WHILE(s,e,c,m) \
83 while (s < e && *s == c) \
88 fprintf (stderr, "Corrupt directive: %s\n", m); \
97 typedef struct symbol_rename
99 struct symbol_rename * next;
102 struct elf_link_hash_entry * current_hash;
103 unsigned long new_symndx;
107 static symbol_rename * rename_list = NULL;
109 /* Accumulate a list of symbols to be renamed. */
112 sh_symbian_import_as (struct bfd_link_info *info, bfd * abfd,
113 char * current_name, char * new_name)
115 struct elf_link_hash_entry * new_hash;
116 symbol_rename * node;
119 fprintf (stderr, "IMPORT '%s' AS '%s'\n", current_name, new_name);
121 for (node = rename_list; node; node = node->next)
122 if (strcmp (node->current_name, current_name) == 0)
124 if (strcmp (node->new_name, new_name) == 0)
125 /* Already added to rename list. */
128 bfd_set_error (bfd_error_invalid_operation);
129 _bfd_error_handler (_("%B: IMPORT AS directive for %s conceals previous IMPORT AS"),
134 if ((node = bfd_malloc (sizeof * node)) == NULL)
137 fprintf (stderr, "IMPORT AS: No mem for new rename node\n");
141 if ((node->current_name = bfd_malloc (strlen (current_name) + 1)) == NULL)
144 fprintf (stderr, "IMPORT AS: No mem for current name field in rename node\n");
149 strcpy (node->current_name, current_name);
151 if ((node->new_name = bfd_malloc (strlen (new_name) + 1)) == NULL)
154 fprintf (stderr, "IMPORT AS: No mem for new name field in rename node\n");
155 free (node->current_name);
160 strcpy (node->new_name, new_name);
162 node->next = rename_list;
163 node->current_hash = NULL;
164 node->new_symndx = 0;
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;
177 sh_symbian_import (bfd * abfd ATTRIBUTE_UNUSED, char * name)
180 fprintf (stderr, "IMPORT '%s'\n", name);
182 /* XXX: Generate an import somehow ? */
188 sh_symbian_export (bfd * abfd ATTRIBUTE_UNUSED, char * name)
191 fprintf (stderr, "EXPORT '%s'\n", name);
193 /* XXX: Generate an export somehow ? */
198 /* Process any magic embedded commands in the .directive. section.
199 Returns TRUE upon sucecss, but if it fails it sets bfd_error and
203 sh_symbian_process_embedded_commands (struct bfd_link_info *info, bfd * abfd,
204 asection * sec, bfd_byte * contents)
208 bfd_boolean result = TRUE;
209 bfd_size_type sz = sec->rawsize ? sec->rawsize : sec->size;
211 for (s = (char *) contents, e = s + sz; s < e;)
213 char * directive = s;
217 /* I want to use "case DIRECTIVE_HEADER [0]:" here but gcc won't let me :-( */
219 if (strcmp (s, DIRECTIVE_HEADER))
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;
229 if (! CONST_STRNEQ (s, DIRECTIVE_IMPORT))
237 /* Skip the IMPORT directive. */
238 s += strlen (DIRECTIVE_IMPORT);
241 /* Find the end of the new name. */
242 while (s < e && *s != ' ' && *s != '\n')
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;
252 result = sh_symbian_import (abfd, new_name);
253 * new_name_end = name_end_char;
257 /* Remember where the name ends. */
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;
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))
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");
275 result = sh_symbian_import (abfd, new_name);
277 /* Skip past the NUL character. */
281 fprintf (stderr, "IMPORT: No NUL at end of directive\n");
287 char * current_name_end;
288 char current_name_end_char;
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");
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;
301 SKIP_WHILE (s, e, ' ', "IMPORT AS: Current name just followed by spaces");
302 /* Skip past the newline character. */
305 fprintf (stderr, "IMPORT AS: No newline at end of directive\n");
307 /* Terminate the current name after having performed the skips. */
308 * current_name_end = 0;
310 result = sh_symbian_import_as (info, abfd, current_name, new_name);
312 /* The next character should be a NUL. */
316 fprintf (stderr, "IMPORT AS: Junk at end of directive\n");
321 * current_name_end = current_name_end_char;
324 /* Restore the characters we overwrote, since
325 the .directive section will be emitted. */
326 * new_name_end = name_end_char;
331 if (! CONST_STRNEQ (s, DIRECTIVE_EXPORT))
339 /* Skip the directive. */
340 s += strlen (DIRECTIVE_EXPORT);
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 --)
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;
351 /* Skip passed the newline character. */
354 result = sh_symbian_export (abfd, name);
356 /* The next character should be a NUL. */
360 fprintf (stderr, "EXPORT: Junk at end of directive\n");
365 /* Restore the character we deleted. */
366 * name_end = name_end_char;
378 fprintf (stderr, "offset into .directive section: %ld\n",
379 (long) (directive - (char *) contents));
381 bfd_set_error (bfd_error_invalid_operation);
382 _bfd_error_handler (_("%B: Unrecognised .directive command: %s"),
392 /* Scan a bfd for a .directive section, and if found process it.
393 Returns TRUE upon success, FALSE otherwise. */
396 sh_symbian_process_directives (bfd *abfd, struct bfd_link_info *info)
398 bfd_boolean result = FALSE;
400 asection * sec = bfd_get_section_by_name (abfd, ".directive");
406 sz = sec->rawsize ? sec->rawsize : sec->size;
407 contents = bfd_malloc (sz);
410 bfd_set_error (bfd_error_no_memory);
413 if (bfd_get_section_contents (abfd, sec, contents, 0, sz))
414 result = sh_symbian_process_embedded_commands (info, abfd, sec, contents);
421 /* Intercept the normal sh_relocate_section() function
422 and magle the relocs to allow for symbol renaming. */
425 sh_symbian_relocate_section (bfd * output_bfd,
426 struct bfd_link_info * info,
428 asection * input_section,
430 Elf_Internal_Rela * relocs,
431 Elf_Internal_Sym * local_syms,
432 asection ** local_sections)
434 /* When performing a final link we implement the IMPORT AS directives. */
435 if (!bfd_link_relocatable (info))
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;
444 bfd_size_type num_global_syms;
445 unsigned long num_local_syms;
447 BFD_ASSERT (! elf_bad_symtab (input_bfd));
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;
457 /* First scan the rename table, caching the hash entry and the new index. */
458 for (ptr = rename_list; ptr; ptr = ptr->next)
460 struct elf_link_hash_entry * new_hash;
461 struct elf_link_hash_entry ** h;
463 ptr->current_hash = elf_link_hash_lookup (hash_table, ptr->current_name, FALSE, FALSE, TRUE);
465 if (ptr->current_hash == NULL)
468 fprintf (stderr, "IMPORT AS: current symbol '%s' does not exist\n", ptr->current_name);
472 new_hash = elf_link_hash_lookup (hash_table, ptr->new_name,
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)
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,
488 new_hash = (struct elf_link_hash_entry *) bh;
489 new_hash->type = STT_FUNC;
490 new_hash->non_elf = 0;
493 fprintf (stderr, "Created new symbol %s\n", ptr->new_name);
497 if (new_hash == NULL)
499 _bfd_error_handler (_("%B: Failed to add renamed symbol %s"),
500 input_bfd, ptr->new_name);
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 ++)
509 ptr->new_symndx = h - sym_hashes + num_local_syms;
511 fprintf (stderr, "Converted new hash to index of %ld\n", ptr->new_symndx);
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)
521 struct elf_link_hash_entry ** new_sym_hashes;
523 /* This is not very efficient, but it works. */
525 new_sym_hashes = bfd_alloc (input_bfd, num_global_syms * sizeof * sym_hashes);
526 if (new_sym_hashes == NULL)
529 fprintf (stderr, "Out of memory extending hash table\n");
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);
538 ptr->new_symndx = num_global_syms - 1 + num_local_syms;
541 fprintf (stderr, "Extended symbol hash table to insert new symbol as index %ld\n",
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;
553 unsigned long r_symndx;
554 struct elf_link_hash_entry * h;
556 r_symndx = ELF32_R_SYM (rel->r_info);
557 r_type = ELF32_R_TYPE (rel->r_info);
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
564 || r_type >= R_SH_max)
567 /* Ignore relocs against local symbols. */
568 if (r_symndx < num_local_syms)
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);
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;
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)
586 for (ptr = rename_list; ptr; ptr = ptr->next)
587 if (h == ptr->current_hash)
589 BFD_ASSERT (ptr->new_symndx);
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);
600 return sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
601 contents, relocs, local_syms, local_sections);
604 #define TARGET_LITTLE_SYM sh_elf32_symbian_le_vec
605 #define TARGET_LITTLE_NAME "elf32-shl-symbian"
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
612 #include "elf32-target.h"