| 1 |
/* SPU specific support for 32-bit ELF |
/* SPU specific support for 32-bit ELF |
| 2 |
|
|
| 3 |
Copyright 2006, 2007, 2008 Free Software Foundation, Inc. |
Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc. |
| 4 |
|
|
| 5 |
This file is part of BFD, the Binary File Descriptor library. |
This file is part of BFD, the Binary File Descriptor library. |
| 6 |
|
|
| 88 |
HOWTO (R_SPU_PPU64, 0, 4, 64, FALSE, 0, complain_overflow_dont, |
HOWTO (R_SPU_PPU64, 0, 4, 64, FALSE, 0, complain_overflow_dont, |
| 89 |
bfd_elf_generic_reloc, "SPU_PPU64", |
bfd_elf_generic_reloc, "SPU_PPU64", |
| 90 |
FALSE, 0, -1, FALSE), |
FALSE, 0, -1, FALSE), |
| 91 |
|
HOWTO (R_SPU_ADD_PIC, 0, 0, 0, FALSE, 0, complain_overflow_dont, |
| 92 |
|
bfd_elf_generic_reloc, "SPU_ADD_PIC", |
| 93 |
|
FALSE, 0, 0x00000000, FALSE), |
| 94 |
}; |
}; |
| 95 |
|
|
| 96 |
static struct bfd_elf_special_section const spu_elf_special_sections[] = { |
static struct bfd_elf_special_section const spu_elf_special_sections[] = { |
| 138 |
return R_SPU_PPU32; |
return R_SPU_PPU32; |
| 139 |
case BFD_RELOC_SPU_PPU64: |
case BFD_RELOC_SPU_PPU64: |
| 140 |
return R_SPU_PPU64; |
return R_SPU_PPU64; |
| 141 |
|
case BFD_RELOC_SPU_ADD_PIC: |
| 142 |
|
return R_SPU_ADD_PIC; |
| 143 |
} |
} |
| 144 |
} |
} |
| 145 |
|
|
| 306 |
|
|
| 307 |
/* Shortcuts to overlay sections. */ |
/* Shortcuts to overlay sections. */ |
| 308 |
asection *ovtab; |
asection *ovtab; |
| 309 |
|
asection *init; |
| 310 |
asection *toe; |
asection *toe; |
| 311 |
asection **ovl_sec; |
asection **ovl_sec; |
| 312 |
|
|
| 316 |
/* The stub section for each overlay section. */ |
/* The stub section for each overlay section. */ |
| 317 |
asection **stub_sec; |
asection **stub_sec; |
| 318 |
|
|
| 319 |
struct elf_link_hash_entry *ovly_load; |
struct elf_link_hash_entry *ovly_entry[2]; |
|
struct elf_link_hash_entry *ovly_return; |
|
|
unsigned long ovly_load_r_symndx; |
|
| 320 |
|
|
| 321 |
/* Number of overlay buffers. */ |
/* Number of overlay buffers. */ |
| 322 |
unsigned int num_buf; |
unsigned int num_buf; |
| 324 |
/* Total number of overlays. */ |
/* Total number of overlays. */ |
| 325 |
unsigned int num_overlays; |
unsigned int num_overlays; |
| 326 |
|
|
| 327 |
|
/* For soft icache. */ |
| 328 |
|
unsigned int line_size_log2; |
| 329 |
|
unsigned int num_lines_log2; |
| 330 |
|
unsigned int fromelem_size_log2; |
| 331 |
|
|
| 332 |
/* How much memory we have. */ |
/* How much memory we have. */ |
| 333 |
unsigned int local_store; |
unsigned int local_store; |
| 334 |
/* Local store --auto-overlay should reserve for non-overlay |
/* Local store --auto-overlay should reserve for non-overlay |
| 354 |
{ |
{ |
| 355 |
struct got_entry *next; |
struct got_entry *next; |
| 356 |
unsigned int ovl; |
unsigned int ovl; |
| 357 |
bfd_vma addend; |
union { |
| 358 |
|
bfd_vma addend; |
| 359 |
|
bfd_vma br_addr; |
| 360 |
|
}; |
| 361 |
bfd_vma stub_addr; |
bfd_vma stub_addr; |
| 362 |
}; |
}; |
| 363 |
|
|
| 372 |
unsigned int max_depth; |
unsigned int max_depth; |
| 373 |
unsigned int is_tail : 1; |
unsigned int is_tail : 1; |
| 374 |
unsigned int is_pasted : 1; |
unsigned int is_pasted : 1; |
| 375 |
|
unsigned int broken_cycle : 1; |
| 376 |
|
unsigned int priority : 13; |
| 377 |
}; |
}; |
| 378 |
|
|
| 379 |
struct function_info |
struct function_info |
| 396 |
unsigned int call_count; |
unsigned int call_count; |
| 397 |
/* Address range of (this part of) function. */ |
/* Address range of (this part of) function. */ |
| 398 |
bfd_vma lo, hi; |
bfd_vma lo, hi; |
| 399 |
|
/* Offset where we found a store of lr, or -1 if none found. */ |
| 400 |
|
bfd_vma lr_store; |
| 401 |
|
/* Offset where we found the stack adjustment insn. */ |
| 402 |
|
bfd_vma sp_adjust; |
| 403 |
/* Stack usage. */ |
/* Stack usage. */ |
| 404 |
int stack; |
int stack; |
| 405 |
/* Distance from root of call tree. Tail and hot/cold branches |
/* Distance from root of call tree. Tail and hot/cold branches |
| 433 |
struct function_info fun[1]; |
struct function_info fun[1]; |
| 434 |
}; |
}; |
| 435 |
|
|
| 436 |
|
static struct function_info *find_function (asection *, bfd_vma, |
| 437 |
|
struct bfd_link_info *); |
| 438 |
|
|
| 439 |
/* Create a spu ELF linker hash table. */ |
/* Create a spu ELF linker hash table. */ |
| 440 |
|
|
| 441 |
static struct bfd_link_hash_table * |
static struct bfd_link_hash_table * |
| 468 |
void |
void |
| 469 |
spu_elf_setup (struct bfd_link_info *info, struct spu_elf_params *params) |
spu_elf_setup (struct bfd_link_info *info, struct spu_elf_params *params) |
| 470 |
{ |
{ |
| 471 |
|
bfd_vma max_branch_log2; |
| 472 |
|
|
| 473 |
struct spu_link_hash_table *htab = spu_hash_table (info); |
struct spu_link_hash_table *htab = spu_hash_table (info); |
| 474 |
htab->params = params; |
htab->params = params; |
| 475 |
|
htab->line_size_log2 = bfd_log2 (htab->params->line_size); |
| 476 |
|
htab->num_lines_log2 = bfd_log2 (htab->params->num_lines); |
| 477 |
|
|
| 478 |
|
/* For the software i-cache, we provide a "from" list whose size |
| 479 |
|
is a power-of-two number of quadwords, big enough to hold one |
| 480 |
|
byte per outgoing branch. Compute this number here. */ |
| 481 |
|
max_branch_log2 = bfd_log2 (htab->params->max_branch); |
| 482 |
|
htab->fromelem_size_log2 = max_branch_log2 > 4 ? max_branch_log2 - 4 : 0; |
| 483 |
} |
} |
| 484 |
|
|
| 485 |
/* Find the symbol for the given R_SYMNDX in IBFD and set *HP and *SYMP |
/* Find the symbol for the given R_SYMNDX in IBFD and set *HP and *SYMP |
| 618 |
return (*s1)->index - (*s2)->index; |
return (*s1)->index - (*s2)->index; |
| 619 |
} |
} |
| 620 |
|
|
| 621 |
/* Identify overlays in the output bfd, and number them. */ |
/* Identify overlays in the output bfd, and number them. |
| 622 |
|
Returns 0 on error, 1 if no overlays, 2 if overlays. */ |
| 623 |
|
|
| 624 |
bfd_boolean |
int |
| 625 |
spu_elf_find_overlays (struct bfd_link_info *info) |
spu_elf_find_overlays (struct bfd_link_info *info) |
| 626 |
{ |
{ |
| 627 |
struct spu_link_hash_table *htab = spu_hash_table (info); |
struct spu_link_hash_table *htab = spu_hash_table (info); |
| 629 |
unsigned int i, n, ovl_index, num_buf; |
unsigned int i, n, ovl_index, num_buf; |
| 630 |
asection *s; |
asection *s; |
| 631 |
bfd_vma ovl_end; |
bfd_vma ovl_end; |
| 632 |
|
static const char *const entry_names[2][2] = { |
| 633 |
|
{ "__ovly_load", "__icache_br_handler" }, |
| 634 |
|
{ "__ovly_return", "__icache_call_handler" } |
| 635 |
|
}; |
| 636 |
|
|
| 637 |
if (info->output_bfd->section_count < 2) |
if (info->output_bfd->section_count < 2) |
| 638 |
return FALSE; |
return 1; |
| 639 |
|
|
| 640 |
alloc_sec |
alloc_sec |
| 641 |
= bfd_malloc (info->output_bfd->section_count * sizeof (*alloc_sec)); |
= bfd_malloc (info->output_bfd->section_count * sizeof (*alloc_sec)); |
| 642 |
if (alloc_sec == NULL) |
if (alloc_sec == NULL) |
| 643 |
return FALSE; |
return 0; |
| 644 |
|
|
| 645 |
/* Pick out all the alloced sections. */ |
/* Pick out all the alloced sections. */ |
| 646 |
for (n = 0, s = info->output_bfd->sections; s != NULL; s = s->next) |
for (n = 0, s = info->output_bfd->sections; s != NULL; s = s->next) |
| 652 |
if (n == 0) |
if (n == 0) |
| 653 |
{ |
{ |
| 654 |
free (alloc_sec); |
free (alloc_sec); |
| 655 |
return FALSE; |
return 1; |
| 656 |
} |
} |
| 657 |
|
|
| 658 |
/* Sort them by vma. */ |
/* Sort them by vma. */ |
| 659 |
qsort (alloc_sec, n, sizeof (*alloc_sec), sort_sections); |
qsort (alloc_sec, n, sizeof (*alloc_sec), sort_sections); |
| 660 |
|
|
|
/* Look for overlapping vmas. Any with overlap must be overlays. |
|
|
Count them. Also count the number of overlay regions. */ |
|
| 661 |
ovl_end = alloc_sec[0]->vma + alloc_sec[0]->size; |
ovl_end = alloc_sec[0]->vma + alloc_sec[0]->size; |
| 662 |
for (ovl_index = 0, num_buf = 0, i = 1; i < n; i++) |
if (htab->params->ovly_flavour == ovly_soft_icache) |
| 663 |
{ |
{ |
| 664 |
s = alloc_sec[i]; |
/* Look for an overlapping vma to find the first overlay section. */ |
| 665 |
if (s->vma < ovl_end) |
bfd_vma vma_start = 0; |
| 666 |
|
bfd_vma lma_start = 0; |
| 667 |
|
|
| 668 |
|
for (i = 1; i < n; i++) |
| 669 |
{ |
{ |
| 670 |
asection *s0 = alloc_sec[i - 1]; |
s = alloc_sec[i]; |
| 671 |
|
if (s->vma < ovl_end) |
| 672 |
|
{ |
| 673 |
|
asection *s0 = alloc_sec[i - 1]; |
| 674 |
|
vma_start = s0->vma; |
| 675 |
|
if (strncmp (s0->name, ".ovl.init", 9) != 0) |
| 676 |
|
lma_start = s0->lma; |
| 677 |
|
else |
| 678 |
|
lma_start = s->lma; |
| 679 |
|
ovl_end = (s0->vma |
| 680 |
|
+ ((bfd_vma) 1 |
| 681 |
|
<< (htab->num_lines_log2 + htab->line_size_log2))); |
| 682 |
|
--i; |
| 683 |
|
break; |
| 684 |
|
} |
| 685 |
|
else |
| 686 |
|
ovl_end = s->vma + s->size; |
| 687 |
|
} |
| 688 |
|
|
| 689 |
if (spu_elf_section_data (s0)->u.o.ovl_index == 0) |
/* Now find any sections within the cache area. */ |
| 690 |
|
for (ovl_index = 0, num_buf = 0; i < n; i++) |
| 691 |
|
{ |
| 692 |
|
s = alloc_sec[i]; |
| 693 |
|
if (s->vma >= ovl_end) |
| 694 |
|
break; |
| 695 |
|
|
| 696 |
|
/* A section in an overlay area called .ovl.init is not |
| 697 |
|
an overlay, in the sense that it might be loaded in |
| 698 |
|
by the overlay manager, but rather the initial |
| 699 |
|
section contents for the overlay buffer. */ |
| 700 |
|
if (strncmp (s->name, ".ovl.init", 9) != 0) |
| 701 |
{ |
{ |
| 702 |
alloc_sec[ovl_index] = s0; |
num_buf = ((s->vma - vma_start) >> htab->line_size_log2) + 1; |
| 703 |
spu_elf_section_data (s0)->u.o.ovl_index = ++ovl_index; |
if (((s->vma - vma_start) & (htab->params->line_size - 1)) |
| 704 |
spu_elf_section_data (s0)->u.o.ovl_buf = ++num_buf; |
|| ((s->lma - lma_start) & (htab->params->line_size - 1))) |
| 705 |
|
{ |
| 706 |
|
info->callbacks->einfo (_("%X%P: overlay section %A " |
| 707 |
|
"does not start on a cache line.\n"), |
| 708 |
|
s); |
| 709 |
|
bfd_set_error (bfd_error_bad_value); |
| 710 |
|
return 0; |
| 711 |
|
} |
| 712 |
|
else if (s->size > htab->params->line_size) |
| 713 |
|
{ |
| 714 |
|
info->callbacks->einfo (_("%X%P: overlay section %A " |
| 715 |
|
"is larger than a cache line.\n"), |
| 716 |
|
s); |
| 717 |
|
bfd_set_error (bfd_error_bad_value); |
| 718 |
|
return 0; |
| 719 |
|
} |
| 720 |
|
|
| 721 |
|
alloc_sec[ovl_index++] = s; |
| 722 |
|
spu_elf_section_data (s)->u.o.ovl_index |
| 723 |
|
= ((s->lma - lma_start) >> htab->line_size_log2) + 1; |
| 724 |
|
spu_elf_section_data (s)->u.o.ovl_buf = num_buf; |
| 725 |
} |
} |
| 726 |
alloc_sec[ovl_index] = s; |
} |
| 727 |
spu_elf_section_data (s)->u.o.ovl_index = ++ovl_index; |
|
| 728 |
spu_elf_section_data (s)->u.o.ovl_buf = num_buf; |
/* Ensure there are no more overlay sections. */ |
| 729 |
if (s0->vma != s->vma) |
for ( ; i < n; i++) |
| 730 |
|
{ |
| 731 |
|
s = alloc_sec[i]; |
| 732 |
|
if (s->vma < ovl_end) |
| 733 |
{ |
{ |
| 734 |
info->callbacks->einfo (_("%X%P: overlay sections %A and %A " |
info->callbacks->einfo (_("%X%P: overlay section %A " |
| 735 |
"do not start at the same address.\n"), |
"is not in cache area.\n"), |
| 736 |
s0, s); |
alloc_sec[i-1]); |
| 737 |
return FALSE; |
bfd_set_error (bfd_error_bad_value); |
| 738 |
|
return 0; |
| 739 |
|
} |
| 740 |
|
else |
| 741 |
|
ovl_end = s->vma + s->size; |
| 742 |
|
} |
| 743 |
|
} |
| 744 |
|
else |
| 745 |
|
{ |
| 746 |
|
/* Look for overlapping vmas. Any with overlap must be overlays. |
| 747 |
|
Count them. Also count the number of overlay regions. */ |
| 748 |
|
for (ovl_index = 0, num_buf = 0, i = 1; i < n; i++) |
| 749 |
|
{ |
| 750 |
|
s = alloc_sec[i]; |
| 751 |
|
if (s->vma < ovl_end) |
| 752 |
|
{ |
| 753 |
|
asection *s0 = alloc_sec[i - 1]; |
| 754 |
|
|
| 755 |
|
if (spu_elf_section_data (s0)->u.o.ovl_index == 0) |
| 756 |
|
{ |
| 757 |
|
++num_buf; |
| 758 |
|
if (strncmp (s0->name, ".ovl.init", 9) != 0) |
| 759 |
|
{ |
| 760 |
|
alloc_sec[ovl_index] = s0; |
| 761 |
|
spu_elf_section_data (s0)->u.o.ovl_index = ++ovl_index; |
| 762 |
|
spu_elf_section_data (s0)->u.o.ovl_buf = num_buf; |
| 763 |
|
} |
| 764 |
|
else |
| 765 |
|
ovl_end = s->vma + s->size; |
| 766 |
|
} |
| 767 |
|
if (strncmp (s->name, ".ovl.init", 9) != 0) |
| 768 |
|
{ |
| 769 |
|
alloc_sec[ovl_index] = s; |
| 770 |
|
spu_elf_section_data (s)->u.o.ovl_index = ++ovl_index; |
| 771 |
|
spu_elf_section_data (s)->u.o.ovl_buf = num_buf; |
| 772 |
|
if (s0->vma != s->vma) |
| 773 |
|
{ |
| 774 |
|
info->callbacks->einfo (_("%X%P: overlay sections %A " |
| 775 |
|
"and %A do not start at the " |
| 776 |
|
"same address.\n"), |
| 777 |
|
s0, s); |
| 778 |
|
bfd_set_error (bfd_error_bad_value); |
| 779 |
|
return 0; |
| 780 |
|
} |
| 781 |
|
if (ovl_end < s->vma + s->size) |
| 782 |
|
ovl_end = s->vma + s->size; |
| 783 |
|
} |
| 784 |
} |
} |
| 785 |
if (ovl_end < s->vma + s->size) |
else |
| 786 |
ovl_end = s->vma + s->size; |
ovl_end = s->vma + s->size; |
| 787 |
} |
} |
|
else |
|
|
ovl_end = s->vma + s->size; |
|
| 788 |
} |
} |
| 789 |
|
|
| 790 |
htab->num_overlays = ovl_index; |
htab->num_overlays = ovl_index; |
| 791 |
htab->num_buf = num_buf; |
htab->num_buf = num_buf; |
| 792 |
htab->ovl_sec = alloc_sec; |
htab->ovl_sec = alloc_sec; |
| 793 |
htab->ovly_load = elf_link_hash_lookup (&htab->elf, "__ovly_load", |
|
| 794 |
FALSE, FALSE, FALSE); |
if (ovl_index == 0) |
| 795 |
htab->ovly_return = elf_link_hash_lookup (&htab->elf, "__ovly_return", |
return 1; |
| 796 |
FALSE, FALSE, FALSE); |
|
| 797 |
return ovl_index != 0; |
for (i = 0; i < 2; i++) |
| 798 |
|
{ |
| 799 |
|
const char *name; |
| 800 |
|
struct elf_link_hash_entry *h; |
| 801 |
|
|
| 802 |
|
name = entry_names[i][htab->params->ovly_flavour]; |
| 803 |
|
h = elf_link_hash_lookup (&htab->elf, name, TRUE, FALSE, FALSE); |
| 804 |
|
if (h == NULL) |
| 805 |
|
return 0; |
| 806 |
|
|
| 807 |
|
if (h->root.type == bfd_link_hash_new) |
| 808 |
|
{ |
| 809 |
|
h->root.type = bfd_link_hash_undefined; |
| 810 |
|
h->ref_regular = 1; |
| 811 |
|
h->ref_regular_nonweak = 1; |
| 812 |
|
h->non_elf = 0; |
| 813 |
|
} |
| 814 |
|
htab->ovly_entry[i] = h; |
| 815 |
|
} |
| 816 |
|
|
| 817 |
|
return 2; |
| 818 |
} |
} |
| 819 |
|
|
| 820 |
#define BRSL 0x33000000 |
/* Non-zero to use bra in overlay stubs rather than br. */ |
| 821 |
|
#define BRA_STUBS 0 |
| 822 |
|
|
| 823 |
|
#define BRA 0x30000000 |
| 824 |
|
#define BRASL 0x31000000 |
| 825 |
#define BR 0x32000000 |
#define BR 0x32000000 |
| 826 |
|
#define BRSL 0x33000000 |
| 827 |
#define NOP 0x40200000 |
#define NOP 0x40200000 |
| 828 |
#define LNOP 0x00200000 |
#define LNOP 0x00200000 |
| 829 |
#define ILA 0x42000000 |
#define ILA 0x42000000 |
| 893 |
enum _stub_type |
enum _stub_type |
| 894 |
{ |
{ |
| 895 |
no_stub, |
no_stub, |
| 896 |
ovl_stub, |
call_ovl_stub, |
| 897 |
|
br000_ovl_stub, |
| 898 |
|
br001_ovl_stub, |
| 899 |
|
br010_ovl_stub, |
| 900 |
|
br011_ovl_stub, |
| 901 |
|
br100_ovl_stub, |
| 902 |
|
br101_ovl_stub, |
| 903 |
|
br110_ovl_stub, |
| 904 |
|
br111_ovl_stub, |
| 905 |
nonovl_stub, |
nonovl_stub, |
| 906 |
stub_error |
stub_error |
| 907 |
}; |
}; |
| 921 |
struct spu_link_hash_table *htab = spu_hash_table (info); |
struct spu_link_hash_table *htab = spu_hash_table (info); |
| 922 |
enum elf_spu_reloc_type r_type; |
enum elf_spu_reloc_type r_type; |
| 923 |
unsigned int sym_type; |
unsigned int sym_type; |
| 924 |
bfd_boolean branch; |
bfd_boolean branch, hint, call; |
| 925 |
enum _stub_type ret = no_stub; |
enum _stub_type ret = no_stub; |
| 926 |
|
bfd_byte insn[4]; |
| 927 |
|
|
| 928 |
if (sym_sec == NULL |
if (sym_sec == NULL |
| 929 |
|| sym_sec->output_section == bfd_abs_section_ptr |
|| sym_sec->output_section == bfd_abs_section_ptr |
| 933 |
if (h != NULL) |
if (h != NULL) |
| 934 |
{ |
{ |
| 935 |
/* Ensure no stubs for user supplied overlay manager syms. */ |
/* Ensure no stubs for user supplied overlay manager syms. */ |
| 936 |
if (h == htab->ovly_load || h == htab->ovly_return) |
if (h == htab->ovly_entry[0] || h == htab->ovly_entry[1]) |
| 937 |
return ret; |
return ret; |
| 938 |
|
|
| 939 |
/* setjmp always goes via an overlay stub, because then the return |
/* setjmp always goes via an overlay stub, because then the return |
| 941 |
makes setjmp/longjmp between overlays work. */ |
makes setjmp/longjmp between overlays work. */ |
| 942 |
if (strncmp (h->root.root.string, "setjmp", 6) == 0 |
if (strncmp (h->root.root.string, "setjmp", 6) == 0 |
| 943 |
&& (h->root.root.string[6] == '\0' || h->root.root.string[6] == '@')) |
&& (h->root.root.string[6] == '\0' || h->root.root.string[6] == '@')) |
| 944 |
ret = ovl_stub; |
ret = call_ovl_stub; |
| 945 |
} |
} |
| 946 |
|
|
|
/* Usually, symbols in non-overlay sections don't need stubs. */ |
|
|
if (spu_elf_section_data (sym_sec->output_section)->u.o.ovl_index == 0 |
|
|
&& !htab->params->non_overlay_stubs) |
|
|
return ret; |
|
|
|
|
| 947 |
if (h != NULL) |
if (h != NULL) |
| 948 |
sym_type = h->type; |
sym_type = h->type; |
| 949 |
else |
else |
| 951 |
|
|
| 952 |
r_type = ELF32_R_TYPE (irela->r_info); |
r_type = ELF32_R_TYPE (irela->r_info); |
| 953 |
branch = FALSE; |
branch = FALSE; |
| 954 |
|
hint = FALSE; |
| 955 |
|
call = FALSE; |
| 956 |
if (r_type == R_SPU_REL16 || r_type == R_SPU_ADDR16) |
if (r_type == R_SPU_REL16 || r_type == R_SPU_ADDR16) |
| 957 |
{ |
{ |
|
bfd_byte insn[4]; |
|
|
|
|
| 958 |
if (contents == NULL) |
if (contents == NULL) |
| 959 |
{ |
{ |
| 960 |
contents = insn; |
contents = insn; |
| 967 |
else |
else |
| 968 |
contents += irela->r_offset; |
contents += irela->r_offset; |
| 969 |
|
|
| 970 |
if (is_branch (contents) || is_hint (contents)) |
branch = is_branch (contents); |
| 971 |
|
hint = is_hint (contents); |
| 972 |
|
if (branch || hint) |
| 973 |
{ |
{ |
| 974 |
branch = TRUE; |
call = (contents[0] & 0xfd) == 0x31; |
| 975 |
if ((contents[0] & 0xfd) == 0x31 |
if (call |
| 976 |
&& sym_type != STT_FUNC |
&& sym_type != STT_FUNC |
| 977 |
&& contents != insn) |
&& contents != insn) |
| 978 |
{ |
{ |
| 1003 |
} |
} |
| 1004 |
} |
} |
| 1005 |
|
|
| 1006 |
if (sym_type != STT_FUNC |
if ((!branch && htab->params->ovly_flavour == ovly_soft_icache) |
| 1007 |
&& !branch |
|| (sym_type != STT_FUNC |
| 1008 |
&& (sym_sec->flags & SEC_CODE) == 0) |
&& !(branch || hint) |
| 1009 |
|
&& (sym_sec->flags & SEC_CODE) == 0)) |
| 1010 |
|
return no_stub; |
| 1011 |
|
|
| 1012 |
|
/* Usually, symbols in non-overlay sections don't need stubs. */ |
| 1013 |
|
if (spu_elf_section_data (sym_sec->output_section)->u.o.ovl_index == 0 |
| 1014 |
|
&& !htab->params->non_overlay_stubs) |
| 1015 |
return ret; |
return ret; |
| 1016 |
|
|
| 1017 |
/* A reference from some other section to a symbol in an overlay |
/* A reference from some other section to a symbol in an overlay |
| 1018 |
section needs a stub. */ |
section needs a stub. */ |
| 1019 |
if (spu_elf_section_data (sym_sec->output_section)->u.o.ovl_index |
if (spu_elf_section_data (sym_sec->output_section)->u.o.ovl_index |
| 1020 |
!= spu_elf_section_data (input_section->output_section)->u.o.ovl_index) |
!= spu_elf_section_data (input_section->output_section)->u.o.ovl_index) |
| 1021 |
ret = ovl_stub; |
{ |
| 1022 |
|
unsigned int lrlive = 0; |
| 1023 |
|
if (branch) |
| 1024 |
|
lrlive = (contents[1] & 0x70) >> 4; |
| 1025 |
|
|
| 1026 |
|
if (!lrlive && (call || sym_type == STT_FUNC)) |
| 1027 |
|
ret = call_ovl_stub; |
| 1028 |
|
else |
| 1029 |
|
ret = br000_ovl_stub + lrlive; |
| 1030 |
|
} |
| 1031 |
|
|
| 1032 |
/* If this insn isn't a branch then we are possibly taking the |
/* If this insn isn't a branch then we are possibly taking the |
| 1033 |
address of a function and passing it out somehow. */ |
address of a function and passing it out somehow. Soft-icache code |
| 1034 |
return !branch && sym_type == STT_FUNC ? nonovl_stub : ret; |
always generates inline code to do indirect branches. */ |
| 1035 |
|
if (!(branch || hint) |
| 1036 |
|
&& sym_type == STT_FUNC |
| 1037 |
|
&& htab->params->ovly_flavour != ovly_soft_icache) |
| 1038 |
|
ret = nonovl_stub; |
| 1039 |
|
|
| 1040 |
|
return ret; |
| 1041 |
} |
} |
| 1042 |
|
|
| 1043 |
static bfd_boolean |
static bfd_boolean |
| 1075 |
head = elf_local_got_ents (ibfd) + ELF32_R_SYM (irela->r_info); |
head = elf_local_got_ents (ibfd) + ELF32_R_SYM (irela->r_info); |
| 1076 |
} |
} |
| 1077 |
|
|
| 1078 |
|
if (htab->params->ovly_flavour == ovly_soft_icache) |
| 1079 |
|
{ |
| 1080 |
|
htab->stub_count[ovl] += 1; |
| 1081 |
|
return TRUE; |
| 1082 |
|
} |
| 1083 |
|
|
| 1084 |
addend = 0; |
addend = 0; |
| 1085 |
if (irela != NULL) |
if (irela != NULL) |
| 1086 |
addend = irela->r_addend; |
addend = irela->r_addend; |
| 1132 |
} |
} |
| 1133 |
|
|
| 1134 |
/* Support two sizes of overlay stubs, a slower more compact stub of two |
/* Support two sizes of overlay stubs, a slower more compact stub of two |
| 1135 |
intructions, and a faster stub of four instructions. */ |
intructions, and a faster stub of four instructions. |
| 1136 |
|
Soft-icache stubs are four or eight words. */ |
| 1137 |
|
|
| 1138 |
|
static unsigned int |
| 1139 |
|
ovl_stub_size (struct spu_elf_params *params) |
| 1140 |
|
{ |
| 1141 |
|
return 16 << params->ovly_flavour >> params->compact_stub; |
| 1142 |
|
} |
| 1143 |
|
|
| 1144 |
static unsigned int |
static unsigned int |
| 1145 |
ovl_stub_size (enum _ovly_flavour ovly_flavour) |
ovl_stub_size_log2 (struct spu_elf_params *params) |
| 1146 |
{ |
{ |
| 1147 |
return 8 << ovly_flavour; |
return 4 + params->ovly_flavour - params->compact_stub; |
| 1148 |
} |
} |
| 1149 |
|
|
| 1150 |
/* Two instruction overlay stubs look like: |
/* Two instruction overlay stubs look like: |
| 1160 |
ila $78,ovl_number |
ila $78,ovl_number |
| 1161 |
lnop |
lnop |
| 1162 |
ila $79,target_address |
ila $79,target_address |
| 1163 |
br __ovly_load */ |
br __ovly_load |
| 1164 |
|
|
| 1165 |
|
Software icache stubs are: |
| 1166 |
|
|
| 1167 |
|
.word target_index |
| 1168 |
|
.word target_ia; |
| 1169 |
|
.word lrlive_branchlocalstoreaddr; |
| 1170 |
|
brasl $75,__icache_br_handler |
| 1171 |
|
.quad xor_pattern |
| 1172 |
|
*/ |
| 1173 |
|
|
| 1174 |
static bfd_boolean |
static bfd_boolean |
| 1175 |
build_stub (struct spu_link_hash_table *htab, |
build_stub (struct bfd_link_info *info, |
| 1176 |
bfd *ibfd, |
bfd *ibfd, |
| 1177 |
asection *isec, |
asection *isec, |
| 1178 |
enum _stub_type stub_type, |
enum _stub_type stub_type, |
| 1181 |
bfd_vma dest, |
bfd_vma dest, |
| 1182 |
asection *dest_sec) |
asection *dest_sec) |
| 1183 |
{ |
{ |
| 1184 |
unsigned int ovl, dest_ovl; |
struct spu_link_hash_table *htab = spu_hash_table (info); |
| 1185 |
|
unsigned int ovl, dest_ovl, set_id; |
| 1186 |
struct got_entry *g, **head; |
struct got_entry *g, **head; |
| 1187 |
asection *sec; |
asection *sec; |
| 1188 |
bfd_vma addend, from, to; |
bfd_vma addend, from, to, br_dest, patt; |
| 1189 |
|
unsigned int lrlive; |
| 1190 |
|
|
| 1191 |
ovl = 0; |
ovl = 0; |
| 1192 |
if (stub_type != nonovl_stub) |
if (stub_type != nonovl_stub) |
| 1201 |
if (irela != NULL) |
if (irela != NULL) |
| 1202 |
addend = irela->r_addend; |
addend = irela->r_addend; |
| 1203 |
|
|
| 1204 |
for (g = *head; g != NULL; g = g->next) |
if (htab->params->ovly_flavour == ovly_soft_icache) |
| 1205 |
if (g->addend == addend && (g->ovl == ovl || g->ovl == 0)) |
{ |
| 1206 |
break; |
g = bfd_malloc (sizeof *g); |
| 1207 |
if (g == NULL) |
if (g == NULL) |
| 1208 |
abort (); |
return FALSE; |
| 1209 |
|
g->ovl = ovl; |
| 1210 |
|
g->br_addr = 0; |
| 1211 |
|
if (irela != NULL) |
| 1212 |
|
g->br_addr = (irela->r_offset |
| 1213 |
|
+ isec->output_offset |
| 1214 |
|
+ isec->output_section->vma); |
| 1215 |
|
g->next = *head; |
| 1216 |
|
*head = g; |
| 1217 |
|
} |
| 1218 |
|
else |
| 1219 |
|
{ |
| 1220 |
|
for (g = *head; g != NULL; g = g->next) |
| 1221 |
|
if (g->addend == addend && (g->ovl == ovl || g->ovl == 0)) |
| 1222 |
|
break; |
| 1223 |
|
if (g == NULL) |
| 1224 |
|
abort (); |
| 1225 |
|
|
| 1226 |
if (g->ovl == 0 && ovl != 0) |
if (g->ovl == 0 && ovl != 0) |
| 1227 |
return TRUE; |
return TRUE; |
| 1228 |
|
|
| 1229 |
if (g->stub_addr != (bfd_vma) -1) |
if (g->stub_addr != (bfd_vma) -1) |
| 1230 |
return TRUE; |
return TRUE; |
| 1231 |
|
} |
| 1232 |
|
|
| 1233 |
sec = htab->stub_sec[ovl]; |
sec = htab->stub_sec[ovl]; |
| 1234 |
dest += dest_sec->output_offset + dest_sec->output_section->vma; |
dest += dest_sec->output_offset + dest_sec->output_section->vma; |
| 1235 |
from = sec->size + sec->output_offset + sec->output_section->vma; |
from = sec->size + sec->output_offset + sec->output_section->vma; |
| 1236 |
g->stub_addr = from; |
g->stub_addr = from; |
| 1237 |
to = (htab->ovly_load->root.u.def.value |
to = (htab->ovly_entry[0]->root.u.def.value |
| 1238 |
+ htab->ovly_load->root.u.def.section->output_offset |
+ htab->ovly_entry[0]->root.u.def.section->output_offset |
| 1239 |
+ htab->ovly_load->root.u.def.section->output_section->vma); |
+ htab->ovly_entry[0]->root.u.def.section->output_section->vma); |
| 1240 |
|
|
| 1241 |
if (((dest | to | from) & 3) != 0) |
if (((dest | to | from) & 3) != 0) |
| 1242 |
{ |
{ |
| 1245 |
} |
} |
| 1246 |
dest_ovl = spu_elf_section_data (dest_sec->output_section)->u.o.ovl_index; |
dest_ovl = spu_elf_section_data (dest_sec->output_section)->u.o.ovl_index; |
| 1247 |
|
|
| 1248 |
switch (htab->params->ovly_flavour) |
if (htab->params->ovly_flavour == ovly_normal |
| 1249 |
|
&& !htab->params->compact_stub) |
| 1250 |
{ |
{ |
|
case ovly_normal: |
|
| 1251 |
bfd_put_32 (sec->owner, ILA + ((dest_ovl << 7) & 0x01ffff80) + 78, |
bfd_put_32 (sec->owner, ILA + ((dest_ovl << 7) & 0x01ffff80) + 78, |
| 1252 |
sec->contents + sec->size); |
sec->contents + sec->size); |
| 1253 |
bfd_put_32 (sec->owner, LNOP, |
bfd_put_32 (sec->owner, LNOP, |
| 1254 |
sec->contents + sec->size + 4); |
sec->contents + sec->size + 4); |
| 1255 |
bfd_put_32 (sec->owner, ILA + ((dest << 7) & 0x01ffff80) + 79, |
bfd_put_32 (sec->owner, ILA + ((dest << 7) & 0x01ffff80) + 79, |
| 1256 |
sec->contents + sec->size + 8); |
sec->contents + sec->size + 8); |
| 1257 |
bfd_put_32 (sec->owner, BR + (((to - (from + 12)) << 5) & 0x007fff80), |
if (!BRA_STUBS) |
| 1258 |
sec->contents + sec->size + 12); |
bfd_put_32 (sec->owner, BR + (((to - (from + 12)) << 5) & 0x007fff80), |
| 1259 |
break; |
sec->contents + sec->size + 12); |
| 1260 |
|
else |
| 1261 |
|
bfd_put_32 (sec->owner, BRA + ((to << 5) & 0x007fff80), |
| 1262 |
|
sec->contents + sec->size + 12); |
| 1263 |
|
} |
| 1264 |
|
else if (htab->params->ovly_flavour == ovly_normal |
| 1265 |
|
&& htab->params->compact_stub) |
| 1266 |
|
{ |
| 1267 |
|
if (!BRA_STUBS) |
| 1268 |
|
bfd_put_32 (sec->owner, BRSL + (((to - from) << 5) & 0x007fff80) + 75, |
| 1269 |
|
sec->contents + sec->size); |
| 1270 |
|
else |
| 1271 |
|
bfd_put_32 (sec->owner, BRASL + ((to << 5) & 0x007fff80) + 75, |
| 1272 |
|
sec->contents + sec->size); |
| 1273 |
|
bfd_put_32 (sec->owner, (dest & 0x3ffff) | (dest_ovl << 18), |
| 1274 |
|
sec->contents + sec->size + 4); |
| 1275 |
|
} |
| 1276 |
|
else if (htab->params->ovly_flavour == ovly_soft_icache |
| 1277 |
|
&& htab->params->compact_stub) |
| 1278 |
|
{ |
| 1279 |
|
lrlive = 0; |
| 1280 |
|
if (stub_type == nonovl_stub) |
| 1281 |
|
; |
| 1282 |
|
else if (stub_type == call_ovl_stub) |
| 1283 |
|
/* A brsl makes lr live and *(*sp+16) is live. |
| 1284 |
|
Tail calls have the same liveness. */ |
| 1285 |
|
lrlive = 5; |
| 1286 |
|
else if (!htab->params->lrlive_analysis) |
| 1287 |
|
/* Assume stack frame and lr save. */ |
| 1288 |
|
lrlive = 1; |
| 1289 |
|
else if (irela != NULL) |
| 1290 |
|
{ |
| 1291 |
|
/* Analyse branch instructions. */ |
| 1292 |
|
struct function_info *caller; |
| 1293 |
|
bfd_vma off; |
| 1294 |
|
|
| 1295 |
|
caller = find_function (isec, irela->r_offset, info); |
| 1296 |
|
if (caller->start == NULL) |
| 1297 |
|
off = irela->r_offset; |
| 1298 |
|
else |
| 1299 |
|
{ |
| 1300 |
|
struct function_info *found = NULL; |
| 1301 |
|
|
| 1302 |
|
/* Find the earliest piece of this function that |
| 1303 |
|
has frame adjusting instructions. We might |
| 1304 |
|
see dynamic frame adjustment (eg. for alloca) |
| 1305 |
|
in some later piece, but functions using |
| 1306 |
|
alloca always set up a frame earlier. Frame |
| 1307 |
|
setup instructions are always in one piece. */ |
| 1308 |
|
if (caller->lr_store != (bfd_vma) -1 |
| 1309 |
|
|| caller->sp_adjust != (bfd_vma) -1) |
| 1310 |
|
found = caller; |
| 1311 |
|
while (caller->start != NULL) |
| 1312 |
|
{ |
| 1313 |
|
caller = caller->start; |
| 1314 |
|
if (caller->lr_store != (bfd_vma) -1 |
| 1315 |
|
|| caller->sp_adjust != (bfd_vma) -1) |
| 1316 |
|
found = caller; |
| 1317 |
|
} |
| 1318 |
|
if (found != NULL) |
| 1319 |
|
caller = found; |
| 1320 |
|
off = (bfd_vma) -1; |
| 1321 |
|
} |
| 1322 |
|
|
| 1323 |
|
if (off > caller->sp_adjust) |
| 1324 |
|
{ |
| 1325 |
|
if (off > caller->lr_store) |
| 1326 |
|
/* Only *(*sp+16) is live. */ |
| 1327 |
|
lrlive = 1; |
| 1328 |
|
else |
| 1329 |
|
/* If no lr save, then we must be in a |
| 1330 |
|
leaf function with a frame. |
| 1331 |
|
lr is still live. */ |
| 1332 |
|
lrlive = 4; |
| 1333 |
|
} |
| 1334 |
|
else if (off > caller->lr_store) |
| 1335 |
|
{ |
| 1336 |
|
/* Between lr save and stack adjust. */ |
| 1337 |
|
lrlive = 3; |
| 1338 |
|
/* This should never happen since prologues won't |
| 1339 |
|
be split here. */ |
| 1340 |
|
BFD_ASSERT (0); |
| 1341 |
|
} |
| 1342 |
|
else |
| 1343 |
|
/* On entry to function. */ |
| 1344 |
|
lrlive = 5; |
| 1345 |
|
|
| 1346 |
|
if (stub_type != br000_ovl_stub |
| 1347 |
|
&& lrlive != stub_type - br000_ovl_stub) |
| 1348 |
|
info->callbacks->einfo (_("%A:0x%v lrlive .brinfo (%u) differs " |
| 1349 |
|
"from analysis (%u)\n"), |
| 1350 |
|
isec, irela->r_offset, lrlive, |
| 1351 |
|
stub_type - br000_ovl_stub); |
| 1352 |
|
} |
| 1353 |
|
|
| 1354 |
|
/* If given lrlive info via .brinfo, use it. */ |
| 1355 |
|
if (stub_type > br000_ovl_stub) |
| 1356 |
|
lrlive = stub_type - br000_ovl_stub; |
| 1357 |
|
|
| 1358 |
|
if (ovl == 0) |
| 1359 |
|
to = (htab->ovly_entry[1]->root.u.def.value |
| 1360 |
|
+ htab->ovly_entry[1]->root.u.def.section->output_offset |
| 1361 |
|
+ htab->ovly_entry[1]->root.u.def.section->output_section->vma); |
| 1362 |
|
|
| 1363 |
|
/* The branch that uses this stub goes to stub_addr + 4. We'll |
| 1364 |
|
set up an xor pattern that can be used by the icache manager |
| 1365 |
|
to modify this branch to go directly to its destination. */ |
| 1366 |
|
g->stub_addr += 4; |
| 1367 |
|
br_dest = g->stub_addr; |
| 1368 |
|
if (irela == NULL) |
| 1369 |
|
{ |
| 1370 |
|
/* Except in the case of _SPUEAR_ stubs, the branch in |
| 1371 |
|
question is the one in the stub itself. */ |
| 1372 |
|
BFD_ASSERT (stub_type == nonovl_stub); |
| 1373 |
|
g->br_addr = g->stub_addr; |
| 1374 |
|
br_dest = to; |
| 1375 |
|
} |
| 1376 |
|
|
| 1377 |
case ovly_compact: |
set_id = ((dest_ovl - 1) >> htab->num_lines_log2) + 1; |
| 1378 |
bfd_put_32 (sec->owner, BRSL + (((to - from) << 5) & 0x007fff80) + 75, |
bfd_put_32 (sec->owner, (set_id << 18) | (dest & 0x3ffff), |
| 1379 |
sec->contents + sec->size); |
sec->contents + sec->size); |
| 1380 |
bfd_put_32 (sec->owner, (dest & 0x3ffff) | (dest_ovl << 18), |
bfd_put_32 (sec->owner, BRASL + ((to << 5) & 0x007fff80) + 75, |
| 1381 |
sec->contents + sec->size + 4); |
sec->contents + sec->size + 4); |
| 1382 |
break; |
bfd_put_32 (sec->owner, (lrlive << 29) | (g->br_addr & 0x3ffff), |
| 1383 |
|
sec->contents + sec->size + 8); |
| 1384 |
|
patt = dest ^ br_dest; |
| 1385 |
|
if (irela != NULL && ELF32_R_TYPE (irela->r_info) == R_SPU_REL16) |
| 1386 |
|
patt = (dest - g->br_addr) ^ (br_dest - g->br_addr); |
| 1387 |
|
bfd_put_32 (sec->owner, (patt << 5) & 0x007fff80, |
| 1388 |
|
sec->contents + sec->size + 12); |
| 1389 |
|
|
| 1390 |
default: |
if (ovl == 0) |
| 1391 |
abort (); |
/* Extra space for linked list entries. */ |
| 1392 |
|
sec->size += 16; |
| 1393 |
} |
} |
| 1394 |
sec->size += ovl_stub_size (htab->params->ovly_flavour); |
else |
| 1395 |
|
abort (); |
| 1396 |
|
|
| 1397 |
|
sec->size += ovl_stub_size (htab->params); |
| 1398 |
|
|
| 1399 |
if (htab->params->emit_stub_syms) |
if (htab->params->emit_stub_syms) |
| 1400 |
{ |
{ |
| 1434 |
{ |
{ |
| 1435 |
h->root.type = bfd_link_hash_defined; |
h->root.type = bfd_link_hash_defined; |
| 1436 |
h->root.u.def.section = sec; |
h->root.u.def.section = sec; |
| 1437 |
h->size = ovl_stub_size (htab->params->ovly_flavour); |
h->size = ovl_stub_size (htab->params); |
| 1438 |
h->root.u.def.value = sec->size - h->size; |
h->root.u.def.value = sec->size - h->size; |
| 1439 |
h->type = STT_FUNC; |
h->type = STT_FUNC; |
| 1440 |
h->ref_regular = 1; |
h->ref_regular = 1; |
| 1495 |
&& (spu_elf_section_data (sym_sec->output_section)->u.o.ovl_index != 0 |
&& (spu_elf_section_data (sym_sec->output_section)->u.o.ovl_index != 0 |
| 1496 |
|| htab->params->non_overlay_stubs)) |
|| htab->params->non_overlay_stubs)) |
| 1497 |
{ |
{ |
| 1498 |
return build_stub (htab, NULL, NULL, nonovl_stub, h, NULL, |
return build_stub (info, NULL, NULL, nonovl_stub, h, NULL, |
| 1499 |
h->root.u.def.value, sym_sec); |
h->root.u.def.value, sym_sec); |
| 1500 |
} |
} |
| 1501 |
|
|
| 1607 |
else |
else |
| 1608 |
dest = sym->st_value; |
dest = sym->st_value; |
| 1609 |
dest += irela->r_addend; |
dest += irela->r_addend; |
| 1610 |
if (!build_stub (htab, ibfd, isec, stub_type, h, irela, |
if (!build_stub (info, ibfd, isec, stub_type, h, irela, |
| 1611 |
dest, sym_sec)) |
dest, sym_sec)) |
| 1612 |
goto error_ret_free_internal; |
goto error_ret_free_internal; |
| 1613 |
} |
} |
| 1631 |
return TRUE; |
return TRUE; |
| 1632 |
} |
} |
| 1633 |
|
|
| 1634 |
/* Allocate space for overlay call and return stubs. */ |
/* Allocate space for overlay call and return stubs. |
| 1635 |
|
Return 0 on error, 1 if no overlays, 2 otherwise. */ |
| 1636 |
|
|
| 1637 |
int |
int |
| 1638 |
spu_elf_size_stubs (struct bfd_link_info *info) |
spu_elf_size_stubs (struct bfd_link_info *info) |
| 1652 |
if (htab->stub_err) |
if (htab->stub_err) |
| 1653 |
return 0; |
return 0; |
| 1654 |
|
|
|
if (htab->stub_count == NULL) |
|
|
return 1; |
|
|
|
|
| 1655 |
ibfd = info->input_bfds; |
ibfd = info->input_bfds; |
| 1656 |
amt = (htab->num_overlays + 1) * sizeof (*htab->stub_sec); |
if (htab->stub_count != NULL) |
|
htab->stub_sec = bfd_zmalloc (amt); |
|
|
if (htab->stub_sec == NULL) |
|
|
return 0; |
|
|
|
|
|
flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_READONLY |
|
|
| SEC_HAS_CONTENTS | SEC_IN_MEMORY); |
|
|
stub = bfd_make_section_anyway_with_flags (ibfd, ".stub", flags); |
|
|
htab->stub_sec[0] = stub; |
|
|
if (stub == NULL |
|
|
|| !bfd_set_section_alignment (ibfd, stub, |
|
|
htab->params->ovly_flavour + 3)) |
|
|
return 0; |
|
|
stub->size = htab->stub_count[0] * ovl_stub_size (htab->params->ovly_flavour); |
|
|
(*htab->params->place_spu_section) (stub, NULL, ".text"); |
|
|
|
|
|
for (i = 0; i < htab->num_overlays; ++i) |
|
| 1657 |
{ |
{ |
| 1658 |
asection *osec = htab->ovl_sec[i]; |
amt = (htab->num_overlays + 1) * sizeof (*htab->stub_sec); |
| 1659 |
unsigned int ovl = spu_elf_section_data (osec)->u.o.ovl_index; |
htab->stub_sec = bfd_zmalloc (amt); |
| 1660 |
|
if (htab->stub_sec == NULL) |
| 1661 |
|
return 0; |
| 1662 |
|
|
| 1663 |
|
flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_READONLY |
| 1664 |
|
| SEC_HAS_CONTENTS | SEC_IN_MEMORY); |
| 1665 |
stub = bfd_make_section_anyway_with_flags (ibfd, ".stub", flags); |
stub = bfd_make_section_anyway_with_flags (ibfd, ".stub", flags); |
| 1666 |
htab->stub_sec[ovl] = stub; |
htab->stub_sec[0] = stub; |
| 1667 |
if (stub == NULL |
if (stub == NULL |
| 1668 |
|| !bfd_set_section_alignment (ibfd, stub, |
|| !bfd_set_section_alignment (ibfd, stub, |
| 1669 |
htab->params->ovly_flavour + 3)) |
ovl_stub_size_log2 (htab->params))) |
| 1670 |
return 0; |
return 0; |
| 1671 |
stub->size = htab->stub_count[ovl] * ovl_stub_size (htab->params->ovly_flavour); |
stub->size = htab->stub_count[0] * ovl_stub_size (htab->params); |
| 1672 |
(*htab->params->place_spu_section) (stub, osec, NULL); |
if (htab->params->ovly_flavour == ovly_soft_icache) |
| 1673 |
|
/* Extra space for linked list entries. */ |
| 1674 |
|
stub->size += htab->stub_count[0] * 16; |
| 1675 |
|
|
| 1676 |
|
for (i = 0; i < htab->num_overlays; ++i) |
| 1677 |
|
{ |
| 1678 |
|
asection *osec = htab->ovl_sec[i]; |
| 1679 |
|
unsigned int ovl = spu_elf_section_data (osec)->u.o.ovl_index; |
| 1680 |
|
stub = bfd_make_section_anyway_with_flags (ibfd, ".stub", flags); |
| 1681 |
|
htab->stub_sec[ovl] = stub; |
| 1682 |
|
if (stub == NULL |
| 1683 |
|
|| !bfd_set_section_alignment (ibfd, stub, |
| 1684 |
|
ovl_stub_size_log2 (htab->params))) |
| 1685 |
|
return 0; |
| 1686 |
|
stub->size = htab->stub_count[ovl] * ovl_stub_size (htab->params); |
| 1687 |
|
} |
| 1688 |
} |
} |
| 1689 |
|
|
| 1690 |
/* htab->ovtab consists of two arrays. |
if (htab->params->ovly_flavour == ovly_soft_icache) |
| 1691 |
. struct { |
{ |
| 1692 |
. u32 vma; |
/* Space for icache manager tables. |
| 1693 |
. u32 size; |
a) Tag array, one quadword per cache line. |
| 1694 |
. u32 file_off; |
b) Rewrite "to" list, one quadword per cache line. |
| 1695 |
. u32 buf; |
c) Rewrite "from" list, one byte per outgoing branch (rounded up to |
| 1696 |
. } _ovly_table[]; |
a power-of-two number of full quadwords) per cache line. */ |
| 1697 |
. |
|
| 1698 |
. struct { |
flags = SEC_ALLOC; |
| 1699 |
. u32 mapped; |
htab->ovtab = bfd_make_section_anyway_with_flags (ibfd, ".ovtab", flags); |
| 1700 |
. } _ovly_buf_table[]; |
if (htab->ovtab == NULL |
| 1701 |
. */ |
|| !bfd_set_section_alignment (ibfd, htab->ovtab, 4)) |
| 1702 |
|
return 0; |
| 1703 |
flags = (SEC_ALLOC | SEC_LOAD |
|
| 1704 |
| SEC_HAS_CONTENTS | SEC_IN_MEMORY); |
htab->ovtab->size = (16 + 16 + (16 << htab->fromelem_size_log2)) |
| 1705 |
htab->ovtab = bfd_make_section_anyway_with_flags (ibfd, ".ovtab", flags); |
<< htab->num_lines_log2; |
| 1706 |
if (htab->ovtab == NULL |
|
| 1707 |
|| !bfd_set_section_alignment (ibfd, htab->ovtab, 4)) |
flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY; |
| 1708 |
return 0; |
htab->init = bfd_make_section_anyway_with_flags (ibfd, ".ovini", flags); |
| 1709 |
|
if (htab->init == NULL |
| 1710 |
|
|| !bfd_set_section_alignment (ibfd, htab->init, 4)) |
| 1711 |
|
return 0; |
| 1712 |
|
|
| 1713 |
|
htab->init->size = 16; |
| 1714 |
|
} |
| 1715 |
|
else if (htab->stub_count == NULL) |
| 1716 |
|
return 1; |
| 1717 |
|
else |
| 1718 |
|
{ |
| 1719 |
|
/* htab->ovtab consists of two arrays. |
| 1720 |
|
. struct { |
| 1721 |
|
. u32 vma; |
| 1722 |
|
. u32 size; |
| 1723 |
|
. u32 file_off; |
| 1724 |
|
. u32 buf; |
| 1725 |
|
. } _ovly_table[]; |
| 1726 |
|
. |
| 1727 |
|
. struct { |
| 1728 |
|
. u32 mapped; |
| 1729 |
|
. } _ovly_buf_table[]; |
| 1730 |
|
. */ |
| 1731 |
|
|
| 1732 |
|
flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY; |
| 1733 |
|
htab->ovtab = bfd_make_section_anyway_with_flags (ibfd, ".ovtab", flags); |
| 1734 |
|
if (htab->ovtab == NULL |
| 1735 |
|
|| !bfd_set_section_alignment (ibfd, htab->ovtab, 4)) |
| 1736 |
|
return 0; |
| 1737 |
|
|
| 1738 |
htab->ovtab->size = htab->num_overlays * 16 + 16 + htab->num_buf * 4; |
htab->ovtab->size = htab->num_overlays * 16 + 16 + htab->num_buf * 4; |
| 1739 |
(*htab->params->place_spu_section) (htab->ovtab, NULL, ".data"); |
} |
| 1740 |
|
|
| 1741 |
htab->toe = bfd_make_section_anyway_with_flags (ibfd, ".toe", SEC_ALLOC); |
htab->toe = bfd_make_section_anyway_with_flags (ibfd, ".toe", SEC_ALLOC); |
| 1742 |
if (htab->toe == NULL |
if (htab->toe == NULL |
| 1743 |
|| !bfd_set_section_alignment (ibfd, htab->toe, 4)) |
|| !bfd_set_section_alignment (ibfd, htab->toe, 4)) |
| 1744 |
return 0; |
return 0; |
| 1745 |
htab->toe->size = 16; |
htab->toe->size = 16; |
|
(*htab->params->place_spu_section) (htab->toe, NULL, ".toe"); |
|
| 1746 |
|
|
| 1747 |
return 2; |
return 2; |
| 1748 |
} |
} |
| 1749 |
|
|
| 1750 |
|
/* Called from ld to place overlay manager data sections. This is done |
| 1751 |
|
after the overlay manager itself is loaded, mainly so that the |
| 1752 |
|
linker's htab->init section is placed after any other .ovl.init |
| 1753 |
|
sections. */ |
| 1754 |
|
|
| 1755 |
|
void |
| 1756 |
|
spu_elf_place_overlay_data (struct bfd_link_info *info) |
| 1757 |
|
{ |
| 1758 |
|
struct spu_link_hash_table *htab = spu_hash_table (info); |
| 1759 |
|
unsigned int i; |
| 1760 |
|
|
| 1761 |
|
if (htab->stub_sec != NULL) |
| 1762 |
|
{ |
| 1763 |
|
(*htab->params->place_spu_section) (htab->stub_sec[0], NULL, ".text"); |
| 1764 |
|
|
| 1765 |
|
for (i = 0; i < htab->num_overlays; ++i) |
| 1766 |
|
{ |
| 1767 |
|
asection *osec = htab->ovl_sec[i]; |
| 1768 |
|
unsigned int ovl = spu_elf_section_data (osec)->u.o.ovl_index; |
| 1769 |
|
(*htab->params->place_spu_section) (htab->stub_sec[ovl], osec, NULL); |
| 1770 |
|
} |
| 1771 |
|
} |
| 1772 |
|
|
| 1773 |
|
if (htab->params->ovly_flavour == ovly_soft_icache) |
| 1774 |
|
(*htab->params->place_spu_section) (htab->init, NULL, ".ovl.init"); |
| 1775 |
|
|
| 1776 |
|
if (htab->ovtab != NULL) |
| 1777 |
|
{ |
| 1778 |
|
const char *ovout = ".data"; |
| 1779 |
|
if (htab->params->ovly_flavour == ovly_soft_icache) |
| 1780 |
|
ovout = ".bss"; |
| 1781 |
|
(*htab->params->place_spu_section) (htab->ovtab, NULL, ovout); |
| 1782 |
|
} |
| 1783 |
|
|
| 1784 |
|
if (htab->toe != NULL) |
| 1785 |
|
(*htab->params->place_spu_section) (htab->toe, NULL, ".toe"); |
| 1786 |
|
} |
| 1787 |
|
|
| 1788 |
/* Functions to handle embedded spu_ovl.o object. */ |
/* Functions to handle embedded spu_ovl.o object. */ |
| 1789 |
|
|
| 1790 |
static void * |
static void * |
| 1831 |
return *ovl_bfd != NULL; |
return *ovl_bfd != NULL; |
| 1832 |
} |
} |
| 1833 |
|
|
| 1834 |
|
static unsigned int |
| 1835 |
|
overlay_index (asection *sec) |
| 1836 |
|
{ |
| 1837 |
|
if (sec == NULL |
| 1838 |
|
|| sec->output_section == bfd_abs_section_ptr) |
| 1839 |
|
return 0; |
| 1840 |
|
return spu_elf_section_data (sec->output_section)->u.o.ovl_index; |
| 1841 |
|
} |
| 1842 |
|
|
| 1843 |
/* Define an STT_OBJECT symbol. */ |
/* Define an STT_OBJECT symbol. */ |
| 1844 |
|
|
| 1845 |
static struct elf_link_hash_entry * |
static struct elf_link_hash_entry * |
| 1883 |
|
|
| 1884 |
/* Fill in all stubs and the overlay tables. */ |
/* Fill in all stubs and the overlay tables. */ |
| 1885 |
|
|
| 1886 |
bfd_boolean |
static bfd_boolean |
| 1887 |
spu_elf_build_stubs (struct bfd_link_info *info) |
spu_elf_build_stubs (struct bfd_link_info *info) |
| 1888 |
{ |
{ |
| 1889 |
struct spu_link_hash_table *htab = spu_hash_table (info); |
struct spu_link_hash_table *htab = spu_hash_table (info); |
| 1893 |
bfd *obfd; |
bfd *obfd; |
| 1894 |
unsigned int i; |
unsigned int i; |
| 1895 |
|
|
| 1896 |
if (htab->stub_count == NULL) |
if (htab->num_overlays != 0) |
| 1897 |
return TRUE; |
{ |
| 1898 |
|
for (i = 0; i < 2; i++) |
| 1899 |
for (i = 0; i <= htab->num_overlays; i++) |
{ |
| 1900 |
if (htab->stub_sec[i]->size != 0) |
h = htab->ovly_entry[i]; |
| 1901 |
{ |
if (h != NULL |
|
htab->stub_sec[i]->contents = bfd_zalloc (htab->stub_sec[i]->owner, |
|
|
htab->stub_sec[i]->size); |
|
|
if (htab->stub_sec[i]->contents == NULL) |
|
|
return FALSE; |
|
|
htab->stub_sec[i]->rawsize = htab->stub_sec[i]->size; |
|
|
htab->stub_sec[i]->size = 0; |
|
|
} |
|
|
|
|
|
h = elf_link_hash_lookup (&htab->elf, "__ovly_load", FALSE, FALSE, FALSE); |
|
|
htab->ovly_load = h; |
|
|
BFD_ASSERT (h != NULL |
|
| 1902 |
&& (h->root.type == bfd_link_hash_defined |
&& (h->root.type == bfd_link_hash_defined |
| 1903 |
|| h->root.type == bfd_link_hash_defweak) |
|| h->root.type == bfd_link_hash_defweak) |
| 1904 |
&& h->def_regular); |
&& h->def_regular) |
| 1905 |
|
{ |
| 1906 |
s = h->root.u.def.section->output_section; |
s = h->root.u.def.section->output_section; |
| 1907 |
if (spu_elf_section_data (s)->u.o.ovl_index) |
if (spu_elf_section_data (s)->u.o.ovl_index) |
| 1908 |
{ |
{ |
| 1909 |
(*_bfd_error_handler) (_("%s in overlay section"), |
(*_bfd_error_handler) (_("%s in overlay section"), |
| 1910 |
h->root.root.string); |
h->root.root.string); |
| 1911 |
bfd_set_error (bfd_error_bad_value); |
bfd_set_error (bfd_error_bad_value); |
| 1912 |
return FALSE; |
return FALSE; |
| 1913 |
|
} |
| 1914 |
|
} |
| 1915 |
|
} |
| 1916 |
} |
} |
| 1917 |
|
|
| 1918 |
h = elf_link_hash_lookup (&htab->elf, "__ovly_return", FALSE, FALSE, FALSE); |
if (htab->stub_sec != NULL) |
|
htab->ovly_return = h; |
|
|
|
|
|
/* Fill in all the stubs. */ |
|
|
process_stubs (info, TRUE); |
|
|
if (!htab->stub_err) |
|
|
elf_link_hash_traverse (&htab->elf, build_spuear_stubs, info); |
|
|
|
|
|
if (htab->stub_err) |
|
| 1919 |
{ |
{ |
| 1920 |
(*_bfd_error_handler) (_("overlay stub relocation overflow")); |
for (i = 0; i <= htab->num_overlays; i++) |
| 1921 |
bfd_set_error (bfd_error_bad_value); |
if (htab->stub_sec[i]->size != 0) |
| 1922 |
return FALSE; |
{ |
| 1923 |
} |
htab->stub_sec[i]->contents = bfd_zalloc (htab->stub_sec[i]->owner, |
| 1924 |
|
htab->stub_sec[i]->size); |
| 1925 |
|
if (htab->stub_sec[i]->contents == NULL) |
| 1926 |
|
return FALSE; |
| 1927 |
|
htab->stub_sec[i]->rawsize = htab->stub_sec[i]->size; |
| 1928 |
|
htab->stub_sec[i]->size = 0; |
| 1929 |
|
} |
| 1930 |
|
|
| 1931 |
for (i = 0; i <= htab->num_overlays; i++) |
/* Fill in all the stubs. */ |
| 1932 |
{ |
process_stubs (info, TRUE); |
| 1933 |
if (htab->stub_sec[i]->size != htab->stub_sec[i]->rawsize) |
if (!htab->stub_err) |
| 1934 |
|
elf_link_hash_traverse (&htab->elf, build_spuear_stubs, info); |
| 1935 |
|
|
| 1936 |
|
if (htab->stub_err) |
| 1937 |
{ |
{ |
| 1938 |
(*_bfd_error_handler) (_("stubs don't match calculated size")); |
(*_bfd_error_handler) (_("overlay stub relocation overflow")); |
| 1939 |
bfd_set_error (bfd_error_bad_value); |
bfd_set_error (bfd_error_bad_value); |
| 1940 |
return FALSE; |
return FALSE; |
| 1941 |
} |
} |
| 1942 |
htab->stub_sec[i]->rawsize = 0; |
|
| 1943 |
|
for (i = 0; i <= htab->num_overlays; i++) |
| 1944 |
|
{ |
| 1945 |
|
if (htab->stub_sec[i]->size != htab->stub_sec[i]->rawsize) |
| 1946 |
|
{ |
| 1947 |
|
(*_bfd_error_handler) (_("stubs don't match calculated size")); |
| 1948 |
|
bfd_set_error (bfd_error_bad_value); |
| 1949 |
|
return FALSE; |
| 1950 |
|
} |
| 1951 |
|
htab->stub_sec[i]->rawsize = 0; |
| 1952 |
|
} |
| 1953 |
} |
} |
| 1954 |
|
|
| 1955 |
|
if (htab->ovtab == NULL || htab->ovtab->size == 0) |
| 1956 |
|
return TRUE; |
| 1957 |
|
|
| 1958 |
htab->ovtab->contents = bfd_zalloc (htab->ovtab->owner, htab->ovtab->size); |
htab->ovtab->contents = bfd_zalloc (htab->ovtab->owner, htab->ovtab->size); |
| 1959 |
if (htab->ovtab->contents == NULL) |
if (htab->ovtab->contents == NULL) |
| 1960 |
return FALSE; |
return FALSE; |
| 1961 |
|
|
|
/* Write out _ovly_table. */ |
|
| 1962 |
p = htab->ovtab->contents; |
p = htab->ovtab->contents; |
| 1963 |
/* set low bit of .size to mark non-overlay area as present. */ |
if (htab->params->ovly_flavour == ovly_soft_icache) |
|
p[7] = 1; |
|
|
obfd = htab->ovtab->output_section->owner; |
|
|
for (s = obfd->sections; s != NULL; s = s->next) |
|
| 1964 |
{ |
{ |
| 1965 |
unsigned int ovl_index = spu_elf_section_data (s)->u.o.ovl_index; |
bfd_vma off; |
| 1966 |
|
|
| 1967 |
|
h = define_ovtab_symbol (htab, "__icache_tag_array"); |
| 1968 |
|
if (h == NULL) |
| 1969 |
|
return FALSE; |
| 1970 |
|
h->root.u.def.value = 0; |
| 1971 |
|
h->size = 16 << htab->num_lines_log2; |
| 1972 |
|
off = h->size; |
| 1973 |
|
|
| 1974 |
|
h = define_ovtab_symbol (htab, "__icache_tag_array_size"); |
| 1975 |
|
if (h == NULL) |
| 1976 |
|
return FALSE; |
| 1977 |
|
h->root.u.def.value = 16 << htab->num_lines_log2; |
| 1978 |
|
h->root.u.def.section = bfd_abs_section_ptr; |
| 1979 |
|
|
| 1980 |
|
h = define_ovtab_symbol (htab, "__icache_rewrite_to"); |
| 1981 |
|
if (h == NULL) |
| 1982 |
|
return FALSE; |
| 1983 |
|
h->root.u.def.value = off; |
| 1984 |
|
h->size = 16 << htab->num_lines_log2; |
| 1985 |
|
off += h->size; |
| 1986 |
|
|
| 1987 |
|
h = define_ovtab_symbol (htab, "__icache_rewrite_to_size"); |
| 1988 |
|
if (h == NULL) |
| 1989 |
|
return FALSE; |
| 1990 |
|
h->root.u.def.value = 16 << htab->num_lines_log2; |
| 1991 |
|
h->root.u.def.section = bfd_abs_section_ptr; |
| 1992 |
|
|
| 1993 |
if (ovl_index != 0) |
h = define_ovtab_symbol (htab, "__icache_rewrite_from"); |
| 1994 |
|
if (h == NULL) |
| 1995 |
|
return FALSE; |
| 1996 |
|
h->root.u.def.value = off; |
| 1997 |
|
h->size = 16 << (htab->fromelem_size_log2 + htab->num_lines_log2); |
| 1998 |
|
off += h->size; |
| 1999 |
|
|
| 2000 |
|
h = define_ovtab_symbol (htab, "__icache_rewrite_from_size"); |
| 2001 |
|
if (h == NULL) |
| 2002 |
|
return FALSE; |
| 2003 |
|
h->root.u.def.value = 16 << (htab->fromelem_size_log2 |
| 2004 |
|
+ htab->num_lines_log2); |
| 2005 |
|
h->root.u.def.section = bfd_abs_section_ptr; |
| 2006 |
|
|
| 2007 |
|
h = define_ovtab_symbol (htab, "__icache_log2_fromelemsize"); |
| 2008 |
|
if (h == NULL) |
| 2009 |
|
return FALSE; |
| 2010 |
|
h->root.u.def.value = htab->fromelem_size_log2; |
| 2011 |
|
h->root.u.def.section = bfd_abs_section_ptr; |
| 2012 |
|
|
| 2013 |
|
h = define_ovtab_symbol (htab, "__icache_base"); |
| 2014 |
|
if (h == NULL) |
| 2015 |
|
return FALSE; |
| 2016 |
|
h->root.u.def.value = htab->ovl_sec[0]->vma; |
| 2017 |
|
h->root.u.def.section = bfd_abs_section_ptr; |
| 2018 |
|
h->size = htab->num_buf << htab->line_size_log2; |
| 2019 |
|
|
| 2020 |
|
h = define_ovtab_symbol (htab, "__icache_linesize"); |
| 2021 |
|
if (h == NULL) |
| 2022 |
|
return FALSE; |
| 2023 |
|
h->root.u.def.value = 1 << htab->line_size_log2; |
| 2024 |
|
h->root.u.def.section = bfd_abs_section_ptr; |
| 2025 |
|
|
| 2026 |
|
h = define_ovtab_symbol (htab, "__icache_log2_linesize"); |
| 2027 |
|
if (h == NULL) |
| 2028 |
|
return FALSE; |
| 2029 |
|
h->root.u.def.value = htab->line_size_log2; |
| 2030 |
|
h->root.u.def.section = bfd_abs_section_ptr; |
| 2031 |
|
|
| 2032 |
|
h = define_ovtab_symbol (htab, "__icache_neg_log2_linesize"); |
| 2033 |
|
if (h == NULL) |
| 2034 |
|
return FALSE; |
| 2035 |
|
h->root.u.def.value = -htab->line_size_log2; |
| 2036 |
|
h->root.u.def.section = bfd_abs_section_ptr; |
| 2037 |
|
|
| 2038 |
|
h = define_ovtab_symbol (htab, "__icache_cachesize"); |
| 2039 |
|
if (h == NULL) |
| 2040 |
|
return FALSE; |
| 2041 |
|
h->root.u.def.value = 1 << (htab->num_lines_log2 + htab->line_size_log2); |
| 2042 |
|
h->root.u.def.section = bfd_abs_section_ptr; |
| 2043 |
|
|
| 2044 |
|
h = define_ovtab_symbol (htab, "__icache_log2_cachesize"); |
| 2045 |
|
if (h == NULL) |
| 2046 |
|
return FALSE; |
| 2047 |
|
h->root.u.def.value = htab->num_lines_log2 + htab->line_size_log2; |
| 2048 |
|
h->root.u.def.section = bfd_abs_section_ptr; |
| 2049 |
|
|
| 2050 |
|
h = define_ovtab_symbol (htab, "__icache_neg_log2_cachesize"); |
| 2051 |
|
if (h == NULL) |
| 2052 |
|
return FALSE; |
| 2053 |
|
h->root.u.def.value = -(htab->num_lines_log2 + htab->line_size_log2); |
| 2054 |
|
h->root.u.def.section = bfd_abs_section_ptr; |
| 2055 |
|
|
| 2056 |
|
if (htab->init != NULL && htab->init->size != 0) |
| 2057 |
{ |
{ |
| 2058 |
unsigned long off = ovl_index * 16; |
htab->init->contents = bfd_zalloc (htab->init->owner, |
| 2059 |
unsigned int ovl_buf = spu_elf_section_data (s)->u.o.ovl_buf; |
htab->init->size); |
| 2060 |
|
if (htab->init->contents == NULL) |
| 2061 |
|
return FALSE; |
| 2062 |
|
|
| 2063 |
bfd_put_32 (htab->ovtab->owner, s->vma, p + off); |
h = define_ovtab_symbol (htab, "__icache_fileoff"); |
| 2064 |
bfd_put_32 (htab->ovtab->owner, (s->size + 15) & -16, p + off + 4); |
if (h == NULL) |
| 2065 |
/* file_off written later in spu_elf_modify_program_headers. */ |
return FALSE; |
| 2066 |
bfd_put_32 (htab->ovtab->owner, ovl_buf, p + off + 12); |
h->root.u.def.value = 0; |
| 2067 |
|
h->root.u.def.section = htab->init; |
| 2068 |
|
h->size = 8; |
| 2069 |
} |
} |
| 2070 |
} |
} |
| 2071 |
|
else |
| 2072 |
|
{ |
| 2073 |
|
/* Write out _ovly_table. */ |
| 2074 |
|
/* set low bit of .size to mark non-overlay area as present. */ |
| 2075 |
|
p[7] = 1; |
| 2076 |
|
obfd = htab->ovtab->output_section->owner; |
| 2077 |
|
for (s = obfd->sections; s != NULL; s = s->next) |
| 2078 |
|
{ |
| 2079 |
|
unsigned int ovl_index = spu_elf_section_data (s)->u.o.ovl_index; |
| 2080 |
|
|
| 2081 |
h = define_ovtab_symbol (htab, "_ovly_table"); |
if (ovl_index != 0) |
| 2082 |
if (h == NULL) |
{ |
| 2083 |
return FALSE; |
unsigned long off = ovl_index * 16; |
| 2084 |
h->root.u.def.value = 16; |
unsigned int ovl_buf = spu_elf_section_data (s)->u.o.ovl_buf; |
|
h->size = htab->num_overlays * 16; |
|
| 2085 |
|
|
| 2086 |
h = define_ovtab_symbol (htab, "_ovly_table_end"); |
bfd_put_32 (htab->ovtab->owner, s->vma, p + off); |
| 2087 |
if (h == NULL) |
bfd_put_32 (htab->ovtab->owner, (s->size + 15) & -16, |
| 2088 |
return FALSE; |
p + off + 4); |
| 2089 |
h->root.u.def.value = htab->num_overlays * 16 + 16; |
/* file_off written later in spu_elf_modify_program_headers. */ |
| 2090 |
h->size = 0; |
bfd_put_32 (htab->ovtab->owner, ovl_buf, p + off + 12); |
| 2091 |
|
} |
| 2092 |
|
} |
| 2093 |
|
|
| 2094 |
h = define_ovtab_symbol (htab, "_ovly_buf_table"); |
h = define_ovtab_symbol (htab, "_ovly_table"); |
| 2095 |
if (h == NULL) |
if (h == NULL) |
| 2096 |
return FALSE; |
return FALSE; |
| 2097 |
h->root.u.def.value = htab->num_overlays * 16 + 16; |
h->root.u.def.value = 16; |
| 2098 |
h->size = htab->num_buf * 4; |
h->size = htab->num_overlays * 16; |
| 2099 |
|
|
| 2100 |
h = define_ovtab_symbol (htab, "_ovly_buf_table_end"); |
h = define_ovtab_symbol (htab, "_ovly_table_end"); |
| 2101 |
if (h == NULL) |
if (h == NULL) |
| 2102 |
return FALSE; |
return FALSE; |
| 2103 |
h->root.u.def.value = htab->num_overlays * 16 + 16 + htab->num_buf * 4; |
h->root.u.def.value = htab->num_overlays * 16 + 16; |
| 2104 |
h->size = 0; |
h->size = 0; |
| 2105 |
|
|
| 2106 |
|
h = define_ovtab_symbol (htab, "_ovly_buf_table"); |
| 2107 |
|
if (h == NULL) |
| 2108 |
|
return FALSE; |
| 2109 |
|
h->root.u.def.value = htab->num_overlays * 16 + 16; |
| 2110 |
|
h->size = htab->num_buf * 4; |
| 2111 |
|
|
| 2112 |
|
h = define_ovtab_symbol (htab, "_ovly_buf_table_end"); |
| 2113 |
|
if (h == NULL) |
| 2114 |
|
return FALSE; |
| 2115 |
|
h->root.u.def.value = htab->num_overlays * 16 + 16 + htab->num_buf * 4; |
| 2116 |
|
h->size = 0; |
| 2117 |
|
} |
| 2118 |
|
|
| 2119 |
h = define_ovtab_symbol (htab, "_EAR_"); |
h = define_ovtab_symbol (htab, "_EAR_"); |
| 2120 |
if (h == NULL) |
if (h == NULL) |
| 2150 |
|| m->sections[i]->vma + m->sections[i]->size - 1 > hi)) |
|| m->sections[i]->vma + m->sections[i]->size - 1 > hi)) |
| 2151 |
return m->sections[i]; |
return m->sections[i]; |
| 2152 |
|
|
|
/* No need for overlays if it all fits. */ |
|
|
htab->params->auto_overlay = 0; |
|
| 2153 |
return NULL; |
return NULL; |
| 2154 |
} |
} |
| 2155 |
|
|
| 2156 |
/* OFFSET in SEC (presumably) is the beginning of a function prologue. |
/* OFFSET in SEC (presumably) is the beginning of a function prologue. |
| 2157 |
Search for stack adjusting insns, and return the sp delta. */ |
Search for stack adjusting insns, and return the sp delta. |
| 2158 |
|
If a store of lr is found save the instruction offset to *LR_STORE. |
| 2159 |
|
If a stack adjusting instruction is found, save that offset to |
| 2160 |
|
*SP_ADJUST. */ |
| 2161 |
|
|
| 2162 |
static int |
static int |
| 2163 |
find_function_stack_adjust (asection *sec, bfd_vma offset) |
find_function_stack_adjust (asection *sec, |
| 2164 |
|
bfd_vma offset, |
| 2165 |
|
bfd_vma *lr_store, |
| 2166 |
|
bfd_vma *sp_adjust) |
| 2167 |
{ |
{ |
| 2168 |
int reg[128]; |
int reg[128]; |
| 2169 |
|
|
| 2178 |
if (!bfd_get_section_contents (sec->owner, sec, buf, offset, 4)) |
if (!bfd_get_section_contents (sec->owner, sec, buf, offset, 4)) |
| 2179 |
break; |
break; |
| 2180 |
|
|
|
if (buf[0] == 0x24 /* stqd */) |
|
|
continue; |
|
|
|
|
| 2181 |
rt = buf[3] & 0x7f; |
rt = buf[3] & 0x7f; |
| 2182 |
ra = ((buf[2] & 0x3f) << 1) | (buf[3] >> 7); |
ra = ((buf[2] & 0x3f) << 1) | (buf[3] >> 7); |
| 2183 |
|
|
| 2184 |
|
if (buf[0] == 0x24 /* stqd */) |
| 2185 |
|
{ |
| 2186 |
|
if (rt == 0 /* lr */ && ra == 1 /* sp */) |
| 2187 |
|
*lr_store = offset; |
| 2188 |
|
continue; |
| 2189 |
|
} |
| 2190 |
|
|
| 2191 |
/* Partly decoded immediate field. */ |
/* Partly decoded immediate field. */ |
| 2192 |
imm = (buf[1] << 9) | (buf[2] << 1) | (buf[3] >> 7); |
imm = (buf[1] << 9) | (buf[2] << 1) | (buf[3] >> 7); |
| 2193 |
|
|
| 2201 |
{ |
{ |
| 2202 |
if (reg[rt] > 0) |
if (reg[rt] > 0) |
| 2203 |
break; |
break; |
| 2204 |
|
*sp_adjust = offset; |
| 2205 |
return reg[rt]; |
return reg[rt]; |
| 2206 |
} |
} |
| 2207 |
} |
} |
| 2214 |
{ |
{ |
| 2215 |
if (reg[rt] > 0) |
if (reg[rt] > 0) |
| 2216 |
break; |
break; |
| 2217 |
|
*sp_adjust = offset; |
| 2218 |
|
return reg[rt]; |
| 2219 |
|
} |
| 2220 |
|
} |
| 2221 |
|
else if (buf[0] == 0x08 && (buf[1] & 0xe0) == 0 /* sf */) |
| 2222 |
|
{ |
| 2223 |
|
int rb = ((buf[1] & 0x1f) << 2) | ((buf[2] & 0xc0) >> 6); |
| 2224 |
|
|
| 2225 |
|
reg[rt] = reg[rb] - reg[ra]; |
| 2226 |
|
if (rt == 1) |
| 2227 |
|
{ |
| 2228 |
|
if (reg[rt] > 0) |
| 2229 |
|
break; |
| 2230 |
|
*sp_adjust = offset; |
| 2231 |
return reg[rt]; |
return reg[rt]; |
| 2232 |
} |
} |
| 2233 |
} |
} |
| 2428 |
sinfo->fun[i].u.sym = sym_h; |
sinfo->fun[i].u.sym = sym_h; |
| 2429 |
sinfo->fun[i].lo = off; |
sinfo->fun[i].lo = off; |
| 2430 |
sinfo->fun[i].hi = off + size; |
sinfo->fun[i].hi = off + size; |
| 2431 |
sinfo->fun[i].stack = -find_function_stack_adjust (sec, off); |
sinfo->fun[i].lr_store = -1; |
| 2432 |
|
sinfo->fun[i].sp_adjust = -1; |
| 2433 |
|
sinfo->fun[i].stack = -find_function_stack_adjust (sec, off, |
| 2434 |
|
&sinfo->fun[i].lr_store, |
| 2435 |
|
&sinfo->fun[i].sp_adjust); |
| 2436 |
sinfo->num_fun += 1; |
sinfo->num_fun += 1; |
| 2437 |
return &sinfo->fun[i]; |
return &sinfo->fun[i]; |
| 2438 |
} |
} |
| 2575 |
} |
} |
| 2576 |
info->callbacks->einfo (_("%A:0x%v not found in function table\n"), |
info->callbacks->einfo (_("%A:0x%v not found in function table\n"), |
| 2577 |
sec, offset); |
sec, offset); |
| 2578 |
|
bfd_set_error (bfd_error_bad_value); |
| 2579 |
return NULL; |
return NULL; |
| 2580 |
} |
} |
| 2581 |
|
|
| 2599 |
p->fun->start = NULL; |
p->fun->start = NULL; |
| 2600 |
p->fun->is_func = TRUE; |
p->fun->is_func = TRUE; |
| 2601 |
} |
} |
| 2602 |
p->count += 1; |
p->count += callee->count; |
| 2603 |
/* Reorder list so most recent call is first. */ |
/* Reorder list so most recent call is first. */ |
| 2604 |
*pp = p->next; |
*pp = p->next; |
| 2605 |
p->next = caller->call_list; |
p->next = caller->call_list; |
| 2607 |
return FALSE; |
return FALSE; |
| 2608 |
} |
} |
| 2609 |
callee->next = caller->call_list; |
callee->next = caller->call_list; |
|
callee->count += 1; |
|
| 2610 |
caller->call_list = callee; |
caller->call_list = callee; |
| 2611 |
return TRUE; |
return TRUE; |
| 2612 |
} |
} |
| 2652 |
Elf_Internal_Rela *internal_relocs, *irelaend, *irela; |
Elf_Internal_Rela *internal_relocs, *irelaend, *irela; |
| 2653 |
Elf_Internal_Shdr *symtab_hdr; |
Elf_Internal_Shdr *symtab_hdr; |
| 2654 |
void *psyms; |
void *psyms; |
| 2655 |
|
unsigned int priority = 0; |
| 2656 |
static bfd_boolean warned; |
static bfd_boolean warned; |
| 2657 |
|
|
| 2658 |
if (!interesting_section (sec) |
if (!interesting_section (sec) |
| 2709 |
if (is_branch (insn)) |
if (is_branch (insn)) |
| 2710 |
{ |
{ |
| 2711 |
is_call = (insn[0] & 0xfd) == 0x31; |
is_call = (insn[0] & 0xfd) == 0x31; |
| 2712 |
|
priority = insn[1] & 0x0f; |
| 2713 |
|
priority <<= 8; |
| 2714 |
|
priority |= insn[2]; |
| 2715 |
|
priority <<= 8; |
| 2716 |
|
priority |= insn[3]; |
| 2717 |
|
priority >>= 7; |
| 2718 |
if ((sym_sec->flags & (SEC_ALLOC | SEC_LOAD | SEC_CODE)) |
if ((sym_sec->flags & (SEC_ALLOC | SEC_LOAD | SEC_CODE)) |
| 2719 |
!= (SEC_ALLOC | SEC_LOAD | SEC_CODE)) |
!= (SEC_ALLOC | SEC_LOAD | SEC_CODE)) |
| 2720 |
{ |
{ |
| 2795 |
return FALSE; |
return FALSE; |
| 2796 |
callee->is_tail = !is_call; |
callee->is_tail = !is_call; |
| 2797 |
callee->is_pasted = FALSE; |
callee->is_pasted = FALSE; |
| 2798 |
callee->count = 0; |
callee->broken_cycle = FALSE; |
| 2799 |
|
callee->priority = priority; |
| 2800 |
|
callee->count = 1; |
| 2801 |
if (callee->fun->last_caller != sec) |
if (callee->fun->last_caller != sec) |
| 2802 |
{ |
{ |
| 2803 |
callee->fun->last_caller = sec; |
callee->fun->last_caller = sec; |
| 2820 |
callee->fun->is_func = TRUE; |
callee->fun->is_func = TRUE; |
| 2821 |
} |
} |
| 2822 |
else if (callee->fun->start == NULL) |
else if (callee->fun->start == NULL) |
| 2823 |
callee->fun->start = caller; |
{ |
| 2824 |
|
struct function_info *caller_start = caller; |
| 2825 |
|
while (caller_start->start) |
| 2826 |
|
caller_start = caller_start->start; |
| 2827 |
|
|
| 2828 |
|
if (caller_start != callee->fun) |
| 2829 |
|
callee->fun->start = caller_start; |
| 2830 |
|
} |
| 2831 |
else |
else |
| 2832 |
{ |
{ |
| 2833 |
struct function_info *callee_start; |
struct function_info *callee_start; |
| 2854 |
These sections are pasted together to form a single function. */ |
These sections are pasted together to form a single function. */ |
| 2855 |
|
|
| 2856 |
static bfd_boolean |
static bfd_boolean |
| 2857 |
pasted_function (asection *sec, struct bfd_link_info *info) |
pasted_function (asection *sec) |
| 2858 |
{ |
{ |
| 2859 |
struct bfd_link_order *l; |
struct bfd_link_order *l; |
| 2860 |
struct _spu_elf_section_data *sec_data; |
struct _spu_elf_section_data *sec_data; |
| 2889 |
callee->fun = fun; |
callee->fun = fun; |
| 2890 |
callee->is_tail = TRUE; |
callee->is_tail = TRUE; |
| 2891 |
callee->is_pasted = TRUE; |
callee->is_pasted = TRUE; |
| 2892 |
callee->count = 0; |
callee->broken_cycle = FALSE; |
| 2893 |
|
callee->priority = 0; |
| 2894 |
|
callee->count = 1; |
| 2895 |
if (!insert_callee (fun_start, callee)) |
if (!insert_callee (fun_start, callee)) |
| 2896 |
free (callee); |
free (callee); |
| 2897 |
return TRUE; |
return TRUE; |
| 2905 |
fun_start = &sinfo->fun[sinfo->num_fun - 1]; |
fun_start = &sinfo->fun[sinfo->num_fun - 1]; |
| 2906 |
} |
} |
| 2907 |
|
|
| 2908 |
info->callbacks->einfo (_("%A link_order not found\n"), sec); |
/* Don't return an error if we did not find a function preceding this |
| 2909 |
return FALSE; |
section. The section may have incorrect flags. */ |
| 2910 |
|
return TRUE; |
| 2911 |
} |
} |
| 2912 |
|
|
| 2913 |
/* Map address ranges in code sections to functions. */ |
/* Map address ranges in code sections to functions. */ |
| 2931 |
sec_arr = bfd_zmalloc (bfd_idx * sizeof (*sec_arr)); |
sec_arr = bfd_zmalloc (bfd_idx * sizeof (*sec_arr)); |
| 2932 |
if (sec_arr == NULL) |
if (sec_arr == NULL) |
| 2933 |
return FALSE; |
return FALSE; |
|
|
|
| 2934 |
|
|
| 2935 |
for (ibfd = info->input_bfds, bfd_idx = 0; |
for (ibfd = info->input_bfds, bfd_idx = 0; |
| 2936 |
ibfd != NULL; |
ibfd != NULL; |
| 2985 |
sec_arr[bfd_idx] = psecs; |
sec_arr[bfd_idx] = psecs; |
| 2986 |
for (psy = psyms, p = psecs, sy = syms; sy < syms + symcount; ++p, ++sy) |
for (psy = psyms, p = psecs, sy = syms; sy < syms + symcount; ++p, ++sy) |
| 2987 |
if (ELF_ST_TYPE (sy->st_info) == STT_NOTYPE |
if (ELF_ST_TYPE (sy->st_info) == STT_NOTYPE |
| 2988 |
|| ELF_ST_TYPE (sy->st_info) == STT_FUNC |
|| ELF_ST_TYPE (sy->st_info) == STT_FUNC) |
|
|| ELF_ST_TYPE (sy->st_info) == STT_SECTION) |
|
| 2989 |
{ |
{ |
| 2990 |
asection *s; |
asection *s; |
| 2991 |
|
|
| 3115 |
|
|
| 3116 |
sec_data = spu_elf_section_data (sec); |
sec_data = spu_elf_section_data (sec); |
| 3117 |
sinfo = sec_data->u.i.stack_info; |
sinfo = sec_data->u.i.stack_info; |
| 3118 |
if (sinfo != NULL) |
if (sinfo != NULL && sinfo->num_fun != 0) |
| 3119 |
{ |
{ |
| 3120 |
int fun_idx; |
int fun_idx; |
| 3121 |
bfd_vma hi = sec->size; |
bfd_vma hi = sec->size; |
| 3125 |
sinfo->fun[fun_idx].hi = hi; |
sinfo->fun[fun_idx].hi = hi; |
| 3126 |
hi = sinfo->fun[fun_idx].lo; |
hi = sinfo->fun[fun_idx].lo; |
| 3127 |
} |
} |
| 3128 |
|
|
| 3129 |
|
sinfo->fun[0].lo = 0; |
| 3130 |
} |
} |
| 3131 |
/* No symbols in this section. Must be .init or .fini |
/* No symbols in this section. Must be .init or .fini |
| 3132 |
or something similar. */ |
or something similar. */ |
| 3133 |
else if (!pasted_function (sec, info)) |
else if (!pasted_function (sec)) |
| 3134 |
return FALSE; |
return FALSE; |
| 3135 |
} |
} |
| 3136 |
} |
} |
| 3259 |
callp = &fun->call_list; |
callp = &fun->call_list; |
| 3260 |
while ((call = *callp) != NULL) |
while ((call = *callp) != NULL) |
| 3261 |
{ |
{ |
| 3262 |
|
call->max_depth = depth + !call->is_pasted; |
| 3263 |
if (!call->fun->visit2) |
if (!call->fun->visit2) |
| 3264 |
{ |
{ |
|
call->max_depth = depth + !call->is_pasted; |
|
| 3265 |
if (!remove_cycles (call->fun, info, &call->max_depth)) |
if (!remove_cycles (call->fun, info, &call->max_depth)) |
| 3266 |
return FALSE; |
return FALSE; |
| 3267 |
if (max_depth < call->max_depth) |
if (max_depth < call->max_depth) |
| 3269 |
} |
} |
| 3270 |
else if (call->fun->marking) |
else if (call->fun->marking) |
| 3271 |
{ |
{ |
| 3272 |
if (!spu_hash_table (info)->params->auto_overlay) |
struct spu_link_hash_table *htab = spu_hash_table (info); |
| 3273 |
|
|
| 3274 |
|
if (!htab->params->auto_overlay |
| 3275 |
|
&& htab->params->stack_analysis) |
| 3276 |
{ |
{ |
| 3277 |
const char *f1 = func_name (fun); |
const char *f1 = func_name (fun); |
| 3278 |
const char *f2 = func_name (call->fun); |
const char *f2 = func_name (call->fun); |
| 3281 |
"from %s to %s\n"), |
"from %s to %s\n"), |
| 3282 |
f1, f2); |
f1, f2); |
| 3283 |
} |
} |
| 3284 |
*callp = call->next; |
|
| 3285 |
free (call); |
call->broken_cycle = TRUE; |
|
continue; |
|
| 3286 |
} |
} |
| 3287 |
callp = &call->next; |
callp = &call->next; |
| 3288 |
} |
} |
| 3348 |
return for_each_node (mark_detached_root, info, &depth, FALSE); |
return for_each_node (mark_detached_root, info, &depth, FALSE); |
| 3349 |
} |
} |
| 3350 |
|
|
| 3351 |
/* qsort predicate to sort calls by max_depth then count. */ |
/* qsort predicate to sort calls by priority, max_depth then count. */ |
| 3352 |
|
|
| 3353 |
static int |
static int |
| 3354 |
sort_calls (const void *a, const void *b) |
sort_calls (const void *a, const void *b) |
| 3357 |
struct call_info *const *c2 = b; |
struct call_info *const *c2 = b; |
| 3358 |
int delta; |
int delta; |
| 3359 |
|
|
| 3360 |
|
delta = (*c2)->priority - (*c1)->priority; |
| 3361 |
|
if (delta != 0) |
| 3362 |
|
return delta; |
| 3363 |
|
|
| 3364 |
delta = (*c2)->max_depth - (*c1)->max_depth; |
delta = (*c2)->max_depth - (*c1)->max_depth; |
| 3365 |
if (delta != 0) |
if (delta != 0) |
| 3366 |
return delta; |
return delta; |
| 3397 |
struct call_info *call; |
struct call_info *call; |
| 3398 |
unsigned int count; |
unsigned int count; |
| 3399 |
struct _mos_param *mos_param = param; |
struct _mos_param *mos_param = param; |
| 3400 |
|
struct spu_link_hash_table *htab = spu_hash_table (info); |
| 3401 |
|
|
| 3402 |
if (fun->visit4) |
if (fun->visit4) |
| 3403 |
return TRUE; |
return TRUE; |
| 3404 |
|
|
| 3405 |
fun->visit4 = TRUE; |
fun->visit4 = TRUE; |
| 3406 |
if (!fun->sec->linker_mark) |
if (!fun->sec->linker_mark |
| 3407 |
|
&& (htab->params->ovly_flavour != ovly_soft_icache |
| 3408 |
|
|| htab->params->non_ia_text |
| 3409 |
|
|| strncmp (fun->sec->name, ".text.ia.", 9) == 0 |
| 3410 |
|
|| strcmp (fun->sec->name, ".init") == 0 |
| 3411 |
|
|| strcmp (fun->sec->name, ".fini") == 0)) |
| 3412 |
{ |
{ |
| 3413 |
unsigned int size; |
unsigned int size; |
| 3414 |
|
|
| 3420 |
this flag to differentiate the two overlay section types. */ |
this flag to differentiate the two overlay section types. */ |
| 3421 |
fun->sec->flags |= SEC_CODE; |
fun->sec->flags |= SEC_CODE; |
| 3422 |
|
|
| 3423 |
if (spu_hash_table (info)->params->auto_overlay & OVERLAY_RODATA) |
size = fun->sec->size; |
| 3424 |
|
if (htab->params->auto_overlay & OVERLAY_RODATA) |
| 3425 |
{ |
{ |
| 3426 |
char *name = NULL; |
char *name = NULL; |
| 3427 |
|
|
| 3472 |
fun->rodata = rodata; |
fun->rodata = rodata; |
| 3473 |
if (fun->rodata) |
if (fun->rodata) |
| 3474 |
{ |
{ |
| 3475 |
fun->rodata->linker_mark = 1; |
size += fun->rodata->size; |
| 3476 |
fun->rodata->gc_mark = 1; |
if (htab->params->line_size != 0 |
| 3477 |
fun->rodata->flags &= ~SEC_CODE; |
&& size > htab->params->line_size) |
| 3478 |
|
{ |
| 3479 |
|
size -= fun->rodata->size; |
| 3480 |
|
fun->rodata = NULL; |
| 3481 |
|
} |
| 3482 |
|
else |
| 3483 |
|
{ |
| 3484 |
|
fun->rodata->linker_mark = 1; |
| 3485 |
|
fun->rodata->gc_mark = 1; |
| 3486 |
|
fun->rodata->flags &= ~SEC_CODE; |
| 3487 |
|
} |
| 3488 |
} |
} |
| 3489 |
free (name); |
free (name); |
| 3490 |
} |
} |
| 3491 |
} |
} |
|
size = fun->sec->size; |
|
|
if (fun->rodata) |
|
|
size += fun->rodata->size; |
|
| 3492 |
if (mos_param->max_overlay_size < size) |
if (mos_param->max_overlay_size < size) |
| 3493 |
mos_param->max_overlay_size = size; |
mos_param->max_overlay_size = size; |
| 3494 |
} |
} |
| 3525 |
BFD_ASSERT (!fun->sec->segment_mark); |
BFD_ASSERT (!fun->sec->segment_mark); |
| 3526 |
fun->sec->segment_mark = 1; |
fun->sec->segment_mark = 1; |
| 3527 |
} |
} |
| 3528 |
if (!mark_overlay_section (call->fun, info, param)) |
if (!call->broken_cycle |
| 3529 |
|
&& !mark_overlay_section (call->fun, info, param)) |
| 3530 |
return FALSE; |
return FALSE; |
| 3531 |
} |
} |
| 3532 |
|
|
| 3533 |
/* Don't put entry code into an overlay. The overlay manager needs |
/* Don't put entry code into an overlay. The overlay manager needs |
| 3534 |
a stack! */ |
a stack! Also, don't mark .ovl.init as an overlay. */ |
| 3535 |
if (fun->lo + fun->sec->output_offset + fun->sec->output_section->vma |
if (fun->lo + fun->sec->output_offset + fun->sec->output_section->vma |
| 3536 |
== info->output_bfd->start_address) |
== info->output_bfd->start_address |
| 3537 |
|
|| strncmp (fun->sec->output_section->name, ".ovl.init", 9) == 0) |
| 3538 |
{ |
{ |
| 3539 |
fun->sec->linker_mark = 0; |
fun->sec->linker_mark = 0; |
| 3540 |
if (fun->rodata != NULL) |
if (fun->rodata != NULL) |
| 3586 |
} |
} |
| 3587 |
|
|
| 3588 |
for (call = fun->call_list; call != NULL; call = call->next) |
for (call = fun->call_list; call != NULL; call = call->next) |
| 3589 |
if (!unmark_overlay_section (call->fun, info, param)) |
if (!call->broken_cycle |
| 3590 |
|
&& !unmark_overlay_section (call->fun, info, param)) |
| 3591 |
return FALSE; |
return FALSE; |
| 3592 |
|
|
| 3593 |
if (RECURSE_UNMARK) |
if (RECURSE_UNMARK) |
| 3623 |
size = fun->sec->size; |
size = fun->sec->size; |
| 3624 |
if (fun->rodata) |
if (fun->rodata) |
| 3625 |
size += fun->rodata->size; |
size += fun->rodata->size; |
| 3626 |
|
|
| 3627 |
if (size <= lib_param->lib_size) |
if (size <= lib_param->lib_size) |
| 3628 |
{ |
{ |
| 3629 |
*lib_param->lib_sections++ = fun->sec; |
*lib_param->lib_sections++ = fun->sec; |
| 3638 |
} |
} |
| 3639 |
|
|
| 3640 |
for (call = fun->call_list; call != NULL; call = call->next) |
for (call = fun->call_list; call != NULL; call = call->next) |
| 3641 |
collect_lib_sections (call->fun, info, param); |
if (!call->broken_cycle) |
| 3642 |
|
collect_lib_sections (call->fun, info, param); |
| 3643 |
|
|
| 3644 |
return TRUE; |
return TRUE; |
| 3645 |
} |
} |
| 3753 |
if (p->fun == call->fun) |
if (p->fun == call->fun) |
| 3754 |
break; |
break; |
| 3755 |
if (!p) |
if (!p) |
| 3756 |
stub_size += ovl_stub_size (htab->params->ovly_flavour); |
stub_size += ovl_stub_size (htab->params); |
| 3757 |
} |
} |
| 3758 |
} |
} |
| 3759 |
if (tmp + stub_size < lib_size) |
if (tmp + stub_size < lib_size) |
| 3771 |
while ((p = *pp) != NULL) |
while ((p = *pp) != NULL) |
| 3772 |
if (!p->fun->sec->linker_mark) |
if (!p->fun->sec->linker_mark) |
| 3773 |
{ |
{ |
| 3774 |
lib_size += ovl_stub_size (htab->params->ovly_flavour); |
lib_size += ovl_stub_size (htab->params); |
| 3775 |
*pp = p->next; |
*pp = p->next; |
| 3776 |
free (p); |
free (p); |
| 3777 |
} |
} |
| 3833 |
|
|
| 3834 |
fun->visit7 = TRUE; |
fun->visit7 = TRUE; |
| 3835 |
for (call = fun->call_list; call != NULL; call = call->next) |
for (call = fun->call_list; call != NULL; call = call->next) |
| 3836 |
if (!call->is_pasted) |
if (!call->is_pasted && !call->broken_cycle) |
| 3837 |
{ |
{ |
| 3838 |
if (!collect_overlays (call->fun, info, ovly_sections)) |
if (!collect_overlays (call->fun, info, ovly_sections)) |
| 3839 |
return FALSE; |
return FALSE; |
| 3879 |
} |
} |
| 3880 |
|
|
| 3881 |
for (call = fun->call_list; call != NULL; call = call->next) |
for (call = fun->call_list; call != NULL; call = call->next) |
| 3882 |
if (!collect_overlays (call->fun, info, ovly_sections)) |
if (!call->broken_cycle |
| 3883 |
|
&& !collect_overlays (call->fun, info, ovly_sections)) |
| 3884 |
return FALSE; |
return FALSE; |
| 3885 |
|
|
| 3886 |
if (added_fun) |
if (added_fun) |
| 3931 |
max = NULL; |
max = NULL; |
| 3932 |
for (call = fun->call_list; call; call = call->next) |
for (call = fun->call_list; call; call = call->next) |
| 3933 |
{ |
{ |
| 3934 |
|
if (call->broken_cycle) |
| 3935 |
|
continue; |
| 3936 |
if (!call->is_pasted) |
if (!call->is_pasted) |
| 3937 |
has_call = TRUE; |
has_call = TRUE; |
| 3938 |
if (!sum_stack (call->fun, info, sum_stack_param)) |
if (!sum_stack (call->fun, info, sum_stack_param)) |
| 3965 |
return TRUE; |
return TRUE; |
| 3966 |
|
|
| 3967 |
f1 = func_name (fun); |
f1 = func_name (fun); |
| 3968 |
if (!fun->non_root) |
if (htab->params->stack_analysis) |
| 3969 |
info->callbacks->info (_(" %s: 0x%v\n"), f1, (bfd_vma) cum_stack); |
{ |
| 3970 |
info->callbacks->minfo (_("%s: 0x%v 0x%v\n"), |
if (!fun->non_root) |
| 3971 |
f1, (bfd_vma) stack, (bfd_vma) cum_stack); |
info->callbacks->info (_(" %s: 0x%v\n"), f1, (bfd_vma) cum_stack); |
| 3972 |
|
info->callbacks->minfo (_("%s: 0x%v 0x%v\n"), |
| 3973 |
if (has_call) |
f1, (bfd_vma) stack, (bfd_vma) cum_stack); |
| 3974 |
{ |
|
| 3975 |
info->callbacks->minfo (_(" calls:\n")); |
if (has_call) |
| 3976 |
for (call = fun->call_list; call; call = call->next) |
{ |
| 3977 |
if (!call->is_pasted) |
info->callbacks->minfo (_(" calls:\n")); |
| 3978 |
{ |
for (call = fun->call_list; call; call = call->next) |
| 3979 |
const char *f2 = func_name (call->fun); |
if (!call->is_pasted && !call->broken_cycle) |
| 3980 |
const char *ann1 = call->fun == max ? "*" : " "; |
{ |
| 3981 |
const char *ann2 = call->is_tail ? "t" : " "; |
const char *f2 = func_name (call->fun); |
| 3982 |
|
const char *ann1 = call->fun == max ? "*" : " "; |
| 3983 |
|
const char *ann2 = call->is_tail ? "t" : " "; |
| 3984 |
|
|
| 3985 |
info->callbacks->minfo (_(" %s%s %s\n"), ann1, ann2, f2); |
info->callbacks->minfo (_(" %s%s %s\n"), ann1, ann2, f2); |
| 3986 |
} |
} |
| 3987 |
|
} |
| 3988 |
} |
} |
| 3989 |
|
|
| 3990 |
if (sum_stack_param->emit_stack_syms) |
if (sum_stack_param->emit_stack_syms) |
| 4053 |
return strcmp ((*abfd1)->filename, (*abfd2)->filename); |
return strcmp ((*abfd1)->filename, (*abfd2)->filename); |
| 4054 |
} |
} |
| 4055 |
|
|
| 4056 |
/* Handle --auto-overlay. */ |
static unsigned int |
| 4057 |
|
print_one_overlay_section (FILE *script, |
| 4058 |
|
unsigned int base, |
| 4059 |
|
unsigned int count, |
| 4060 |
|
unsigned int ovlynum, |
| 4061 |
|
unsigned int *ovly_map, |
| 4062 |
|
asection **ovly_sections, |
| 4063 |
|
struct bfd_link_info *info) |
| 4064 |
|
{ |
| 4065 |
|
unsigned int j; |
| 4066 |
|
|
| 4067 |
|
for (j = base; j < count && ovly_map[j] == ovlynum; j++) |
| 4068 |
|
{ |
| 4069 |
|
asection *sec = ovly_sections[2 * j]; |
| 4070 |
|
|
| 4071 |
static void spu_elf_auto_overlay (struct bfd_link_info *) |
if (fprintf (script, " %s%c%s (%s)\n", |
| 4072 |
ATTRIBUTE_NORETURN; |
(sec->owner->my_archive != NULL |
| 4073 |
|
? sec->owner->my_archive->filename : ""), |
| 4074 |
|
info->path_separator, |
| 4075 |
|
sec->owner->filename, |
| 4076 |
|
sec->name) <= 0) |
| 4077 |
|
return -1; |
| 4078 |
|
if (sec->segment_mark) |
| 4079 |
|
{ |
| 4080 |
|
struct call_info *call = find_pasted_call (sec); |
| 4081 |
|
while (call != NULL) |
| 4082 |
|
{ |
| 4083 |
|
struct function_info *call_fun = call->fun; |
| 4084 |
|
sec = call_fun->sec; |
| 4085 |
|
if (fprintf (script, " %s%c%s (%s)\n", |
| 4086 |
|
(sec->owner->my_archive != NULL |
| 4087 |
|
? sec->owner->my_archive->filename : ""), |
| 4088 |
|
info->path_separator, |
| 4089 |
|
sec->owner->filename, |
| 4090 |
|
sec->name) <= 0) |
| 4091 |
|
return -1; |
| 4092 |
|
for (call = call_fun->call_list; call; call = call->next) |
| 4093 |
|
if (call->is_pasted) |
| 4094 |
|
break; |
| 4095 |
|
} |
| 4096 |
|
} |
| 4097 |
|
} |
| 4098 |
|
|
| 4099 |
|
for (j = base; j < count && ovly_map[j] == ovlynum; j++) |
| 4100 |
|
{ |
| 4101 |
|
asection *sec = ovly_sections[2 * j + 1]; |
| 4102 |
|
if (sec != NULL |
| 4103 |
|
&& fprintf (script, " %s%c%s (%s)\n", |
| 4104 |
|
(sec->owner->my_archive != NULL |
| 4105 |
|
? sec->owner->my_archive->filename : ""), |
| 4106 |
|
info->path_separator, |
| 4107 |
|
sec->owner->filename, |
| 4108 |
|
sec->name) <= 0) |
| 4109 |
|
return -1; |
| 4110 |
|
|
| 4111 |
|
sec = ovly_sections[2 * j]; |
| 4112 |
|
if (sec->segment_mark) |
| 4113 |
|
{ |
| 4114 |
|
struct call_info *call = find_pasted_call (sec); |
| 4115 |
|
while (call != NULL) |
| 4116 |
|
{ |
| 4117 |
|
struct function_info *call_fun = call->fun; |
| 4118 |
|
sec = call_fun->rodata; |
| 4119 |
|
if (sec != NULL |
| 4120 |
|
&& fprintf (script, " %s%c%s (%s)\n", |
| 4121 |
|
(sec->owner->my_archive != NULL |
| 4122 |
|
? sec->owner->my_archive->filename : ""), |
| 4123 |
|
info->path_separator, |
| 4124 |
|
sec->owner->filename, |
| 4125 |
|
sec->name) <= 0) |
| 4126 |
|
return -1; |
| 4127 |
|
for (call = call_fun->call_list; call; call = call->next) |
| 4128 |
|
if (call->is_pasted) |
| 4129 |
|
break; |
| 4130 |
|
} |
| 4131 |
|
} |
| 4132 |
|
} |
| 4133 |
|
|
| 4134 |
|
return j; |
| 4135 |
|
} |
| 4136 |
|
|
| 4137 |
|
/* Handle --auto-overlay. */ |
| 4138 |
|
|
| 4139 |
static void |
static void |
| 4140 |
spu_elf_auto_overlay (struct bfd_link_info *info) |
spu_elf_auto_overlay (struct bfd_link_info *info) |
| 4150 |
unsigned int *ovly_map; |
unsigned int *ovly_map; |
| 4151 |
FILE *script; |
FILE *script; |
| 4152 |
unsigned int total_overlay_size, overlay_size; |
unsigned int total_overlay_size, overlay_size; |
| 4153 |
|
const char *ovly_mgr_entry; |
| 4154 |
struct elf_link_hash_entry *h; |
struct elf_link_hash_entry *h; |
| 4155 |
struct _mos_param mos_param; |
struct _mos_param mos_param; |
| 4156 |
struct _uos_param uos_param; |
struct _uos_param uos_param; |
| 4177 |
if (!build_call_tree (info)) |
if (!build_call_tree (info)) |
| 4178 |
goto err_exit; |
goto err_exit; |
| 4179 |
|
|
| 4180 |
|
htab = spu_hash_table (info); |
| 4181 |
|
if (htab->reserved == 0) |
| 4182 |
|
{ |
| 4183 |
|
struct _sum_stack_param sum_stack_param; |
| 4184 |
|
|
| 4185 |
|
sum_stack_param.emit_stack_syms = 0; |
| 4186 |
|
sum_stack_param.overall_stack = 0; |
| 4187 |
|
if (!for_each_node (sum_stack, info, &sum_stack_param, TRUE)) |
| 4188 |
|
goto err_exit; |
| 4189 |
|
htab->reserved = sum_stack_param.overall_stack + htab->extra_stack_space; |
| 4190 |
|
} |
| 4191 |
|
|
| 4192 |
|
/* No need for overlays if everything already fits. */ |
| 4193 |
|
if (fixed_size + htab->reserved <= htab->local_store |
| 4194 |
|
&& htab->params->ovly_flavour != ovly_soft_icache) |
| 4195 |
|
{ |
| 4196 |
|
htab->params->auto_overlay = 0; |
| 4197 |
|
return; |
| 4198 |
|
} |
| 4199 |
|
|
| 4200 |
uos_param.exclude_input_section = 0; |
uos_param.exclude_input_section = 0; |
| 4201 |
uos_param.exclude_output_section |
uos_param.exclude_output_section |
| 4202 |
= bfd_get_section_by_name (info->output_bfd, ".interrupt"); |
= bfd_get_section_by_name (info->output_bfd, ".interrupt"); |
| 4203 |
|
|
| 4204 |
htab = spu_hash_table (info); |
ovly_mgr_entry = "__ovly_load"; |
| 4205 |
h = elf_link_hash_lookup (&htab->elf, "__ovly_load", |
if (htab->params->ovly_flavour == ovly_soft_icache) |
| 4206 |
|
ovly_mgr_entry = "__icache_br_handler"; |
| 4207 |
|
h = elf_link_hash_lookup (&htab->elf, ovly_mgr_entry, |
| 4208 |
FALSE, FALSE, FALSE); |
FALSE, FALSE, FALSE); |
| 4209 |
if (h != NULL |
if (h != NULL |
| 4210 |
&& (h->root.type == bfd_link_hash_defined |
&& (h->root.type == bfd_link_hash_defined |
| 4263 |
fixed_size -= sec->size; |
fixed_size -= sec->size; |
| 4264 |
total_overlay_size += sec->size; |
total_overlay_size += sec->size; |
| 4265 |
} |
} |
| 4266 |
|
else if ((sec->flags & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD) |
| 4267 |
|
&& sec->output_section->owner == info->output_bfd |
| 4268 |
|
&& strncmp (sec->output_section->name, ".ovl.init", 9) == 0) |
| 4269 |
|
fixed_size -= sec->size; |
| 4270 |
if (count != old_count) |
if (count != old_count) |
| 4271 |
bfd_arr[bfd_count++] = ibfd; |
bfd_arr[bfd_count++] = ibfd; |
| 4272 |
} |
} |
| 4303 |
} |
} |
| 4304 |
free (bfd_arr); |
free (bfd_arr); |
| 4305 |
|
|
|
if (htab->reserved == 0) |
|
|
{ |
|
|
struct _sum_stack_param sum_stack_param; |
|
|
|
|
|
sum_stack_param.emit_stack_syms = 0; |
|
|
sum_stack_param.overall_stack = 0; |
|
|
if (!for_each_node (sum_stack, info, &sum_stack_param, TRUE)) |
|
|
goto err_exit; |
|
|
htab->reserved = sum_stack_param.overall_stack + htab->extra_stack_space; |
|
|
} |
|
| 4306 |
fixed_size += htab->reserved; |
fixed_size += htab->reserved; |
| 4307 |
fixed_size += htab->non_ovly_stub * ovl_stub_size (htab->params->ovly_flavour); |
fixed_size += htab->non_ovly_stub * ovl_stub_size (htab->params); |
| 4308 |
if (fixed_size + mos_param.max_overlay_size <= htab->local_store) |
if (fixed_size + mos_param.max_overlay_size <= htab->local_store) |
| 4309 |
{ |
{ |
| 4310 |
/* Guess number of overlays. Assuming overlay buffer is on |
if (htab->params->ovly_flavour == ovly_soft_icache) |
| 4311 |
average only half full should be conservative. */ |
{ |
| 4312 |
ovlynum = total_overlay_size * 2 / (htab->local_store - fixed_size); |
/* Stubs in the non-icache area are bigger. */ |
| 4313 |
/* Space for _ovly_table[], _ovly_buf_table[] and toe. */ |
fixed_size += htab->non_ovly_stub * 16; |
| 4314 |
fixed_size += ovlynum * 16 + 16 + 4 + 16; |
/* Space for icache manager tables. |
| 4315 |
|
a) Tag array, one quadword per cache line. |
| 4316 |
|
- word 0: ia address of present line, init to zero. */ |
| 4317 |
|
fixed_size += 16 << htab->num_lines_log2; |
| 4318 |
|
/* b) Rewrite "to" list, one quadword per cache line. */ |
| 4319 |
|
fixed_size += 16 << htab->num_lines_log2; |
| 4320 |
|
/* c) Rewrite "from" list, one byte per outgoing branch (rounded up |
| 4321 |
|
to a power-of-two number of full quadwords) per cache line. */ |
| 4322 |
|
fixed_size += 16 << (htab->fromelem_size_log2 |
| 4323 |
|
+ htab->num_lines_log2); |
| 4324 |
|
/* d) Pointer to __ea backing store (toe), 1 quadword. */ |
| 4325 |
|
fixed_size += 16; |
| 4326 |
|
} |
| 4327 |
|
else |
| 4328 |
|
{ |
| 4329 |
|
/* Guess number of overlays. Assuming overlay buffer is on |
| 4330 |
|
average only half full should be conservative. */ |
| 4331 |
|
ovlynum = (total_overlay_size * 2 * htab->params->num_lines |
| 4332 |
|
/ (htab->local_store - fixed_size)); |
| 4333 |
|
/* Space for _ovly_table[], _ovly_buf_table[] and toe. */ |
| 4334 |
|
fixed_size += ovlynum * 16 + 16 + 4 + 16; |
| 4335 |
|
} |
| 4336 |
} |
} |
| 4337 |
|
|
| 4338 |
if (fixed_size + mos_param.max_overlay_size > htab->local_store) |
if (fixed_size + mos_param.max_overlay_size > htab->local_store) |
| 4370 |
goto err_exit; |
goto err_exit; |
| 4371 |
|
|
| 4372 |
memset (&dummy_caller, 0, sizeof (dummy_caller)); |
memset (&dummy_caller, 0, sizeof (dummy_caller)); |
| 4373 |
overlay_size = (htab->local_store - fixed_size) / htab->params->num_regions; |
overlay_size = (htab->local_store - fixed_size) / htab->params->num_lines; |
| 4374 |
|
if (htab->params->line_size != 0) |
| 4375 |
|
overlay_size = htab->params->line_size; |
| 4376 |
base = 0; |
base = 0; |
| 4377 |
ovlynum = 0; |
ovlynum = 0; |
| 4378 |
while (base < count) |
while (base < count) |
| 4379 |
{ |
{ |
| 4380 |
unsigned int size = 0; |
unsigned int size = 0, rosize = 0, roalign = 0; |
| 4381 |
|
|
| 4382 |
for (i = base; i < count; i++) |
for (i = base; i < count; i++) |
| 4383 |
{ |
{ |
| 4384 |
asection *sec; |
asection *sec, *rosec; |
| 4385 |
unsigned int tmp; |
unsigned int tmp, rotmp; |
| 4386 |
unsigned int num_stubs; |
unsigned int num_stubs; |
| 4387 |
struct call_info *call, *pasty; |
struct call_info *call, *pasty; |
| 4388 |
struct _spu_elf_section_data *sec_data; |
struct _spu_elf_section_data *sec_data; |
| 4392 |
/* See whether we can add this section to the current |
/* See whether we can add this section to the current |
| 4393 |
overlay without overflowing our overlay buffer. */ |
overlay without overflowing our overlay buffer. */ |
| 4394 |
sec = ovly_sections[2 * i]; |
sec = ovly_sections[2 * i]; |
| 4395 |
tmp = size + sec->size; |
tmp = align_power (size, sec->alignment_power) + sec->size; |
| 4396 |
if (ovly_sections[2 * i + 1]) |
rotmp = rosize; |
| 4397 |
tmp += ovly_sections[2 * i + 1]->size; |
rosec = ovly_sections[2 * i + 1]; |
| 4398 |
if (tmp > overlay_size) |
if (rosec != NULL) |
| 4399 |
|
{ |
| 4400 |
|
rotmp = align_power (rotmp, rosec->alignment_power) + rosec->size; |
| 4401 |
|
if (roalign < rosec->alignment_power) |
| 4402 |
|
roalign = rosec->alignment_power; |
| 4403 |
|
} |
| 4404 |
|
if (align_power (tmp, roalign) + rotmp > overlay_size) |
| 4405 |
break; |
break; |
| 4406 |
if (sec->segment_mark) |
if (sec->segment_mark) |
| 4407 |
{ |
{ |
| 4411 |
while (pasty != NULL) |
while (pasty != NULL) |
| 4412 |
{ |
{ |
| 4413 |
struct function_info *call_fun = pasty->fun; |
struct function_info *call_fun = pasty->fun; |
| 4414 |
tmp += call_fun->sec->size; |
tmp = (align_power (tmp, call_fun->sec->alignment_power) |
| 4415 |
|
+ call_fun->sec->size); |
| 4416 |
if (call_fun->rodata) |
if (call_fun->rodata) |
| 4417 |
tmp += call_fun->rodata->size; |
{ |
| 4418 |
|
rotmp = (align_power (rotmp, |
| 4419 |
|
call_fun->rodata->alignment_power) |
| 4420 |
|
+ call_fun->rodata->size); |
| 4421 |
|
if (roalign < rosec->alignment_power) |
| 4422 |
|
roalign = rosec->alignment_power; |
| 4423 |
|
} |
| 4424 |
for (pasty = call_fun->call_list; pasty; pasty = pasty->next) |
for (pasty = call_fun->call_list; pasty; pasty = pasty->next) |
| 4425 |
if (pasty->is_pasted) |
if (pasty->is_pasted) |
| 4426 |
break; |
break; |
| 4427 |
} |
} |
| 4428 |
} |
} |
| 4429 |
if (tmp > overlay_size) |
if (align_power (tmp, roalign) + rotmp > overlay_size) |
| 4430 |
break; |
break; |
| 4431 |
|
|
| 4432 |
/* If we add this section, we might need new overlay call |
/* If we add this section, we might need new overlay call |
| 4465 |
for (call = dummy_caller.call_list; call; call = call->next) |
for (call = dummy_caller.call_list; call; call = call->next) |
| 4466 |
{ |
{ |
| 4467 |
unsigned int k; |
unsigned int k; |
| 4468 |
|
unsigned int stub_delta = 1; |
| 4469 |
|
|
| 4470 |
|
if (htab->params->ovly_flavour == ovly_soft_icache) |
| 4471 |
|
stub_delta = call->count; |
| 4472 |
|
num_stubs += stub_delta; |
| 4473 |
|
|
|
++num_stubs; |
|
| 4474 |
/* If the call is within this overlay, we won't need a |
/* If the call is within this overlay, we won't need a |
| 4475 |
stub. */ |
stub. */ |
| 4476 |
for (k = base; k < i + 1; k++) |
for (k = base; k < i + 1; k++) |
| 4477 |
if (call->fun->sec == ovly_sections[2 * k]) |
if (call->fun->sec == ovly_sections[2 * k]) |
| 4478 |
{ |
{ |
| 4479 |
--num_stubs; |
num_stubs -= stub_delta; |
| 4480 |
break; |
break; |
| 4481 |
} |
} |
| 4482 |
} |
} |
| 4483 |
if (tmp + num_stubs * ovl_stub_size (htab->params->ovly_flavour) |
if (htab->params->ovly_flavour == ovly_soft_icache |
| 4484 |
> overlay_size) |
&& num_stubs > htab->params->max_branch) |
| 4485 |
|
break; |
| 4486 |
|
if (align_power (tmp, roalign) + rotmp |
| 4487 |
|
+ num_stubs * ovl_stub_size (htab->params) > overlay_size) |
| 4488 |
break; |
break; |
|
|
|
| 4489 |
size = tmp; |
size = tmp; |
| 4490 |
|
rosize = rotmp; |
| 4491 |
} |
} |
| 4492 |
|
|
| 4493 |
if (i == base) |
if (i == base) |
| 4517 |
if (fprintf (script, "SECTIONS\n{\n") <= 0) |
if (fprintf (script, "SECTIONS\n{\n") <= 0) |
| 4518 |
goto file_err; |
goto file_err; |
| 4519 |
|
|
| 4520 |
for (region = 1; region <= htab->params->num_regions; region++) |
if (htab->params->ovly_flavour == ovly_soft_icache) |
| 4521 |
{ |
{ |
| 4522 |
ovlynum = region; |
if (fprintf (script, |
| 4523 |
|
" .data.icache ALIGN (16) : { *(.ovtab) *(.data.icache) }\n" |
| 4524 |
|
" . = ALIGN (%u);\n" |
| 4525 |
|
" .ovl.init : { *(.ovl.init) }\n" |
| 4526 |
|
" . = ABSOLUTE (ADDR (.ovl.init));\n", |
| 4527 |
|
htab->params->line_size) <= 0) |
| 4528 |
|
goto file_err; |
| 4529 |
|
|
| 4530 |
base = 0; |
base = 0; |
| 4531 |
while (base < count && ovly_map[base] < ovlynum) |
ovlynum = 1; |
| 4532 |
base++; |
while (base < count) |
| 4533 |
|
{ |
| 4534 |
|
unsigned int indx = ovlynum - 1; |
| 4535 |
|
unsigned int vma, lma; |
| 4536 |
|
|
| 4537 |
if (base == count) |
vma = (indx & (htab->params->num_lines - 1)) << htab->line_size_log2; |
| 4538 |
break; |
lma = indx << htab->line_size_log2; |
| 4539 |
|
|
| 4540 |
|
if (fprintf (script, " .ovly%u ABSOLUTE (ADDR (.ovl.init)) + %u " |
| 4541 |
|
": AT (ALIGN (LOADADDR (.ovl.init) + SIZEOF (.ovl.init), 16) + %u) {\n", |
| 4542 |
|
ovlynum, vma, lma) <= 0) |
| 4543 |
|
goto file_err; |
| 4544 |
|
|
| 4545 |
|
base = print_one_overlay_section (script, base, count, ovlynum, |
| 4546 |
|
ovly_map, ovly_sections, info); |
| 4547 |
|
if (base == (unsigned) -1) |
| 4548 |
|
goto file_err; |
| 4549 |
|
|
| 4550 |
if (fprintf (script, " OVERLAY :\n {\n") <= 0) |
if (fprintf (script, " }\n") <= 0) |
| 4551 |
|
goto file_err; |
| 4552 |
|
|
| 4553 |
|
ovlynum++; |
| 4554 |
|
} |
| 4555 |
|
|
| 4556 |
|
if (fprintf (script, " . = ABSOLUTE (ADDR (.ovl.init)) + %u;\n", |
| 4557 |
|
1 << (htab->num_lines_log2 + htab->line_size_log2)) <= 0) |
| 4558 |
|
goto file_err; |
| 4559 |
|
} |
| 4560 |
|
else |
| 4561 |
|
{ |
| 4562 |
|
if (fprintf (script, |
| 4563 |
|
" . = ALIGN (16);\n" |
| 4564 |
|
" .ovl.init : { *(.ovl.init) }\n" |
| 4565 |
|
" . = ABSOLUTE (ADDR (.ovl.init));\n") <= 0) |
| 4566 |
goto file_err; |
goto file_err; |
| 4567 |
|
|
| 4568 |
while (base < count) |
for (region = 1; region <= htab->params->num_lines; region++) |
| 4569 |
{ |
{ |
| 4570 |
unsigned int j; |
ovlynum = region; |
| 4571 |
|
base = 0; |
| 4572 |
if (fprintf (script, " .ovly%u {\n", ovlynum) <= 0) |
while (base < count && ovly_map[base] < ovlynum) |
| 4573 |
goto file_err; |
base++; |
| 4574 |
|
|
| 4575 |
for (j = base; j < count && ovly_map[j] == ovlynum; j++) |
if (base == count) |
| 4576 |
{ |
break; |
|
asection *sec = ovly_sections[2 * j]; |
|
| 4577 |
|
|
| 4578 |
if (fprintf (script, " %s%c%s (%s)\n", |
if (region == 1) |
| 4579 |
(sec->owner->my_archive != NULL |
{ |
| 4580 |
? sec->owner->my_archive->filename : ""), |
/* We need to set lma since we are overlaying .ovl.init. */ |
| 4581 |
info->path_separator, |
if (fprintf (script, |
| 4582 |
sec->owner->filename, |
" OVERLAY : AT (ALIGN (LOADADDR (.ovl.init) + SIZEOF (.ovl.init), 16))\n {\n") <= 0) |
| 4583 |
sec->name) <= 0) |
goto file_err; |
| 4584 |
|
} |
| 4585 |
|
else |
| 4586 |
|
{ |
| 4587 |
|
if (fprintf (script, " OVERLAY :\n {\n") <= 0) |
| 4588 |
goto file_err; |
goto file_err; |
|
if (sec->segment_mark) |
|
|
{ |
|
|
struct call_info *call = find_pasted_call (sec); |
|
|
while (call != NULL) |
|
|
{ |
|
|
struct function_info *call_fun = call->fun; |
|
|
sec = call_fun->sec; |
|
|
if (fprintf (script, " %s%c%s (%s)\n", |
|
|
(sec->owner->my_archive != NULL |
|
|
? sec->owner->my_archive->filename : ""), |
|
|
info->path_separator, |
|
|
sec->owner->filename, |
|
|
sec->name) <= 0) |
|
|
goto file_err; |
|
|
for (call = call_fun->call_list; call; call = call->next) |
|
|
if (call->is_pasted) |
|
|
break; |
|
|
} |
|
|
} |
|
| 4589 |
} |
} |
| 4590 |
|
|
| 4591 |
for (j = base; j < count && ovly_map[j] == ovlynum; j++) |
while (base < count) |
| 4592 |
{ |
{ |
| 4593 |
asection *sec = ovly_sections[2 * j + 1]; |
if (fprintf (script, " .ovly%u {\n", ovlynum) <= 0) |
|
if (sec != NULL |
|
|
&& fprintf (script, " %s%c%s (%s)\n", |
|
|
(sec->owner->my_archive != NULL |
|
|
? sec->owner->my_archive->filename : ""), |
|
|
info->path_separator, |
|
|
sec->owner->filename, |
|
|
sec->name) <= 0) |
|
| 4594 |
goto file_err; |
goto file_err; |
| 4595 |
|
|
| 4596 |
sec = ovly_sections[2 * j]; |
base = print_one_overlay_section (script, base, count, ovlynum, |
| 4597 |
if (sec->segment_mark) |
ovly_map, ovly_sections, info); |
| 4598 |
{ |
if (base == (unsigned) -1) |
| 4599 |
struct call_info *call = find_pasted_call (sec); |
goto file_err; |
| 4600 |
while (call != NULL) |
|
| 4601 |
{ |
if (fprintf (script, " }\n") <= 0) |
| 4602 |
struct function_info *call_fun = call->fun; |
goto file_err; |
| 4603 |
sec = call_fun->rodata; |
|
| 4604 |
if (sec != NULL |
ovlynum += htab->params->num_lines; |
| 4605 |
&& fprintf (script, " %s%c%s (%s)\n", |
while (base < count && ovly_map[base] < ovlynum) |
| 4606 |
(sec->owner->my_archive != NULL |
base++; |
|
? sec->owner->my_archive->filename : ""), |
|
|
info->path_separator, |
|
|
sec->owner->filename, |
|
|
sec->name) <= 0) |
|
|
goto file_err; |
|
|
for (call = call_fun->call_list; call; call = call->next) |
|
|
if (call->is_pasted) |
|
|
break; |
|
|
} |
|
|
} |
|
| 4607 |
} |
} |
| 4608 |
|
|
| 4609 |
if (fprintf (script, " }\n") <= 0) |
if (fprintf (script, " }\n") <= 0) |
| 4610 |
goto file_err; |
goto file_err; |
|
|
|
|
base = j; |
|
|
ovlynum += htab->params->num_regions; |
|
|
while (base < count && ovly_map[base] < ovlynum) |
|
|
base++; |
|
| 4611 |
} |
} |
| 4612 |
|
|
|
if (fprintf (script, " }\n") <= 0) |
|
|
goto file_err; |
|
| 4613 |
} |
} |
| 4614 |
|
|
| 4615 |
free (ovly_map); |
free (ovly_map); |
| 4647 |
return FALSE; |
return FALSE; |
| 4648 |
|
|
| 4649 |
htab = spu_hash_table (info); |
htab = spu_hash_table (info); |
| 4650 |
info->callbacks->info (_("Stack size for call graph root nodes.\n")); |
if (htab->params->stack_analysis) |
| 4651 |
info->callbacks->minfo (_("\nStack size for functions. " |
{ |
| 4652 |
"Annotations: '*' max stack, 't' tail call\n")); |
info->callbacks->info (_("Stack size for call graph root nodes.\n")); |
| 4653 |
|
info->callbacks->minfo (_("\nStack size for functions. " |
| 4654 |
|
"Annotations: '*' max stack, 't' tail call\n")); |
| 4655 |
|
} |
| 4656 |
|
|
| 4657 |
sum_stack_param.emit_stack_syms = htab->params->emit_stack_syms; |
sum_stack_param.emit_stack_syms = htab->params->emit_stack_syms; |
| 4658 |
sum_stack_param.overall_stack = 0; |
sum_stack_param.overall_stack = 0; |
| 4659 |
if (!for_each_node (sum_stack, info, &sum_stack_param, TRUE)) |
if (!for_each_node (sum_stack, info, &sum_stack_param, TRUE)) |
| 4660 |
return FALSE; |
return FALSE; |
| 4661 |
|
|
| 4662 |
info->callbacks->info (_("Maximum stack required is 0x%v\n"), |
if (htab->params->stack_analysis) |
| 4663 |
(bfd_vma) sum_stack_param.overall_stack); |
info->callbacks->info (_("Maximum stack required is 0x%v\n"), |
| 4664 |
|
(bfd_vma) sum_stack_param.overall_stack); |
| 4665 |
return TRUE; |
return TRUE; |
| 4666 |
} |
} |
| 4667 |
|
|
| 4675 |
if (htab->params->auto_overlay) |
if (htab->params->auto_overlay) |
| 4676 |
spu_elf_auto_overlay (info); |
spu_elf_auto_overlay (info); |
| 4677 |
|
|
| 4678 |
if (htab->params->stack_analysis |
if ((htab->params->stack_analysis |
| 4679 |
|
|| (htab->params->ovly_flavour == ovly_soft_icache |
| 4680 |
|
&& htab->params->lrlive_analysis)) |
| 4681 |
&& !spu_elf_stack_analysis (info)) |
&& !spu_elf_stack_analysis (info)) |
| 4682 |
info->callbacks->einfo ("%X%P: stack analysis error: %E\n"); |
info->callbacks->einfo ("%X%P: stack/lrlive analysis error: %E\n"); |
| 4683 |
|
|
| 4684 |
|
if (!spu_elf_build_stubs (info)) |
| 4685 |
|
info->callbacks->einfo ("%F%P: can not build overlay stubs: %E\n"); |
| 4686 |
|
|
| 4687 |
return bfd_elf_final_link (output_bfd, info); |
return bfd_elf_final_link (output_bfd, info); |
| 4688 |
} |
} |
| 4739 |
bfd_boolean emit_these_relocs = FALSE; |
bfd_boolean emit_these_relocs = FALSE; |
| 4740 |
bfd_boolean is_ea_sym; |
bfd_boolean is_ea_sym; |
| 4741 |
bfd_boolean stubs; |
bfd_boolean stubs; |
| 4742 |
|
unsigned int iovl = 0; |
| 4743 |
|
|
| 4744 |
htab = spu_hash_table (info); |
htab = spu_hash_table (info); |
| 4745 |
stubs = (htab->stub_sec != NULL |
stubs = (htab->stub_sec != NULL |
| 4746 |
&& maybe_needs_stubs (input_section)); |
&& maybe_needs_stubs (input_section)); |
| 4747 |
|
iovl = overlay_index (input_section); |
| 4748 |
ea = bfd_get_section_by_name (output_bfd, "._ea"); |
ea = bfd_get_section_by_name (output_bfd, "._ea"); |
| 4749 |
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; |
symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; |
| 4750 |
sym_hashes = (struct elf_link_hash_entry **) (elf_sym_hashes (input_bfd)); |
sym_hashes = (struct elf_link_hash_entry **) (elf_sym_hashes (input_bfd)); |
| 4846 |
if (info->relocatable) |
if (info->relocatable) |
| 4847 |
continue; |
continue; |
| 4848 |
|
|
| 4849 |
|
/* Change "a rt,ra,rb" to "ai rt,ra,0". */ |
| 4850 |
|
if (r_type == R_SPU_ADD_PIC && h != NULL |
| 4851 |
|
&& (h->def_regular || ELF_COMMON_DEF_P (h))) |
| 4852 |
|
{ |
| 4853 |
|
bfd_byte *loc = contents + rel->r_offset; |
| 4854 |
|
loc[0] = 0x1c; |
| 4855 |
|
loc[1] = 0x00; |
| 4856 |
|
loc[2] &= 0x3f; |
| 4857 |
|
} |
| 4858 |
|
|
| 4859 |
is_ea_sym = (ea != NULL |
is_ea_sym = (ea != NULL |
| 4860 |
&& sec != NULL |
&& sec != NULL |
| 4861 |
&& sec->output_section == ea); |
&& sec->output_section == ea); |
| 4862 |
|
|
| 4863 |
if (r_type == R_SPU_PPU32 || r_type == R_SPU_PPU64) |
/* If this symbol is in an overlay area, we may need to relocate |
| 4864 |
|
to the overlay stub. */ |
| 4865 |
|
addend = rel->r_addend; |
| 4866 |
|
if (stubs |
| 4867 |
|
&& !is_ea_sym |
| 4868 |
|
&& (stub_type = needs_ovl_stub (h, sym, sec, input_section, rel, |
| 4869 |
|
contents, info)) != no_stub) |
| 4870 |
|
{ |
| 4871 |
|
unsigned int ovl = 0; |
| 4872 |
|
struct got_entry *g, **head; |
| 4873 |
|
|
| 4874 |
|
if (stub_type != nonovl_stub) |
| 4875 |
|
ovl = iovl; |
| 4876 |
|
|
| 4877 |
|
if (h != NULL) |
| 4878 |
|
head = &h->got.glist; |
| 4879 |
|
else |
| 4880 |
|
head = elf_local_got_ents (input_bfd) + r_symndx; |
| 4881 |
|
|
| 4882 |
|
for (g = *head; g != NULL; g = g->next) |
| 4883 |
|
if (htab->params->ovly_flavour == ovly_soft_icache |
| 4884 |
|
? (g->ovl == ovl |
| 4885 |
|
&& g->br_addr == (rel->r_offset |
| 4886 |
|
+ input_section->output_offset |
| 4887 |
|
+ input_section->output_section->vma)) |
| 4888 |
|
: g->addend == addend && (g->ovl == ovl || g->ovl == 0)) |
| 4889 |
|
break; |
| 4890 |
|
if (g == NULL) |
| 4891 |
|
abort (); |
| 4892 |
|
|
| 4893 |
|
relocation = g->stub_addr; |
| 4894 |
|
addend = 0; |
| 4895 |
|
} |
| 4896 |
|
else |
| 4897 |
|
{ |
| 4898 |
|
/* For soft icache, encode the overlay index into addresses. */ |
| 4899 |
|
if (htab->params->ovly_flavour == ovly_soft_icache |
| 4900 |
|
&& (r_type == R_SPU_ADDR16_HI |
| 4901 |
|
|| r_type == R_SPU_ADDR32 || r_type == R_SPU_REL32) |
| 4902 |
|
&& !is_ea_sym) |
| 4903 |
|
{ |
| 4904 |
|
unsigned int ovl = overlay_index (sec); |
| 4905 |
|
if (ovl != 0) |
| 4906 |
|
{ |
| 4907 |
|
unsigned int set_id = ((ovl - 1) >> htab->num_lines_log2) + 1; |
| 4908 |
|
relocation += set_id << 18; |
| 4909 |
|
} |
| 4910 |
|
} |
| 4911 |
|
} |
| 4912 |
|
|
| 4913 |
|
if (unresolved_reloc) |
| 4914 |
|
; |
| 4915 |
|
else if (r_type == R_SPU_PPU32 || r_type == R_SPU_PPU64) |
| 4916 |
{ |
{ |
| 4917 |
if (is_ea_sym) |
if (is_ea_sym) |
| 4918 |
{ |
{ |
| 4930 |
emit_these_relocs = TRUE; |
emit_these_relocs = TRUE; |
| 4931 |
continue; |
continue; |
| 4932 |
} |
} |
| 4933 |
|
else if (is_ea_sym) |
|
if (is_ea_sym) |
|
| 4934 |
unresolved_reloc = TRUE; |
unresolved_reloc = TRUE; |
| 4935 |
|
|
| 4936 |
if (unresolved_reloc) |
if (unresolved_reloc) |
| 4945 |
ret = FALSE; |
ret = FALSE; |
| 4946 |
} |
} |
| 4947 |
|
|
|
/* If this symbol is in an overlay area, we may need to relocate |
|
|
to the overlay stub. */ |
|
|
addend = rel->r_addend; |
|
|
if (stubs |
|
|
&& (stub_type = needs_ovl_stub (h, sym, sec, input_section, rel, |
|
|
contents, info)) != no_stub) |
|
|
{ |
|
|
unsigned int ovl = 0; |
|
|
struct got_entry *g, **head; |
|
|
|
|
|
if (stub_type != nonovl_stub) |
|
|
ovl = (spu_elf_section_data (input_section->output_section) |
|
|
->u.o.ovl_index); |
|
|
|
|
|
if (h != NULL) |
|
|
head = &h->got.glist; |
|
|
else |
|
|
head = elf_local_got_ents (input_bfd) + r_symndx; |
|
|
|
|
|
for (g = *head; g != NULL; g = g->next) |
|
|
if (g->addend == addend && (g->ovl == ovl || g->ovl == 0)) |
|
|
break; |
|
|
if (g == NULL) |
|
|
abort (); |
|
|
|
|
|
relocation = g->stub_addr; |
|
|
addend = 0; |
|
|
} |
|
|
|
|
| 4948 |
r = _bfd_final_link_relocate (howto, |
r = _bfd_final_link_relocate (howto, |
| 4949 |
input_bfd, |
input_bfd, |
| 4950 |
input_section, |
input_section, |
| 5027 |
|
|
| 5028 |
/* Adjust _SPUEAR_ syms to point at their overlay stubs. */ |
/* Adjust _SPUEAR_ syms to point at their overlay stubs. */ |
| 5029 |
|
|
| 5030 |
static bfd_boolean |
static int |
| 5031 |
spu_elf_output_symbol_hook (struct bfd_link_info *info, |
spu_elf_output_symbol_hook (struct bfd_link_info *info, |
| 5032 |
const char *sym_name ATTRIBUTE_UNUSED, |
const char *sym_name ATTRIBUTE_UNUSED, |
| 5033 |
Elf_Internal_Sym *sym, |
Elf_Internal_Sym *sym, |
| 5047 |
struct got_entry *g; |
struct got_entry *g; |
| 5048 |
|
|
| 5049 |
for (g = h->got.glist; g != NULL; g = g->next) |
for (g = h->got.glist; g != NULL; g = g->next) |
| 5050 |
if (g->addend == 0 && g->ovl == 0) |
if (htab->params->ovly_flavour == ovly_soft_icache |
| 5051 |
|
? g->br_addr == g->stub_addr |
| 5052 |
|
: g->addend == 0 && g->ovl == 0) |
| 5053 |
{ |
{ |
| 5054 |
sym->st_shndx = (_bfd_elf_section_from_bfd_section |
sym->st_shndx = (_bfd_elf_section_from_bfd_section |
| 5055 |
(htab->stub_sec[0]->output_section->owner, |
(htab->stub_sec[0]->output_section->owner, |
| 5059 |
} |
} |
| 5060 |
} |
} |
| 5061 |
|
|
| 5062 |
return TRUE; |
return 1; |
| 5063 |
} |
} |
| 5064 |
|
|
| 5065 |
static int spu_plugin = 0; |
static int spu_plugin = 0; |
| 5116 |
spu_elf_modify_segment_map (bfd *abfd, struct bfd_link_info *info) |
spu_elf_modify_segment_map (bfd *abfd, struct bfd_link_info *info) |
| 5117 |
{ |
{ |
| 5118 |
asection *toe, *s; |
asection *toe, *s; |
| 5119 |
struct elf_segment_map *m; |
struct elf_segment_map *m, *m_overlay; |
| 5120 |
|
struct elf_segment_map **p, **p_overlay; |
| 5121 |
unsigned int i; |
unsigned int i; |
| 5122 |
|
|
| 5123 |
if (info == NULL) |
if (info == NULL) |
| 5164 |
break; |
break; |
| 5165 |
} |
} |
| 5166 |
|
|
| 5167 |
|
|
| 5168 |
|
/* Some SPU ELF loaders ignore the PF_OVERLAY flag and just load all |
| 5169 |
|
PT_LOAD segments. This can cause the .ovl.init section to be |
| 5170 |
|
overwritten with the contents of some overlay segment. To work |
| 5171 |
|
around this issue, we ensure that all PF_OVERLAY segments are |
| 5172 |
|
sorted first amongst the program headers; this ensures that even |
| 5173 |
|
with a broken loader, the .ovl.init section (which is not marked |
| 5174 |
|
as PF_OVERLAY) will be placed into SPU local store on startup. */ |
| 5175 |
|
|
| 5176 |
|
/* Move all overlay segments onto a separate list. */ |
| 5177 |
|
p = &elf_tdata (abfd)->segment_map; |
| 5178 |
|
p_overlay = &m_overlay; |
| 5179 |
|
while (*p != NULL) |
| 5180 |
|
{ |
| 5181 |
|
if ((*p)->p_type == PT_LOAD && (*p)->count == 1 |
| 5182 |
|
&& spu_elf_section_data ((*p)->sections[0])->u.o.ovl_index != 0) |
| 5183 |
|
{ |
| 5184 |
|
struct elf_segment_map *m = *p; |
| 5185 |
|
*p = m->next; |
| 5186 |
|
*p_overlay = m; |
| 5187 |
|
p_overlay = &m->next; |
| 5188 |
|
continue; |
| 5189 |
|
} |
| 5190 |
|
|
| 5191 |
|
p = &((*p)->next); |
| 5192 |
|
} |
| 5193 |
|
|
| 5194 |
|
/* Re-insert overlay segments at the head of the segment map. */ |
| 5195 |
|
*p_overlay = elf_tdata (abfd)->segment_map; |
| 5196 |
|
elf_tdata (abfd)->segment_map = m_overlay; |
| 5197 |
|
|
| 5198 |
return TRUE; |
return TRUE; |
| 5199 |
} |
} |
| 5200 |
|
|
| 5242 |
/* Mark this as an overlay header. */ |
/* Mark this as an overlay header. */ |
| 5243 |
phdr[i].p_flags |= PF_OVERLAY; |
phdr[i].p_flags |= PF_OVERLAY; |
| 5244 |
|
|
| 5245 |
if (htab->ovtab != NULL && htab->ovtab->size != 0) |
if (htab->ovtab != NULL && htab->ovtab->size != 0 |
| 5246 |
|
&& htab->params->ovly_flavour != ovly_soft_icache) |
| 5247 |
{ |
{ |
| 5248 |
bfd_byte *p = htab->ovtab->contents; |
bfd_byte *p = htab->ovtab->contents; |
| 5249 |
unsigned int off = o * 16 + 8; |
unsigned int off = o * 16 + 8; |
| 5252 |
bfd_put_32 (htab->ovtab->owner, phdr[i].p_offset, p + off); |
bfd_put_32 (htab->ovtab->owner, phdr[i].p_offset, p + off); |
| 5253 |
} |
} |
| 5254 |
} |
} |
| 5255 |
|
/* Soft-icache has its file offset put in .ovl.init. */ |
| 5256 |
|
if (htab->init != NULL && htab->init->size != 0) |
| 5257 |
|
{ |
| 5258 |
|
bfd_vma val = elf_section_data (htab->ovl_sec[0])->this_hdr.sh_offset; |
| 5259 |
|
|
| 5260 |
|
bfd_put_32 (htab->init->owner, val, htab->init->contents + 4); |
| 5261 |
|
} |
| 5262 |
} |
} |
| 5263 |
|
|
| 5264 |
/* Round up p_filesz and p_memsz of PT_LOAD segments to multiples |
/* Round up p_filesz and p_memsz of PT_LOAD segments to multiples |
| 5315 |
#define elf_backend_can_gc_sections 1 |
#define elf_backend_can_gc_sections 1 |
| 5316 |
|
|
| 5317 |
#define bfd_elf32_bfd_reloc_type_lookup spu_elf_reloc_type_lookup |
#define bfd_elf32_bfd_reloc_type_lookup spu_elf_reloc_type_lookup |
| 5318 |
#define bfd_elf32_bfd_reloc_name_lookup spu_elf_reloc_name_lookup |
#define bfd_elf32_bfd_reloc_name_lookup spu_elf_reloc_name_lookup |
| 5319 |
#define elf_info_to_howto spu_elf_info_to_howto |
#define elf_info_to_howto spu_elf_info_to_howto |
| 5320 |
#define elf_backend_count_relocs spu_elf_count_relocs |
#define elf_backend_count_relocs spu_elf_count_relocs |
| 5321 |
#define elf_backend_relocate_section spu_elf_relocate_section |
#define elf_backend_relocate_section spu_elf_relocate_section |