1
/* Renesas / SuperH specific support for Symbian 32-bit ELF files
2
Copyright 2004, 2005, 2006, 2007, 2008
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. */
397
sh_symbian_process_directives (bfd *abfd, struct bfd_link_info *info)
399
bfd_boolean result = FALSE;
401
asection * sec = bfd_get_section_by_name (abfd, ".directive");
407
sz = sec->rawsize ? sec->rawsize : sec->size;
408
contents = bfd_malloc (sz);
411
bfd_set_error (bfd_error_no_memory);
414
if (bfd_get_section_contents (abfd, sec, contents, 0, sz))
415
result = sh_symbian_process_embedded_commands (info, abfd, sec, contents);
422
/* Intercept the normal sh_relocate_section() function
423
and magle the relocs to allow for symbol renaming. */
426
sh_symbian_relocate_section (bfd * output_bfd,
427
struct bfd_link_info * info,
429
asection * input_section,
431
Elf_Internal_Rela * relocs,
432
Elf_Internal_Sym * local_syms,
433
asection ** local_sections)
435
/* When performing a final link we implement the IMPORT AS directives. */
436
if (!info->relocatable)
438
Elf_Internal_Rela * rel;
439
Elf_Internal_Rela * relend;
440
Elf_Internal_Shdr * symtab_hdr;
441
struct elf_link_hash_entry ** sym_hashes;
442
struct elf_link_hash_entry ** sym_hashes_end;
443
struct elf_link_hash_table * hash_table;
445
bfd_size_type num_global_syms;
446
unsigned long num_local_syms;
448
BFD_ASSERT (! elf_bad_symtab (input_bfd));
450
symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
451
hash_table = elf_hash_table (info);
452
num_local_syms = symtab_hdr->sh_info;
453
num_global_syms = symtab_hdr->sh_size / sizeof (Elf32_External_Sym);
454
num_global_syms -= num_local_syms;
455
sym_hashes = elf_sym_hashes (input_bfd);
456
sym_hashes_end = sym_hashes + num_global_syms;
458
/* First scan the rename table, caching the hash entry and the new index. */
459
for (ptr = rename_list; ptr; ptr = ptr->next)
461
struct elf_link_hash_entry * new_hash;
462
struct elf_link_hash_entry ** h;
464
ptr->current_hash = elf_link_hash_lookup (hash_table, ptr->current_name, FALSE, FALSE, TRUE);
466
if (ptr->current_hash == NULL)
469
fprintf (stderr, "IMPORT AS: current symbol '%s' does not exist\n", ptr->current_name);
473
new_hash = elf_link_hash_lookup (hash_table, ptr->new_name,
475
/* If we could not find the symbol then it is a new, undefined symbol.
476
Symbian want this behaviour - ie they want to be able to rename the
477
reference in a reloc from one undefined symbol to another, new and
478
undefined symbol. So we create that symbol here. */
479
if (new_hash == NULL)
481
struct bfd_link_hash_entry *bh = NULL;
482
bfd_boolean collect = get_elf_backend_data (input_bfd)->collect;
483
if (_bfd_generic_link_add_one_symbol (info, input_bfd,
484
ptr->new_name, BSF_GLOBAL,
485
bfd_und_section_ptr, 0,
486
NULL, FALSE, collect,
489
new_hash = (struct elf_link_hash_entry *) bh;
490
new_hash->type = STT_FUNC;
491
new_hash->non_elf = 0;
494
fprintf (stderr, "Created new symbol %s\n", ptr->new_name);
498
if (new_hash == NULL)
500
_bfd_error_handler (_("%B: Failed to add renamed symbol %s"),
501
input_bfd, ptr->new_name);
505
/* Convert the new_hash value into a index into the table of symbol hashes. */
506
for (h = sym_hashes; h < sym_hashes_end; h ++)
510
ptr->new_symndx = h - sym_hashes + num_local_syms;
512
fprintf (stderr, "Converted new hash to index of %ld\n", ptr->new_symndx);
516
/* If the new symbol is not in the hash table then it must be
517
because it is one of the newly created undefined symbols
518
manufactured above. So we extend the sym has table here to
519
include this extra symbol. */
520
if (h == sym_hashes_end)
522
struct elf_link_hash_entry ** new_sym_hashes;
524
/* This is not very efficient, but it works. */
526
new_sym_hashes = bfd_alloc (input_bfd, num_global_syms * sizeof * sym_hashes);
527
if (new_sym_hashes == NULL)
530
fprintf (stderr, "Out of memory extending hash table\n");
533
memcpy (new_sym_hashes, sym_hashes, (num_global_syms - 1) * sizeof * sym_hashes);
534
new_sym_hashes[num_global_syms - 1] = new_hash;
535
elf_sym_hashes (input_bfd) = sym_hashes = new_sym_hashes;
536
sym_hashes_end = sym_hashes + num_global_syms;
537
symtab_hdr->sh_size = (num_global_syms + num_local_syms) * sizeof (Elf32_External_Sym);
539
ptr->new_symndx = num_global_syms - 1 + num_local_syms;
542
fprintf (stderr, "Extended symbol hash table to insert new symbol as index %ld\n",
547
/* Walk the reloc list looking for references to renamed symbols.
548
When we find one, we alter the index in the reloc to point to the new symbol. */
549
for (rel = relocs, relend = relocs + input_section->reloc_count;
554
unsigned long r_symndx;
555
struct elf_link_hash_entry * h;
557
r_symndx = ELF32_R_SYM (rel->r_info);
558
r_type = ELF32_R_TYPE (rel->r_info);
560
/* Ignore unused relocs. */
561
if ((r_type >= (int) R_SH_GNU_VTINHERIT
562
&& r_type <= (int) R_SH_LABEL)
563
|| r_type == (int) R_SH_NONE
565
|| r_type >= R_SH_max)
568
/* Ignore relocs against local symbols. */
569
if (r_symndx < num_local_syms)
572
BFD_ASSERT (r_symndx < (num_global_syms + num_local_syms));
573
h = sym_hashes[r_symndx - num_local_syms];
574
BFD_ASSERT (h != NULL);
576
while ( h->root.type == bfd_link_hash_indirect
577
|| h->root.type == bfd_link_hash_warning)
578
h = (struct elf_link_hash_entry *) h->root.u.i.link;
580
/* If the symbol is defined there is no need to rename it.
581
XXX - is this true ? */
582
if ( h->root.type == bfd_link_hash_defined
583
|| h->root.type == bfd_link_hash_defweak
584
|| h->root.type == bfd_link_hash_undefweak)
587
for (ptr = rename_list; ptr; ptr = ptr->next)
588
if (h == ptr->current_hash)
590
BFD_ASSERT (ptr->new_symndx);
592
fprintf (stderr, "convert reloc %lx from using index %ld to using index %ld\n",
593
(unsigned long) rel->r_info,
594
(long) ELF32_R_SYM (rel->r_info), ptr->new_symndx);
595
rel->r_info = ELF32_R_INFO (ptr->new_symndx, r_type);
601
return sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
602
contents, relocs, local_syms, local_sections);
605
#define TARGET_LITTLE_SYM bfd_elf32_shl_symbian_vec
606
#define TARGET_LITTLE_NAME "elf32-shl-symbian"
608
#undef elf_backend_relocate_section
609
#define elf_backend_relocate_section sh_symbian_relocate_section
610
#undef elf_backend_check_directives
611
#define elf_backend_check_directives sh_symbian_process_directives
613
#include "elf32-target.h"