85c26f357f8da7b531855e2a8e67e263c6d60767
[deliverable/binutils-gdb.git] / bfd / elf32-sh-symbian.c
1 /* Renesas / SuperH specific support for Symbian 32-bit ELF files
2 Copyright 2004, 2005, 2006, 2007, 2008
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
396 static bfd_boolean
397 sh_symbian_process_directives (bfd *abfd, struct bfd_link_info *info)
398 {
399 bfd_boolean result = FALSE;
400 bfd_byte * contents;
401 asection * sec = bfd_get_section_by_name (abfd, ".directive");
402 bfd_size_type sz;
403
404 if (!sec)
405 return TRUE;
406
407 sz = sec->rawsize ? sec->rawsize : sec->size;
408 contents = bfd_malloc (sz);
409
410 if (!contents)
411 bfd_set_error (bfd_error_no_memory);
412 else
413 {
414 if (bfd_get_section_contents (abfd, sec, contents, 0, sz))
415 result = sh_symbian_process_embedded_commands (info, abfd, sec, contents);
416 free (contents);
417 }
418
419 return result;
420 }
421
422 /* Intercept the normal sh_relocate_section() function
423 and magle the relocs to allow for symbol renaming. */
424
425 static bfd_boolean
426 sh_symbian_relocate_section (bfd * output_bfd,
427 struct bfd_link_info * info,
428 bfd * input_bfd,
429 asection * input_section,
430 bfd_byte * contents,
431 Elf_Internal_Rela * relocs,
432 Elf_Internal_Sym * local_syms,
433 asection ** local_sections)
434 {
435 /* When performing a final link we implement the IMPORT AS directives. */
436 if (!info->relocatable)
437 {
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;
444 symbol_rename * ptr;
445 bfd_size_type num_global_syms;
446 unsigned long num_local_syms;
447
448 BFD_ASSERT (! elf_bad_symtab (input_bfd));
449
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;
457
458 /* First scan the rename table, caching the hash entry and the new index. */
459 for (ptr = rename_list; ptr; ptr = ptr->next)
460 {
461 struct elf_link_hash_entry * new_hash;
462 struct elf_link_hash_entry ** h;
463
464 ptr->current_hash = elf_link_hash_lookup (hash_table, ptr->current_name, FALSE, FALSE, TRUE);
465
466 if (ptr->current_hash == NULL)
467 {
468 if (SYMBIAN_DEBUG)
469 fprintf (stderr, "IMPORT AS: current symbol '%s' does not exist\n", ptr->current_name);
470 continue;
471 }
472
473 new_hash = elf_link_hash_lookup (hash_table, ptr->new_name,
474 FALSE, FALSE, TRUE);
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)
480 {
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,
487 &bh))
488 {
489 new_hash = (struct elf_link_hash_entry *) bh;
490 new_hash->type = STT_FUNC;
491 new_hash->non_elf = 0;
492
493 if (SYMBIAN_DEBUG)
494 fprintf (stderr, "Created new symbol %s\n", ptr->new_name);
495 }
496 }
497
498 if (new_hash == NULL)
499 {
500 _bfd_error_handler (_("%B: Failed to add renamed symbol %s"),
501 input_bfd, ptr->new_name);
502 continue;
503 }
504
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 ++)
507 {
508 if (* h == new_hash)
509 {
510 ptr->new_symndx = h - sym_hashes + num_local_syms;
511 if (SYMBIAN_DEBUG)
512 fprintf (stderr, "Converted new hash to index of %ld\n", ptr->new_symndx);
513 break;
514 }
515 }
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)
521 {
522 struct elf_link_hash_entry ** new_sym_hashes;
523
524 /* This is not very efficient, but it works. */
525 ++ num_global_syms;
526 new_sym_hashes = bfd_alloc (input_bfd, num_global_syms * sizeof * sym_hashes);
527 if (new_sym_hashes == NULL)
528 {
529 if (SYMBIAN_DEBUG)
530 fprintf (stderr, "Out of memory extending hash table\n");
531 continue;
532 }
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);
538
539 ptr->new_symndx = num_global_syms - 1 + num_local_syms;
540
541 if (SYMBIAN_DEBUG)
542 fprintf (stderr, "Extended symbol hash table to insert new symbol as index %ld\n",
543 ptr->new_symndx);
544 }
545 }
546
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;
550 rel < relend;
551 rel ++)
552 {
553 int r_type;
554 unsigned long r_symndx;
555 struct elf_link_hash_entry * h;
556
557 r_symndx = ELF32_R_SYM (rel->r_info);
558 r_type = ELF32_R_TYPE (rel->r_info);
559
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
564 || r_type < 0
565 || r_type >= R_SH_max)
566 continue;
567
568 /* Ignore relocs against local symbols. */
569 if (r_symndx < num_local_syms)
570 continue;
571
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);
575
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;
579
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)
585 continue;
586
587 for (ptr = rename_list; ptr; ptr = ptr->next)
588 if (h == ptr->current_hash)
589 {
590 BFD_ASSERT (ptr->new_symndx);
591 if (SYMBIAN_DEBUG)
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);
596 break;
597 }
598 }
599 }
600
601 return sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
602 contents, relocs, local_syms, local_sections);
603 }
604
605 #define TARGET_LITTLE_SYM bfd_elf32_shl_symbian_vec
606 #define TARGET_LITTLE_NAME "elf32-shl-symbian"
607
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
612
613 #include "elf32-target.h"
This page took 0.059342 seconds and 4 git commands to generate.