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