Add support for sh-symbian-elf target
[binutils-gdb.git] / bfd / elf32-sh-symbian.c
1 /* Renesas / SuperH specific support for Symbian 32-bit ELF files
2 Copyright 2004
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
24 #include "elf32-sh.c"
25
26
27 //#define DEBUG 1
28 #define DEBUG 0
29
30 #define DIRECTIVE_HEADER "#<SYMEDIT>#\n"
31 #define DIRECTIVE_IMPORT "IMPORT "
32 #define DIRECTIVE_EXPORT "EXPORT "
33 #define DIRECTIVE_AS "AS "
34
35 /* Macro to advance 's' until either it reaches 'e' or the
36 character pointed to by 's' is equal to 'c'. If 'e' is
37 reached and DEBUG is enabled then the error message 'm'
38 is displayed. */
39 #define SKIP_UNTIL(s,e,c,m) \
40 do \
41 { \
42 while (s < e && *s != c) \
43 ++ s; \
44 if (s >= e) \
45 { \
46 if (DEBUG) \
47 fprintf (stderr, "Corrupt directive: %s\n", m); \
48 result = FALSE; \
49 } \
50 } \
51 while (0); \
52 if (!result) \
53 break;
54
55 /* Like SKIP_UNTIL except there are two terminator characters
56 c1 and c2. */
57 #define SKIP_UNTIL2(s,e,c1,c2,m) \
58 do \
59 { \
60 while (s < e && *s != c1 && *s != c2) \
61 ++ s; \
62 if (s >= e) \
63 { \
64 if (DEBUG) \
65 fprintf (stderr, "Corrupt directive: %s\n", m); \
66 result = FALSE; \
67 } \
68 } \
69 while (0); \
70 if (!result) \
71 break;
72
73 /* Macro to advance 's' until either it reaches 'e' or the
74 character pointed to by 's' is not equal to 'c'. If 'e'
75 is reached and DEBUG is enabled then the error message
76 'm' is displayed. */
77 #define SKIP_WHILE(s,e,c,m) \
78 do \
79 { \
80 while (s < e && *s == c) \
81 ++ s; \
82 if (s >= e) \
83 { \
84 if (DEBUG) \
85 fprintf (stderr, "Corrupt directive: %s\n", m); \
86 result = FALSE; \
87 } \
88 } \
89 while (0); \
90 if (!result) \
91 break;
92
93
94 typedef struct symbol_rename
95 {
96 struct symbol_rename * next;
97 bfd_byte * current_name;
98 bfd_byte * new_name;
99 struct elf_link_hash_entry * current_hash;
100 unsigned long new_symndx;
101 }
102 symbol_rename;
103
104 static symbol_rename * rename_list = NULL;
105
106 /* Accumulate a list of symbols to be renamed. */
107
108 static bfd_boolean
109 sh_symbian_import_as (struct bfd_link_info *info, bfd * abfd,
110 bfd_byte * current_name, bfd_byte * new_name)
111 {
112 struct elf_link_hash_entry * new_hash;
113 symbol_rename * node;
114
115 if (DEBUG)
116 fprintf (stderr, "IMPORT '%s' AS '%s'\n", current_name, new_name);
117
118 for (node = rename_list; node; node = node->next)
119 if (strcmp (node->current_name, current_name) == 0)
120 {
121 if (strcmp (node->new_name, new_name) == 0)
122 /* Already added to rename list. */
123 return TRUE;
124
125 bfd_set_error (bfd_error_invalid_operation);
126 _bfd_error_handler (_("%s: IMPORT AS directive for %s conceals previous IMPORT AS"),
127 bfd_archive_filename (abfd), current_name);
128 return FALSE;
129 }
130
131 if ((node = bfd_malloc (sizeof * node)) == NULL)
132 {
133 if (DEBUG)
134 fprintf (stderr, "IMPORT AS: No mem for new rename node\n");
135 return FALSE;
136 }
137
138 if ((node->current_name = bfd_malloc (strlen (current_name) + 1)) == NULL)
139 {
140 if (DEBUG)
141 fprintf (stderr, "IMPORT AS: No mem for current name field in rename node\n");
142 free (node);
143 return FALSE;
144 }
145 else
146 strcpy (node->current_name, current_name);
147
148 if ((node->new_name = bfd_malloc (strlen (new_name) + 1)) == NULL)
149 {
150 if (DEBUG)
151 fprintf (stderr, "IMPORT AS: No mem for new name field in rename node\n");
152 free (node->current_name);
153 free (node);
154 return FALSE;
155 }
156 else
157 strcpy (node->new_name, new_name);
158
159 node->next = rename_list;
160 node->current_hash = NULL;
161 node->new_symndx = 0;
162 rename_list = node;
163
164 new_hash = elf_link_hash_lookup (elf_hash_table (info), node->new_name, TRUE, FALSE, TRUE);
165 bfd_elf_link_record_dynamic_symbol (info, new_hash);
166 if (new_hash->root.type == bfd_link_hash_new)
167 new_hash->root.type = bfd_link_hash_undefined;
168
169 return TRUE;
170 }
171
172
173 static bfd_boolean
174 sh_symbian_import (bfd * abfd ATTRIBUTE_UNUSED, bfd_byte * name)
175 {
176 if (DEBUG)
177 fprintf (stderr, "IMPORT '%s'\n", name);
178
179 /* XXX: Generate an import somehow ? */
180
181 return TRUE;
182 }
183
184 static bfd_boolean
185 sh_symbian_export (bfd * abfd ATTRIBUTE_UNUSED, bfd_byte * name)
186 {
187 if (DEBUG)
188 fprintf (stderr, "EXPORT '%s'\n", name);
189
190 /* XXX: Generate an export somehow ? */
191
192 return TRUE;
193 }
194
195 /* Process any magic embedded commands in the .directive. section.
196 Returns TRUE upon sucecss, but if it fails it sets bfd_error and
197 returns FALSE. */
198
199 static bfd_boolean
200 sh_symbian_process_embedded_commands (struct bfd_link_info *info, bfd * abfd,
201 asection * sec, bfd_byte * contents)
202 {
203 bfd_byte *s;
204 bfd_byte *e;
205 bfd_boolean result = TRUE;
206 bfd_size_type sz = sec->rawsize ? sec->rawsize : sec->size;
207
208 for (s = contents, e = s + sz; s < e;)
209 {
210 bfd_byte * directive = s;
211
212 switch (*s)
213 {
214 /* I want to use "case DIRECTIVE_HEADER [0]:" here but gcc won't let me :-( */
215 case '#':
216 if (strcmp (s, DIRECTIVE_HEADER))
217 result = FALSE;
218 else
219 /* Just ignore the header.
220 XXX: Strictly speaking we ought to check that the header
221 is present and that it is the first thing in the file. */
222 s += strlen (DIRECTIVE_HEADER) + 1;
223 break;
224
225 case 'I':
226 if (strncmp (s, DIRECTIVE_IMPORT, strlen (DIRECTIVE_IMPORT)))
227 result = FALSE;
228 else
229 {
230 bfd_byte * new_name;
231 bfd_byte * new_name_end;
232 bfd_byte name_end_char;
233
234 /* Skip the IMPORT directive. */
235 s += strlen (DIRECTIVE_IMPORT);
236
237 new_name = s;
238 /* Find the end of the new name. */
239 while (s < e && *s != ' ' && *s != '\n')
240 ++ s;
241 if (s >= e)
242 {
243 /* We have reached the end of the .directive section
244 without encountering a string terminator. This is
245 allowed for IMPORT directives. */
246 new_name_end = e - 1;
247 name_end_char = * new_name_end;
248 * new_name_end = 0;
249 result = sh_symbian_import (abfd, new_name);
250 * new_name_end = name_end_char;
251 break;
252 }
253
254 /* Remember where the name ends. */
255 new_name_end = s;
256 /* Skip any whitespace before the 'AS'. */
257 SKIP_WHILE (s, e, ' ', "IMPORT: Name just followed by spaces");
258 /* Terminate the new name. (Do this after skiping...) */
259 name_end_char = * new_name_end;
260 * new_name_end = 0;
261
262 /* Check to see if 'AS '... is present. If se we have an IMPORT AS
263 directive, otherwise we have an IMPORT directive. */
264 if (strncmp (s, DIRECTIVE_AS, strlen (DIRECTIVE_AS)))
265 {
266 /* Skip the new-line at the end of the name. */
267 if (DEBUG && name_end_char != '\n')
268 fprintf (stderr, "IMPORT: No newline at end of directive\n");
269 else
270 s ++;
271
272 result = sh_symbian_import (abfd, new_name);
273
274 /* Skip past the NUL character. */
275 if (* s ++ != 0)
276 {
277 if (DEBUG)
278 fprintf (stderr, "IMPORT: No NUL at end of directive\n");
279 }
280 }
281 else
282 {
283 bfd_byte * current_name;
284 bfd_byte * current_name_end;
285 bfd_byte current_name_end_char;
286
287 /* Skip the 'AS '. */
288 s += strlen (DIRECTIVE_AS);
289 /* Skip any white space after the 'AS '. */
290 SKIP_WHILE (s, e, ' ', "IMPORT AS: Nothing after AS");
291 current_name = s;
292 /* Find the end of the current name. */
293 SKIP_UNTIL2 (s, e, ' ', '\n', "IMPORT AS: No newline at the end of the current name");
294 /* Skip (backwards) over spaces at the end of the current name. */
295 current_name_end = s;
296 current_name_end_char = * current_name_end;
297
298 SKIP_WHILE (s, e, ' ', "IMPORT AS: Current name just followed by spaces");
299 /* Skip past the newline character. */
300 if (* s ++ != '\n')
301 if (DEBUG)
302 fprintf (stderr, "IMPORT AS: No newline at end of directive\n");
303
304 /* Terminate the current name after having performed the skips. */
305 * current_name_end = 0;
306
307 result = sh_symbian_import_as (info, abfd, current_name, new_name);
308
309 /* The next character should be a NUL. */
310 if (* s != 0)
311 {
312 if (DEBUG)
313 fprintf (stderr, "IMPORT AS: Junk at end of directive\n");
314 result = FALSE;
315 }
316 s ++;
317
318 * current_name_end = current_name_end_char;
319 }
320
321 /* Restore the characters we overwrote, since
322 the .directive section will be emitted. */
323 * new_name_end = name_end_char;
324 }
325 break;
326
327 case 'E':
328 if (strncmp (s, DIRECTIVE_EXPORT, strlen (DIRECTIVE_EXPORT)))
329 result = FALSE;
330 else
331 {
332 bfd_byte * name;
333 bfd_byte * name_end;
334 bfd_byte name_end_char;
335
336 /* Skip the directive. */
337 s += strlen (DIRECTIVE_EXPORT);
338 name = s;
339 /* Find the end of the name to be exported. */
340 SKIP_UNTIL (s, e, '\n', "EXPORT: no newline at end of directive");
341 /* Skip (backwards) over spaces at end of exported name. */
342 for (name_end = s; name_end[-1] == ' '; name_end --)
343 ;
344 /* name_end now points at the first character after the
345 end of the exported name, so we can termiante it */
346 name_end_char = * name_end;
347 * name_end = 0;
348 /* Skip passed the newline character. */
349 s ++;
350
351 result = sh_symbian_export (abfd, name);
352
353 /* The next character should be a NUL. */
354 if (* s != 0)
355 {
356 if (DEBUG)
357 fprintf (stderr, "EXPORT: Junk at end of directive\n");
358 result = FALSE;
359 }
360 s++;
361
362 /* Restore the character we deleted. */
363 * name_end = name_end_char;
364 }
365 break;
366
367 default:
368 result = FALSE;
369 break;
370 }
371
372 if (! result)
373 {
374 if (DEBUG)
375 fprintf (stderr, "offset into .directive section: %d\n", directive - contents);
376
377 bfd_set_error (bfd_error_invalid_operation);
378 _bfd_error_handler (_("%s: Unrecognised .directive command: %s"),
379 bfd_archive_filename (abfd), directive);
380 break;
381 }
382 }
383
384 return result;
385 }
386
387
388 /* Scan a bfd for a .directive section, and if found process it.
389 Returns TRUE upon success, FALSE otherwise. */
390 bfd_boolean bfd_elf32_sh_symbian_process_directives (struct bfd_link_info *info, bfd * abfd);
391
392 bfd_boolean
393 bfd_elf32_sh_symbian_process_directives (struct bfd_link_info *info, bfd * abfd)
394 {
395 bfd_boolean result = FALSE;
396 bfd_byte * contents;
397 asection * sec = bfd_get_section_by_name (abfd, ".directive");
398 bfd_size_type sz;
399
400 if (!sec)
401 return TRUE;
402
403 sz = sec->rawsize ? sec->rawsize : sec->size;
404 contents = bfd_malloc (sz);
405
406 if (!contents)
407 bfd_set_error (bfd_error_no_memory);
408 else
409 {
410 if (bfd_get_section_contents (abfd, sec, contents, 0, sz))
411 result = sh_symbian_process_embedded_commands (info, abfd, sec, contents);
412 free (contents);
413 }
414
415 return result;
416 }
417
418 /* Intercept the normal sh_relocate_section() function
419 and magle the relocs to allow for symbol renaming. */
420
421 static bfd_boolean
422 sh_symbian_relocate_section (bfd * output_bfd,
423 struct bfd_link_info * info,
424 bfd * input_bfd,
425 asection * input_section,
426 bfd_byte * contents,
427 Elf_Internal_Rela * relocs,
428 Elf_Internal_Sym * local_syms,
429 asection ** local_sections)
430 {
431 /* When performing a final link we implement the IMPORT AS directives. */
432 if (!info->relocatable)
433 {
434 Elf_Internal_Rela * rel;
435 Elf_Internal_Rela * relend;
436 Elf_Internal_Shdr * symtab_hdr;
437 struct elf_link_hash_entry ** sym_hashes;
438 struct elf_link_hash_entry ** sym_hashes_end;
439 struct elf_link_hash_table * hash_table;
440 symbol_rename * ptr;
441 bfd_size_type num_global_syms;
442 unsigned long num_local_syms;
443
444 BFD_ASSERT (! elf_bad_symtab (input_bfd));
445
446 symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
447 hash_table = elf_hash_table (info);
448 num_local_syms = symtab_hdr->sh_info;
449 num_global_syms = symtab_hdr->sh_size / sizeof (Elf32_External_Sym);
450 num_global_syms -= num_local_syms;
451 sym_hashes = elf_sym_hashes (input_bfd);
452 sym_hashes_end = sym_hashes + num_global_syms;
453
454 /* First scan the rename table, caching the hash entry and the new index. */
455 for (ptr = rename_list; ptr; ptr = ptr->next)
456 {
457 struct elf_link_hash_entry * new_hash;
458 struct elf_link_hash_entry ** h;
459
460 ptr->current_hash = elf_link_hash_lookup (hash_table, ptr->current_name, FALSE, FALSE, TRUE);
461
462 if (ptr->current_hash == NULL)
463 {
464 if (DEBUG)
465 fprintf (stderr, "IMPORT AS: current symbol '%s' does not exist\n", ptr->current_name);
466 continue;
467 }
468
469 new_hash = elf_link_hash_lookup (hash_table, ptr->new_name, FALSE, FALSE, TRUE);
470
471 /* If we could not find the symbol then it is a new, undefined symbol.
472 Symbian want this behaviour - ie they want to be able to rename the
473 reference in a reloc from one undefined symbol to another, new and
474 undefined symbol. So we create that symbol here. */
475 if (new_hash == NULL)
476 {
477 asection * psec = bfd_und_section_ptr;
478 Elf_Internal_Sym new_sym;
479 bfd_vma new_value = 0;
480 bfd_boolean skip;
481 bfd_boolean override;
482 bfd_boolean type_change_ok;
483 bfd_boolean size_change_ok;
484
485 new_sym.st_value = 0;
486 new_sym.st_size = 0;
487 new_sym.st_name = -1;
488 new_sym.st_info = ELF_ST_INFO (STB_GLOBAL, STT_FUNC);
489 new_sym.st_other = ELF_ST_VISIBILITY (STV_DEFAULT);
490 new_sym.st_shndx = SHN_UNDEF;
491
492 if (! _bfd_elf_merge_symbol (input_bfd, info, ptr->new_name, & new_sym, & psec,
493 & new_value, & new_hash, & skip, & override, & type_change_ok,
494 & size_change_ok))
495 {
496 _bfd_error_handler (_("%s: Failed to add renamed symbol %s"),
497 bfd_archive_filename (input_bfd), ptr->new_name);
498 continue;
499 }
500 /* XXX - should we check psec, skip, override etc ? */
501
502 new_hash->root.type = bfd_link_hash_undefined;
503
504 /* Allow the symbol to become local if necessary. */
505 if (new_hash->dynindx == -1)
506 new_hash->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
507
508 if (DEBUG)
509 fprintf (stderr, "Created new symbol %s\n", ptr->new_name);
510 }
511
512 /* Convert the new_hash value into a index into the table of symbol hashes. */
513 for (h = sym_hashes; h < sym_hashes_end; h ++)
514 {
515 if (* h == new_hash)
516 {
517 ptr->new_symndx = h - sym_hashes + num_local_syms;
518 if (DEBUG)
519 fprintf (stderr, "Converted new hash to index of %ld\n", ptr->new_symndx);
520 break;
521 }
522 }
523 /* If the new symbol is not in the hash table then it must be
524 because it is one of the newly created undefined symbols
525 manufactured above. So we extend the sym has table here to
526 include this extra symbol. */
527 if (h == sym_hashes_end)
528 {
529 struct elf_link_hash_entry ** new_sym_hashes;
530
531 /* This is not very efficient, but it works. */
532 ++ num_global_syms;
533 new_sym_hashes = bfd_alloc (input_bfd, num_global_syms * sizeof * sym_hashes);
534 if (new_sym_hashes == NULL)
535 {
536 if (DEBUG)
537 fprintf (stderr, "Out of memory extending hash table\n");
538 continue;
539 }
540 memcpy (new_sym_hashes, sym_hashes, (num_global_syms - 1) * sizeof * sym_hashes);
541 new_sym_hashes[num_global_syms - 1] = new_hash;
542 elf_sym_hashes (input_bfd) = sym_hashes = new_sym_hashes;
543 sym_hashes_end = sym_hashes + num_global_syms;
544 symtab_hdr->sh_size = (num_global_syms + num_local_syms) * sizeof (Elf32_External_Sym);
545
546 ptr->new_symndx = num_global_syms - 1 + num_local_syms;
547
548 if (DEBUG)
549 fprintf (stderr, "Extended symbol hash table to insert new symbol as index %ld\n",
550 ptr->new_symndx);
551 }
552 }
553
554 /* Walk the reloc list looking for references to renamed symbols.
555 When we find one, we alter the index in the reloc to point to the new symbol. */
556 for (rel = relocs, relend = relocs + input_section->reloc_count;
557 rel < relend;
558 rel ++)
559 {
560 int r_type;
561 unsigned long r_symndx;
562 struct elf_link_hash_entry * h;
563
564 r_symndx = ELF32_R_SYM (rel->r_info);
565 r_type = ELF32_R_TYPE (rel->r_info);
566
567 /* Ignore unused relocs. */
568 if ((r_type >= (int) R_SH_GNU_VTINHERIT
569 && r_type <= (int) R_SH_LABEL)
570 || r_type == (int) R_SH_NONE
571 || r_type < 0
572 || r_type >= R_SH_max)
573 continue;
574
575 /* Ignore relocs against local symbols. */
576 if (r_symndx < num_local_syms)
577 continue;
578
579 BFD_ASSERT (r_symndx < (num_global_syms + num_local_syms));
580 h = sym_hashes[r_symndx - num_local_syms];
581 BFD_ASSERT (h != NULL);
582
583 while ( h->root.type == bfd_link_hash_indirect
584 || h->root.type == bfd_link_hash_warning)
585 h = (struct elf_link_hash_entry *) h->root.u.i.link;
586
587 /* If the symbol is defined there is no need to rename it.
588 XXX - is this true ? */
589 if ( h->root.type == bfd_link_hash_defined
590 || h->root.type == bfd_link_hash_defweak
591 || h->root.type == bfd_link_hash_undefweak)
592 continue;
593
594 for (ptr = rename_list; ptr; ptr = ptr->next)
595 if (h == ptr->current_hash)
596 {
597 BFD_ASSERT (ptr->new_symndx);
598 if (DEBUG)
599 fprintf (stderr, "convert reloc %lx from using index %ld to using index %ld\n",
600 (long) rel->r_info, (long) ELF32_R_SYM (rel->r_info), ptr->new_symndx);
601 rel->r_info = ELF32_R_INFO (ptr->new_symndx, r_type);
602 break;
603 }
604 }
605 }
606
607 return sh_elf_relocate_section (output_bfd, info, input_bfd, input_section,
608 contents, relocs, local_syms, local_sections);
609 }
610
611 static bfd_boolean
612 sh_symbian_check_directives (bfd *abfd, struct bfd_link_info *info)
613 {
614 return bfd_elf32_sh_symbian_process_directives (info, abfd);
615 }
616
617 #define TARGET_LITTLE_SYM bfd_elf32_shl_symbian_vec
618 #define TARGET_LITTLE_NAME "elf32-shl-symbian"
619
620 #undef elf_backend_relocate_section
621 #define elf_backend_relocate_section sh_symbian_relocate_section
622 #undef elf_backend_check_directives
623 #define elf_backend_check_directives sh_symbian_check_directives
624
625 #include "elf32-target.h"