include/
[deliverable/binutils-gdb.git] / bfd / elf32-sh-symbian.c
CommitLineData
85fbca6a 1/* Renesas / SuperH specific support for Symbian 32-bit ELF files
f075ee0c 2 Copyright 2004, 2005
85fbca6a
NC
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
1a320fbb
NC
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
85fbca6a
NC
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
96typedef struct symbol_rename
97{
98 struct symbol_rename * next;
f075ee0c
AM
99 char * current_name;
100 char * new_name;
85fbca6a
NC
101 struct elf_link_hash_entry * current_hash;
102 unsigned long new_symndx;
103}
104symbol_rename;
105
106static symbol_rename * rename_list = NULL;
107
108/* Accumulate a list of symbols to be renamed. */
109
110static bfd_boolean
111sh_symbian_import_as (struct bfd_link_info *info, bfd * abfd,
f075ee0c 112 char * current_name, char * new_name)
85fbca6a
NC
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);
d003868e
AM
128 _bfd_error_handler (_("%B: IMPORT AS directive for %s conceals previous IMPORT AS"),
129 abfd, current_name);
85fbca6a
NC
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
175static bfd_boolean
f075ee0c 176sh_symbian_import (bfd * abfd ATTRIBUTE_UNUSED, char * name)
85fbca6a
NC
177{
178 if (DEBUG)
179 fprintf (stderr, "IMPORT '%s'\n", name);
180
181 /* XXX: Generate an import somehow ? */
182
183 return TRUE;
184}
185
186static bfd_boolean
f075ee0c 187sh_symbian_export (bfd * abfd ATTRIBUTE_UNUSED, char * name)
85fbca6a
NC
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
201static bfd_boolean
202sh_symbian_process_embedded_commands (struct bfd_link_info *info, bfd * abfd,
203 asection * sec, bfd_byte * contents)
204{
f075ee0c
AM
205 char *s;
206 char *e;
85fbca6a
NC
207 bfd_boolean result = TRUE;
208 bfd_size_type sz = sec->rawsize ? sec->rawsize : sec->size;
209
f075ee0c 210 for (s = (char *) contents, e = s + sz; s < e;)
85fbca6a 211 {
f075ee0c 212 char * directive = s;
85fbca6a
NC
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 {
f075ee0c
AM
232 char * new_name;
233 char * new_name_end;
234 char name_end_char;
85fbca6a
NC
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 {
f075ee0c
AM
285 char * current_name;
286 char * current_name_end;
287 char current_name_end_char;
85fbca6a
NC
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 {
f075ee0c
AM
334 char * name;
335 char * name_end;
336 char name_end_char;
85fbca6a
NC
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)
f075ee0c
AM
377 fprintf (stderr, "offset into .directive section: %d\n",
378 directive - (char *) contents);
85fbca6a
NC
379
380 bfd_set_error (bfd_error_invalid_operation);
d003868e
AM
381 _bfd_error_handler (_("%B: Unrecognised .directive command: %s"),
382 abfd, directive);
85fbca6a
NC
383 break;
384 }
385 }
386
387 return result;
388}
389
390
391/* Scan a bfd for a .directive section, and if found process it.
392 Returns TRUE upon success, FALSE otherwise. */
393bfd_boolean bfd_elf32_sh_symbian_process_directives (struct bfd_link_info *info, bfd * abfd);
394
395bfd_boolean
396bfd_elf32_sh_symbian_process_directives (struct bfd_link_info *info, bfd * abfd)
397{
398 bfd_boolean result = FALSE;
399 bfd_byte * contents;
400 asection * sec = bfd_get_section_by_name (abfd, ".directive");
401 bfd_size_type sz;
402
403 if (!sec)
404 return TRUE;
405
406 sz = sec->rawsize ? sec->rawsize : sec->size;
407 contents = bfd_malloc (sz);
408
409 if (!contents)
410 bfd_set_error (bfd_error_no_memory);
411 else
412 {
413 if (bfd_get_section_contents (abfd, sec, contents, 0, sz))
414 result = sh_symbian_process_embedded_commands (info, abfd, sec, contents);
415 free (contents);
416 }
417
418 return result;
419}
420
421/* Intercept the normal sh_relocate_section() function
422 and magle the relocs to allow for symbol renaming. */
423
424static bfd_boolean
425sh_symbian_relocate_section (bfd * output_bfd,
426 struct bfd_link_info * info,
427 bfd * input_bfd,
428 asection * input_section,
429 bfd_byte * contents,
430 Elf_Internal_Rela * relocs,
431 Elf_Internal_Sym * local_syms,
432 asection ** local_sections)
433{
434 /* When performing a final link we implement the IMPORT AS directives. */
435 if (!info->relocatable)
436 {
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;
443 symbol_rename * ptr;
444 bfd_size_type num_global_syms;
445 unsigned long num_local_syms;
446
447 BFD_ASSERT (! elf_bad_symtab (input_bfd));
448
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;
456
457 /* First scan the rename table, caching the hash entry and the new index. */
458 for (ptr = rename_list; ptr; ptr = ptr->next)
459 {
460 struct elf_link_hash_entry * new_hash;
461 struct elf_link_hash_entry ** h;
462
463 ptr->current_hash = elf_link_hash_lookup (hash_table, ptr->current_name, FALSE, FALSE, TRUE);
464
465 if (ptr->current_hash == NULL)
466 {
467 if (DEBUG)
468 fprintf (stderr, "IMPORT AS: current symbol '%s' does not exist\n", ptr->current_name);
469 continue;
470 }
471
472 new_hash = elf_link_hash_lookup (hash_table, ptr->new_name, FALSE, FALSE, TRUE);
473
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)
479 {
480 asection * psec = bfd_und_section_ptr;
481 Elf_Internal_Sym new_sym;
482 bfd_vma new_value = 0;
483 bfd_boolean skip;
484 bfd_boolean override;
485 bfd_boolean type_change_ok;
486 bfd_boolean size_change_ok;
487
488 new_sym.st_value = 0;
489 new_sym.st_size = 0;
490 new_sym.st_name = -1;
491 new_sym.st_info = ELF_ST_INFO (STB_GLOBAL, STT_FUNC);
492 new_sym.st_other = ELF_ST_VISIBILITY (STV_DEFAULT);
493 new_sym.st_shndx = SHN_UNDEF;
494
495 if (! _bfd_elf_merge_symbol (input_bfd, info, ptr->new_name, & new_sym, & psec,
496 & new_value, & new_hash, & skip, & override, & type_change_ok,
497 & size_change_ok))
498 {
d003868e
AM
499 _bfd_error_handler (_("%B: Failed to add renamed symbol %s"),
500 input_bfd, ptr->new_name);
85fbca6a
NC
501 continue;
502 }
503 /* XXX - should we check psec, skip, override etc ? */
504
505 new_hash->root.type = bfd_link_hash_undefined;
506
507 /* Allow the symbol to become local if necessary. */
508 if (new_hash->dynindx == -1)
f5385ebf 509 new_hash->def_regular = 1;
85fbca6a
NC
510
511 if (DEBUG)
512 fprintf (stderr, "Created new symbol %s\n", ptr->new_name);
513 }
514
515 /* Convert the new_hash value into a index into the table of symbol hashes. */
516 for (h = sym_hashes; h < sym_hashes_end; h ++)
517 {
518 if (* h == new_hash)
519 {
520 ptr->new_symndx = h - sym_hashes + num_local_syms;
521 if (DEBUG)
522 fprintf (stderr, "Converted new hash to index of %ld\n", ptr->new_symndx);
523 break;
524 }
525 }
526 /* If the new symbol is not in the hash table then it must be
527 because it is one of the newly created undefined symbols
528 manufactured above. So we extend the sym has table here to
529 include this extra symbol. */
530 if (h == sym_hashes_end)
531 {
532 struct elf_link_hash_entry ** new_sym_hashes;
533
534 /* This is not very efficient, but it works. */
535 ++ num_global_syms;
536 new_sym_hashes = bfd_alloc (input_bfd, num_global_syms * sizeof * sym_hashes);
537 if (new_sym_hashes == NULL)
538 {
539 if (DEBUG)
540 fprintf (stderr, "Out of memory extending hash table\n");
541 continue;
542 }
543 memcpy (new_sym_hashes, sym_hashes, (num_global_syms - 1) * sizeof * sym_hashes);
544 new_sym_hashes[num_global_syms - 1] = new_hash;
545 elf_sym_hashes (input_bfd) = sym_hashes = new_sym_hashes;
546 sym_hashes_end = sym_hashes + num_global_syms;
547 symtab_hdr->sh_size = (num_global_syms + num_local_syms) * sizeof (Elf32_External_Sym);
548
549 ptr->new_symndx = num_global_syms - 1 + num_local_syms;
550
551 if (DEBUG)
552 fprintf (stderr, "Extended symbol hash table to insert new symbol as index %ld\n",
553 ptr->new_symndx);
554 }
555 }
556
557 /* Walk the reloc list looking for references to renamed symbols.
558 When we find one, we alter the index in the reloc to point to the new symbol. */
559 for (rel = relocs, relend = relocs + input_section->reloc_count;
560 rel < relend;
561 rel ++)
562 {
563 int r_type;
564 unsigned long r_symndx;
565 struct elf_link_hash_entry * h;
566
567 r_symndx = ELF32_R_SYM (rel->r_info);
568 r_type = ELF32_R_TYPE (rel->r_info);
569
570 /* Ignore unused relocs. */
571 if ((r_type >= (int) R_SH_GNU_VTINHERIT
572 && r_type <= (int) R_SH_LABEL)
573 || r_type == (int) R_SH_NONE
574 || r_type < 0
575 || r_type >= R_SH_max)
576 continue;
577
578 /* Ignore relocs against local symbols. */
579 if (r_symndx < num_local_syms)
580 continue;
581
582 BFD_ASSERT (r_symndx < (num_global_syms + num_local_syms));
583 h = sym_hashes[r_symndx - num_local_syms];
584 BFD_ASSERT (h != NULL);
585
586 while ( h->root.type == bfd_link_hash_indirect
587 || h->root.type == bfd_link_hash_warning)
588 h = (struct elf_link_hash_entry *) h->root.u.i.link;
589
590 /* If the symbol is defined there is no need to rename it.
591 XXX - is this true ? */
592 if ( h->root.type == bfd_link_hash_defined
593 || h->root.type == bfd_link_hash_defweak
594 || h->root.type == bfd_link_hash_undefweak)
595 continue;
596
597 for (ptr = rename_list; ptr; ptr = ptr->next)
598 if (h == ptr->current_hash)
599 {
600 BFD_ASSERT (ptr->new_symndx);
601 if (DEBUG)
602 fprintf (stderr, "convert reloc %lx from using index %ld to using index %ld\n",
603 (long) rel->r_info, (long) ELF32_R_SYM (rel->r_info), ptr->new_symndx);
604 rel->r_info = ELF32_R_INFO (ptr->new_symndx, r_type);
605 break;
606 }
607 }
608 }
609
610 return sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
611 contents, relocs, local_syms, local_sections);
612}
613
614static bfd_boolean
615sh_symbian_check_directives (bfd *abfd, struct bfd_link_info *info)
616{
617 return bfd_elf32_sh_symbian_process_directives (info, abfd);
618}
619
620#define TARGET_LITTLE_SYM bfd_elf32_shl_symbian_vec
621#define TARGET_LITTLE_NAME "elf32-shl-symbian"
622
623#undef elf_backend_relocate_section
624#define elf_backend_relocate_section sh_symbian_relocate_section
625#undef elf_backend_check_directives
626#define elf_backend_check_directives sh_symbian_check_directives
627
628#include "elf32-target.h"
This page took 0.081105 seconds and 4 git commands to generate.